Merge commit '149392b0ba
' into clippyup
This commit is contained in:
parent
e5df17aae5
commit
0413fb35ba
131 changed files with 3025 additions and 630 deletions
|
@ -4430,6 +4430,7 @@ Released 2018-09-13
|
||||||
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
|
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
|
||||||
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
|
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
|
||||||
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
|
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
|
||||||
|
[`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
|
||||||
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
|
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
|
||||||
[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
|
[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
|
||||||
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
|
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
|
||||||
|
@ -4494,6 +4495,7 @@ Released 2018-09-13
|
||||||
[`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future
|
[`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future
|
||||||
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
|
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
|
||||||
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
|
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
|
||||||
|
[`let_underscore_untyped`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_untyped
|
||||||
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
|
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
|
||||||
[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
|
[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
|
||||||
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
|
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
|
||||||
|
@ -4620,6 +4622,7 @@ Released 2018-09-13
|
||||||
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
|
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
|
||||||
[`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace
|
[`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace
|
||||||
[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
|
[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
|
||||||
|
[`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi
|
||||||
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
|
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
|
||||||
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
|
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
|
||||||
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
|
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
|
||||||
|
@ -4675,6 +4678,7 @@ Released 2018-09-13
|
||||||
[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
|
[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
|
||||||
[`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
|
[`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
|
||||||
[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
|
[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
|
||||||
|
[`question_mark_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark_used
|
||||||
[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
|
[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
|
||||||
[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
|
[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
|
||||||
[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
|
[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
|
||||||
|
@ -4734,6 +4738,7 @@ Released 2018-09-13
|
||||||
[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
|
[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
|
||||||
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
|
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
|
||||||
[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
|
[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
|
||||||
|
[`significant_drop_tightening`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_tightening
|
||||||
[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
|
[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
|
||||||
[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
|
[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
|
||||||
[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
|
[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
|
||||||
|
@ -4764,6 +4769,7 @@ Released 2018-09-13
|
||||||
[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
|
[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
|
||||||
[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
|
[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
|
||||||
[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
|
[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
|
||||||
|
[`suspicious_command_arg_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_command_arg_space
|
||||||
[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
|
[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
|
||||||
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
|
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
|
||||||
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
|
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
|
||||||
|
@ -4790,6 +4796,7 @@ Released 2018-09-13
|
||||||
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
|
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
|
||||||
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
|
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
|
||||||
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
|
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
|
||||||
|
[`transmute_int_to_non_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_non_zero
|
||||||
[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
|
[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
|
||||||
[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
|
[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
|
||||||
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
|
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
|
||||||
|
|
39
README.md
39
README.md
|
@ -19,21 +19,35 @@ You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the
|
||||||
| `clippy::complexity` | code that does something simple but in a complex way | **warn** |
|
| `clippy::complexity` | code that does something simple but in a complex way | **warn** |
|
||||||
| `clippy::perf` | code that can be written to run faster | **warn** |
|
| `clippy::perf` | code that can be written to run faster | **warn** |
|
||||||
| `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow |
|
| `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow |
|
||||||
|
| `clippy::restriction` | lints which prevent the use of language and library features[^restrict] | allow |
|
||||||
| `clippy::nursery` | new lints that are still under development | allow |
|
| `clippy::nursery` | new lints that are still under development | allow |
|
||||||
| `clippy::cargo` | lints for the cargo manifest | allow |
|
| `clippy::cargo` | lints for the cargo manifest | allow |
|
||||||
|
|
||||||
More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
|
More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
|
||||||
|
|
||||||
The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are
|
The `restriction` category should, *emphatically*, not be enabled as a whole. The contained
|
||||||
for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used
|
lints may lint against perfectly reasonable code, may not have an alternative suggestion,
|
||||||
very selectively, if at all.
|
and may contradict any other lints (including other categories). Lints should be considered
|
||||||
|
on a case-by-case basis before enabling.
|
||||||
|
|
||||||
|
[^restrict]: Some use cases for `restriction` lints include:
|
||||||
|
- Strict coding styles (e.g. [`clippy::else_if_without_else`]).
|
||||||
|
- Additional restrictions on CI (e.g. [`clippy::todo`]).
|
||||||
|
- Preventing panicking in certain functions (e.g. [`clippy::unwrap_used`]).
|
||||||
|
- Running a lint only on a subset of code (e.g. `#[forbid(clippy::float_arithmetic)]` on a module).
|
||||||
|
|
||||||
|
[`clippy::else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
|
||||||
|
[`clippy::todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
|
||||||
|
[`clippy::unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Table of contents:
|
Table of contents:
|
||||||
|
|
||||||
* [Usage instructions](#usage)
|
* [Usage instructions](#usage)
|
||||||
* [Configuration](#configuration)
|
* [Configuration](#configuration)
|
||||||
* [Contributing](#contributing)
|
* [Contributing](#contributing)
|
||||||
* [License](#license)
|
* [License](#license)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -64,6 +78,7 @@ Once you have rustup and the latest stable release (at least Rust 1.29) installe
|
||||||
```terminal
|
```terminal
|
||||||
rustup component add clippy
|
rustup component add clippy
|
||||||
```
|
```
|
||||||
|
|
||||||
If it says that it can't find the `clippy` component, please run `rustup self update`.
|
If it says that it can't find the `clippy` component, please run `rustup self update`.
|
||||||
|
|
||||||
#### Step 3: Run Clippy
|
#### Step 3: Run Clippy
|
||||||
|
@ -143,16 +158,16 @@ line. (You can swap `clippy::all` with the specific lint category you are target
|
||||||
|
|
||||||
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
|
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
|
||||||
|
|
||||||
* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
|
* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
|
||||||
Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
|
Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
|
||||||
|
|
||||||
* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
|
* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
|
||||||
`#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
|
`#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
|
||||||
lints prone to false positives.
|
lints prone to false positives.
|
||||||
|
|
||||||
* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)
|
* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)
|
||||||
|
|
||||||
* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
|
* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
|
||||||
|
|
||||||
Note: `allow` means to suppress the lint for your code. With `warn` the lint
|
Note: `allow` means to suppress the lint for your code. With `warn` the lint
|
||||||
will only emit a warning, while with `deny` the lint will emit an error, when
|
will only emit a warning, while with `deny` the lint will emit an error, when
|
||||||
|
@ -176,12 +191,14 @@ cargo clippy -- -W clippy::lint_name
|
||||||
|
|
||||||
This also works with lint groups. For example, you
|
This also works with lint groups. For example, you
|
||||||
can run Clippy with warnings for all lints enabled:
|
can run Clippy with warnings for all lints enabled:
|
||||||
|
|
||||||
```terminal
|
```terminal
|
||||||
cargo clippy -- -W clippy::pedantic
|
cargo clippy -- -W clippy::pedantic
|
||||||
```
|
```
|
||||||
|
|
||||||
If you care only about a single lint, you can allow all others and then explicitly warn on
|
If you care only about a single lint, you can allow all others and then explicitly warn on
|
||||||
the lint(s) you are interested in:
|
the lint(s) you are interested in:
|
||||||
|
|
||||||
```terminal
|
```terminal
|
||||||
cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
|
cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
|
||||||
```
|
```
|
||||||
|
|
|
@ -28,6 +28,7 @@ repository. You can do this with:
|
||||||
```bash
|
```bash
|
||||||
# Assuming the current directory corresponds to the Rust repository
|
# Assuming the current directory corresponds to the Rust repository
|
||||||
$ git checkout beta
|
$ git checkout beta
|
||||||
|
# Make sure to change `your-github-name` to your github name in the following command
|
||||||
$ git subtree pull -p src/tools/clippy https://github.com/<your-github-name>/rust-clippy backport
|
$ git subtree pull -p src/tools/clippy https://github.com/<your-github-name>/rust-clippy backport
|
||||||
$ ./x.py test src/tools/clippy
|
$ ./x.py test src/tools/clippy
|
||||||
```
|
```
|
||||||
|
|
|
@ -79,8 +79,7 @@ to be run inside the `rust` directory):
|
||||||
`rustup check`.
|
`rustup check`.
|
||||||
3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
|
3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
|
||||||
```bash
|
```bash
|
||||||
# Make sure to change `your-github-name` to your github name in the following command. Also be
|
# Be sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
|
||||||
# sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
|
|
||||||
# because changes cannot be fast forwarded and you have to run this command again.
|
# because changes cannot be fast forwarded and you have to run this command again.
|
||||||
git subtree push -P src/tools/clippy clippy-local sync-from-rust
|
git subtree push -P src/tools/clippy clippy-local sync-from-rust
|
||||||
```
|
```
|
||||||
|
|
|
@ -53,6 +53,7 @@ Please use that command to update the file and do not edit it by hand.
|
||||||
| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` |
|
| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` |
|
||||||
| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` |
|
| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` |
|
||||||
| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` |
|
| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` |
|
||||||
|
| [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` |
|
||||||
|
|
||||||
### arithmetic-side-effects-allowed
|
### arithmetic-side-effects-allowed
|
||||||
Suppress checking of the passed type names in all types of operations.
|
Suppress checking of the passed type names in all types of operations.
|
||||||
|
@ -471,7 +472,7 @@ The maximum size of a file included via `include_bytes!()` or `include_str!()`,
|
||||||
|
|
||||||
|
|
||||||
### allow-expect-in-tests
|
### allow-expect-in-tests
|
||||||
Whether `expect` should be allowed within `#[cfg(test)]`
|
Whether `expect` should be allowed in test functions or `#[cfg(test)]`
|
||||||
|
|
||||||
**Default Value:** `false` (`bool`)
|
**Default Value:** `false` (`bool`)
|
||||||
|
|
||||||
|
@ -479,7 +480,7 @@ Whether `expect` should be allowed within `#[cfg(test)]`
|
||||||
|
|
||||||
|
|
||||||
### allow-unwrap-in-tests
|
### allow-unwrap-in-tests
|
||||||
Whether `unwrap` should be allowed in test cfg
|
Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
|
||||||
|
|
||||||
**Default Value:** `false` (`bool`)
|
**Default Value:** `false` (`bool`)
|
||||||
|
|
||||||
|
@ -487,7 +488,7 @@ Whether `unwrap` should be allowed in test cfg
|
||||||
|
|
||||||
|
|
||||||
### allow-dbg-in-tests
|
### allow-dbg-in-tests
|
||||||
Whether `dbg!` should be allowed in test functions
|
Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
|
||||||
|
|
||||||
**Default Value:** `false` (`bool`)
|
**Default Value:** `false` (`bool`)
|
||||||
|
|
||||||
|
@ -495,7 +496,7 @@ Whether `dbg!` should be allowed in test functions
|
||||||
|
|
||||||
|
|
||||||
### allow-print-in-tests
|
### allow-print-in-tests
|
||||||
Whether print macros (ex. `println!`) should be allowed in test functions
|
Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
|
||||||
|
|
||||||
**Default Value:** `false` (`bool`)
|
**Default Value:** `false` (`bool`)
|
||||||
|
|
||||||
|
@ -540,4 +541,13 @@ if no suggestion can be made.
|
||||||
* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing)
|
* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing)
|
||||||
|
|
||||||
|
|
||||||
|
### missing-docs-in-crate-items
|
||||||
|
Whether to **only** check for missing documentation in items visible within the current
|
||||||
|
crate. For example, `pub(crate)` items.
|
||||||
|
|
||||||
|
**Default Value:** `false` (`bool`)
|
||||||
|
|
||||||
|
* [missing_docs_in_private_items](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::clippy_project_root;
|
use crate::clippy_project_root;
|
||||||
use indoc::{formatdoc, writedoc};
|
use indoc::{formatdoc, writedoc};
|
||||||
|
use std::fmt;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::fs::{self, OpenOptions};
|
use std::fs::{self, OpenOptions};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
@ -256,7 +257,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let _ = write!(result, "{}", get_lint_declaration(&name_upper, category));
|
let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category));
|
||||||
|
|
||||||
result.push_str(&if enable_msrv {
|
result.push_str(&if enable_msrv {
|
||||||
formatdoc!(
|
formatdoc!(
|
||||||
|
@ -353,7 +354,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
|
||||||
let mut lint_file_contents = String::new();
|
let mut lint_file_contents = String::new();
|
||||||
|
|
||||||
if enable_msrv {
|
if enable_msrv {
|
||||||
let _ = writedoc!(
|
let _: fmt::Result = writedoc!(
|
||||||
lint_file_contents,
|
lint_file_contents,
|
||||||
r#"
|
r#"
|
||||||
use clippy_utils::msrvs::{{self, Msrv}};
|
use clippy_utils::msrvs::{{self, Msrv}};
|
||||||
|
@ -373,7 +374,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
|
||||||
name_upper = name_upper,
|
name_upper = name_upper,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let _ = writedoc!(
|
let _: fmt::Result = writedoc!(
|
||||||
lint_file_contents,
|
lint_file_contents,
|
||||||
r#"
|
r#"
|
||||||
use rustc_lint::{{{context_import}, LintContext}};
|
use rustc_lint::{{{context_import}, LintContext}};
|
||||||
|
@ -521,7 +522,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
|
||||||
.chain(std::iter::once(&*lint_name_upper))
|
.chain(std::iter::once(&*lint_name_upper))
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
{
|
{
|
||||||
let _ = write!(new_arr_content, "\n {ident},");
|
let _: fmt::Result = write!(new_arr_content, "\n {ident},");
|
||||||
}
|
}
|
||||||
new_arr_content.push('\n');
|
new_arr_content.push('\n');
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use itertools::Itertools;
|
||||||
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
|
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fmt::Write;
|
use std::fmt::{self, Write};
|
||||||
use std::fs::{self, OpenOptions};
|
use std::fs::{self, OpenOptions};
|
||||||
use std::io::{self, Read, Seek, SeekFrom, Write as _};
|
use std::io::{self, Read, Seek, SeekFrom, Write as _};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -691,7 +691,7 @@ fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
|
||||||
let mut output = GENERATED_FILE_COMMENT.to_string();
|
let mut output = GENERATED_FILE_COMMENT.to_string();
|
||||||
output.push_str("{\n");
|
output.push_str("{\n");
|
||||||
for lint in lints {
|
for lint in lints {
|
||||||
let _ = write!(
|
let _: fmt::Result = write!(
|
||||||
output,
|
output,
|
||||||
concat!(
|
concat!(
|
||||||
" store.register_removed(\n",
|
" store.register_removed(\n",
|
||||||
|
@ -726,7 +726,7 @@ fn gen_declared_lints<'a>(
|
||||||
if !is_public {
|
if !is_public {
|
||||||
output.push_str(" #[cfg(feature = \"internal\")]\n");
|
output.push_str(" #[cfg(feature = \"internal\")]\n");
|
||||||
}
|
}
|
||||||
let _ = writeln!(output, " crate::{module_name}::{lint_name}_INFO,");
|
let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,");
|
||||||
}
|
}
|
||||||
output.push_str("];\n");
|
output.push_str("];\n");
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
) => {
|
) => {
|
||||||
if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
|
if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
|
||||||
let Some(sig) = expr_sig(cx, path) &&
|
let Some(sig) = expr_sig(cx, path) &&
|
||||||
let Some(input) = sig.input(index)
|
let Some(input) = sig.input(index) &&
|
||||||
|
!cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
|
||||||
{
|
{
|
||||||
input.no_bound_vars().is_some()
|
input.no_bound_vars().is_some()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -168,7 +168,7 @@ pub(super) fn check(
|
||||||
let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
|
let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
|
||||||
|
|
||||||
span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
|
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.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...");
|
||||||
diag.span_suggestion_with_style(
|
diag.span_suggestion_with_style(
|
||||||
expr.span,
|
expr.span,
|
||||||
"... or use `try_from` and handle the error accordingly",
|
"... or use `try_from` and handle the error accordingly",
|
||||||
|
|
|
@ -179,6 +179,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
|
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
|
||||||
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
|
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
|
||||||
crate::functions::DOUBLE_MUST_USE_INFO,
|
crate::functions::DOUBLE_MUST_USE_INFO,
|
||||||
|
crate::functions::IMPL_TRAIT_IN_PARAMS_INFO,
|
||||||
crate::functions::MISNAMED_GETTERS_INFO,
|
crate::functions::MISNAMED_GETTERS_INFO,
|
||||||
crate::functions::MUST_USE_CANDIDATE_INFO,
|
crate::functions::MUST_USE_CANDIDATE_INFO,
|
||||||
crate::functions::MUST_USE_UNIT_INFO,
|
crate::functions::MUST_USE_UNIT_INFO,
|
||||||
|
@ -224,6 +225,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
|
crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
|
||||||
crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
|
crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
|
||||||
crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
|
crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
|
||||||
|
crate::let_underscore::LET_UNDERSCORE_UNTYPED_INFO,
|
||||||
crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
|
crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
|
||||||
crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
|
crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
|
||||||
crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
|
crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
|
||||||
|
@ -378,6 +380,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::methods::SKIP_WHILE_NEXT_INFO,
|
crate::methods::SKIP_WHILE_NEXT_INFO,
|
||||||
crate::methods::STABLE_SORT_PRIMITIVE_INFO,
|
crate::methods::STABLE_SORT_PRIMITIVE_INFO,
|
||||||
crate::methods::STRING_EXTEND_CHARS_INFO,
|
crate::methods::STRING_EXTEND_CHARS_INFO,
|
||||||
|
crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO,
|
||||||
crate::methods::SUSPICIOUS_MAP_INFO,
|
crate::methods::SUSPICIOUS_MAP_INFO,
|
||||||
crate::methods::SUSPICIOUS_SPLITN_INFO,
|
crate::methods::SUSPICIOUS_SPLITN_INFO,
|
||||||
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
|
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
|
||||||
|
@ -447,6 +450,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::no_effect::NO_EFFECT_INFO,
|
crate::no_effect::NO_EFFECT_INFO,
|
||||||
crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
|
crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
|
||||||
crate::no_effect::UNNECESSARY_OPERATION_INFO,
|
crate::no_effect::UNNECESSARY_OPERATION_INFO,
|
||||||
|
crate::no_mangle_with_rust_abi::NO_MANGLE_WITH_RUST_ABI_INFO,
|
||||||
crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
|
crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
|
||||||
crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
|
crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
|
||||||
crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
|
crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
|
||||||
|
@ -506,6 +510,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
|
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
|
||||||
crate::pub_use::PUB_USE_INFO,
|
crate::pub_use::PUB_USE_INFO,
|
||||||
crate::question_mark::QUESTION_MARK_INFO,
|
crate::question_mark::QUESTION_MARK_INFO,
|
||||||
|
crate::question_mark_used::QUESTION_MARK_USED_INFO,
|
||||||
crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
|
crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
|
||||||
crate::ranges::RANGE_MINUS_ONE_INFO,
|
crate::ranges::RANGE_MINUS_ONE_INFO,
|
||||||
crate::ranges::RANGE_PLUS_ONE_INFO,
|
crate::ranges::RANGE_PLUS_ONE_INFO,
|
||||||
|
@ -536,6 +541,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::shadow::SHADOW_REUSE_INFO,
|
crate::shadow::SHADOW_REUSE_INFO,
|
||||||
crate::shadow::SHADOW_SAME_INFO,
|
crate::shadow::SHADOW_SAME_INFO,
|
||||||
crate::shadow::SHADOW_UNRELATED_INFO,
|
crate::shadow::SHADOW_UNRELATED_INFO,
|
||||||
|
crate::significant_drop_tightening::SIGNIFICANT_DROP_TIGHTENING_INFO,
|
||||||
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
|
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
|
||||||
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
|
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
|
||||||
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
|
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
|
||||||
|
@ -573,6 +579,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
|
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
|
||||||
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
|
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
|
||||||
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
|
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
|
||||||
|
crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO,
|
||||||
crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
|
crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
|
||||||
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
|
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
|
||||||
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
|
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
|
||||||
use clippy_utils::msrvs::{self, Msrv};
|
use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||||
use clippy_utils::sugg::has_enclosing_paren;
|
use clippy_utils::sugg::has_enclosing_paren;
|
||||||
use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
|
use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
|
||||||
use clippy_utils::{
|
use clippy_utils::{
|
||||||
fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
|
fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
|
||||||
};
|
};
|
||||||
|
@ -26,8 +26,8 @@ use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::mir::{Rvalue, StatementKind};
|
use rustc_middle::mir::{Rvalue, StatementKind};
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
|
self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
|
||||||
ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
|
PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
|
||||||
};
|
};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::{symbol::sym, Span, Symbol};
|
use rustc_span::{symbol::sym, Span, Symbol};
|
||||||
|
@ -736,7 +736,7 @@ fn walk_parents<'tcx>(
|
||||||
..
|
..
|
||||||
}) if span.ctxt() == ctxt => {
|
}) if span.ctxt() == ctxt => {
|
||||||
let ty = cx.tcx.type_of(owner_id.def_id).subst_identity();
|
let ty = cx.tcx.type_of(owner_id.def_id).subst_identity();
|
||||||
Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
|
Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
|
||||||
},
|
},
|
||||||
|
|
||||||
Node::Item(&Item {
|
Node::Item(&Item {
|
||||||
|
@ -760,7 +760,7 @@ fn walk_parents<'tcx>(
|
||||||
let output = cx
|
let output = cx
|
||||||
.tcx
|
.tcx
|
||||||
.erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
|
.erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
|
||||||
Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
|
Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
|
||||||
},
|
},
|
||||||
|
|
||||||
Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
|
Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
|
||||||
|
@ -768,10 +768,23 @@ fn walk_parents<'tcx>(
|
||||||
hir_id,
|
hir_id,
|
||||||
kind: ExprKind::Struct(path, ..),
|
kind: ExprKind::Struct(path, ..),
|
||||||
..
|
..
|
||||||
}) => variant_of_res(cx, cx.qpath_res(path, *hir_id))
|
}) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
|
||||||
.and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name))
|
.and_then(|(adt, variant)| {
|
||||||
.map(|field_def| {
|
variant
|
||||||
ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did).subst_identity(), precedence).position_for_arg()
|
.fields
|
||||||
|
.iter()
|
||||||
|
.find(|f| f.name == field.ident.name)
|
||||||
|
.map(|f| (adt, f))
|
||||||
|
})
|
||||||
|
.map(|(adt, field_def)| {
|
||||||
|
ty_auto_deref_stability(
|
||||||
|
cx.tcx,
|
||||||
|
// Use the param_env of the target type.
|
||||||
|
cx.tcx.param_env(adt.did()),
|
||||||
|
cx.tcx.type_of(field_def.did).subst_identity(),
|
||||||
|
precedence,
|
||||||
|
)
|
||||||
|
.position_for_arg()
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
@ -792,7 +805,7 @@ fn walk_parents<'tcx>(
|
||||||
let output = cx
|
let output = cx
|
||||||
.tcx
|
.tcx
|
||||||
.erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
|
.erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
|
||||||
ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
|
ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -835,15 +848,20 @@ fn walk_parents<'tcx>(
|
||||||
msrv,
|
msrv,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
|
ty_auto_deref_stability(
|
||||||
.position_for_arg()
|
cx.tcx,
|
||||||
|
// Use the param_env of the target function.
|
||||||
|
sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
|
||||||
|
cx.tcx.erase_late_bound_regions(ty),
|
||||||
|
precedence
|
||||||
|
).position_for_arg()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
ExprKind::MethodCall(method, receiver, args, _) => {
|
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||||
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
||||||
if receiver.hir_id == child_id {
|
if receiver.hir_id == child_id {
|
||||||
// Check for calls to trait methods where the trait is implemented on a reference.
|
// Check for calls to trait methods where the trait is implemented on a reference.
|
||||||
// Two cases need to be handled:
|
// Two cases need to be handled:
|
||||||
|
@ -852,13 +870,17 @@ fn walk_parents<'tcx>(
|
||||||
// priority.
|
// priority.
|
||||||
if e.hir_id != child_id {
|
if e.hir_id != child_id {
|
||||||
return Some(Position::ReborrowStable(precedence))
|
return Some(Position::ReborrowStable(precedence))
|
||||||
} else if let Some(trait_id) = cx.tcx.trait_of_item(id)
|
} else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
|
||||||
&& let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
|
&& let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
|
||||||
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
|
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
|
||||||
&& let subs = cx
|
&& let subs = cx
|
||||||
.typeck_results()
|
.typeck_results()
|
||||||
.node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
|
.node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
|
||||||
&& let impl_ty = if cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[0].is_ref() {
|
&& let impl_ty = if cx.tcx.fn_sig(fn_id)
|
||||||
|
.subst_identity()
|
||||||
|
.skip_binder()
|
||||||
|
.inputs()[0].is_ref()
|
||||||
|
{
|
||||||
// Trait methods taking `&self`
|
// Trait methods taking `&self`
|
||||||
sub_ty
|
sub_ty
|
||||||
} else {
|
} else {
|
||||||
|
@ -879,10 +901,13 @@ fn walk_parents<'tcx>(
|
||||||
return Some(Position::MethodReceiver);
|
return Some(Position::MethodReceiver);
|
||||||
}
|
}
|
||||||
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
|
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
|
||||||
let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i + 1];
|
let ty = cx.tcx.fn_sig(fn_id).subst_identity().input(i + 1);
|
||||||
// `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
|
// `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
|
||||||
// `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
|
// `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
|
||||||
if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
|
if e.hir_id == child_id
|
||||||
|
&& method.args.is_none()
|
||||||
|
&& let ty::Param(param_ty) = ty.skip_binder().kind()
|
||||||
|
{
|
||||||
needless_borrow_impl_arg_position(
|
needless_borrow_impl_arg_position(
|
||||||
cx,
|
cx,
|
||||||
possible_borrowers,
|
possible_borrowers,
|
||||||
|
@ -895,8 +920,10 @@ fn walk_parents<'tcx>(
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ty_auto_deref_stability(
|
ty_auto_deref_stability(
|
||||||
cx,
|
cx.tcx,
|
||||||
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().input(i + 1)),
|
// Use the param_env of the target function.
|
||||||
|
cx.tcx.param_env(fn_id),
|
||||||
|
cx.tcx.erase_late_bound_regions(ty),
|
||||||
precedence,
|
precedence,
|
||||||
)
|
)
|
||||||
.position_for_arg()
|
.position_for_arg()
|
||||||
|
@ -1378,11 +1405,18 @@ impl<'tcx> TyPosition<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether a type is stable when switching to auto dereferencing,
|
// Checks whether a type is stable when switching to auto dereferencing,
|
||||||
fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
|
fn ty_auto_deref_stability<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
param_env: ParamEnv<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
precedence: i8,
|
||||||
|
) -> TyPosition<'tcx> {
|
||||||
let ty::Ref(_, mut ty, _) = *ty.kind() else {
|
let ty::Ref(_, mut ty, _) = *ty.kind() else {
|
||||||
return Position::Other(precedence).into();
|
return Position::Other(precedence).into();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
break match *ty.kind() {
|
break match *ty.kind() {
|
||||||
ty::Ref(_, ref_ty, _) => {
|
ty::Ref(_, ref_ty, _) => {
|
||||||
|
@ -1423,9 +1457,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
|
||||||
| ty::Closure(..)
|
| ty::Closure(..)
|
||||||
| ty::Never
|
| ty::Never
|
||||||
| ty::Tuple(_)
|
| ty::Tuple(_)
|
||||||
| ty::Alias(ty::Projection, _) => {
|
| ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
|
||||||
Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||||
use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
|
use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use pulldown_cmark::Event::{
|
||||||
|
Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
|
||||||
|
};
|
||||||
|
use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
|
||||||
|
use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
|
||||||
use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
|
use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
|
||||||
use rustc_ast::token::CommentKind;
|
use rustc_ast::token::CommentKind;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
@ -497,7 +502,6 @@ struct DocHeaders {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
|
fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
|
||||||
use pulldown_cmark::{BrokenLink, CowStr, Options};
|
|
||||||
/// We don't want the parser to choke on intra doc links. Since we don't
|
/// We don't want the parser to choke on intra doc links. Since we don't
|
||||||
/// actually care about rendering them, just pretend that all broken links are
|
/// actually care about rendering them, just pretend that all broken links are
|
||||||
/// point to a fake address.
|
/// point to a fake address.
|
||||||
|
@ -538,8 +542,6 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
|
||||||
pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter();
|
pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter();
|
||||||
// Iterate over all `Events` and combine consecutive events into one
|
// Iterate over all `Events` and combine consecutive events into one
|
||||||
let events = parser.coalesce(|previous, current| {
|
let events = parser.coalesce(|previous, current| {
|
||||||
use pulldown_cmark::Event::Text;
|
|
||||||
|
|
||||||
let previous_range = previous.1;
|
let previous_range = previous.1;
|
||||||
let current_range = current.1;
|
let current_range = current.1;
|
||||||
|
|
||||||
|
@ -564,12 +566,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||||
spans: &[(usize, Span)],
|
spans: &[(usize, Span)],
|
||||||
) -> DocHeaders {
|
) -> DocHeaders {
|
||||||
// true if a safety header was found
|
// true if a safety header was found
|
||||||
use pulldown_cmark::Event::{
|
|
||||||
Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
|
|
||||||
};
|
|
||||||
use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
|
|
||||||
use pulldown_cmark::{CodeBlockKind, CowStr};
|
|
||||||
|
|
||||||
let mut headers = DocHeaders::default();
|
let mut headers = DocHeaders::default();
|
||||||
let mut in_code = false;
|
let mut in_code = false;
|
||||||
let mut in_link = None;
|
let mut in_link = None;
|
||||||
|
@ -660,6 +656,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||||
check_link_quotes(cx, in_link.is_some(), trimmed_text, span, &range, begin, text.len());
|
check_link_quotes(cx, in_link.is_some(), trimmed_text, span, &range, begin, text.len());
|
||||||
// Adjust for the beginning of the current `Event`
|
// Adjust for the beginning of the current `Event`
|
||||||
let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
|
let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
|
||||||
|
if let Some(link) = in_link.as_ref()
|
||||||
|
&& let Ok(url) = Url::parse(link)
|
||||||
|
&& (url.scheme() == "https" || url.scheme() == "http") {
|
||||||
|
// Don't check the text associated with external URLs
|
||||||
|
continue;
|
||||||
|
}
|
||||||
text_to_check.push((text, span));
|
text_to_check.push((text, span));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -704,10 +706,8 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
|
||||||
let filename = FileName::anon_source_code(&code);
|
let filename = FileName::anon_source_code(&code);
|
||||||
|
|
||||||
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||||
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
|
let fallback_bundle =
|
||||||
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
|
rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
|
||||||
false
|
|
||||||
);
|
|
||||||
let emitter = EmitterWriter::new(
|
let emitter = EmitterWriter::new(
|
||||||
Box::new(io::sink()),
|
Box::new(io::sink()),
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use clippy_utils::{
|
||||||
source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
|
source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
|
||||||
SpanlessEq,
|
SpanlessEq,
|
||||||
};
|
};
|
||||||
use core::fmt::Write;
|
use core::fmt::{self, Write};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
hir_id::HirIdSet,
|
hir_id::HirIdSet,
|
||||||
|
@ -65,6 +65,10 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
|
||||||
impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
||||||
#[expect(clippy::too_many_lines)]
|
#[expect(clippy::too_many_lines)]
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
if expr.span.from_expansion() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
|
let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
|
@ -532,7 +536,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
|
||||||
if is_expr_used_or_unified(cx.tcx, insertion.call) {
|
if is_expr_used_or_unified(cx.tcx, insertion.call) {
|
||||||
write_wrapped(&mut res, insertion, ctxt, app);
|
write_wrapped(&mut res, insertion, ctxt, app);
|
||||||
} else {
|
} else {
|
||||||
let _ = write!(
|
let _: fmt::Result = write!(
|
||||||
res,
|
res,
|
||||||
"e.insert({})",
|
"e.insert({})",
|
||||||
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
|
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
|
||||||
|
@ -548,7 +552,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
|
||||||
(
|
(
|
||||||
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
|
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
|
||||||
// Insertion into a map would return `Some(&mut value)`, but the entry returns `&mut value`
|
// Insertion into a map would return `Some(&mut value)`, but the entry returns `&mut value`
|
||||||
let _ = write!(
|
let _: fmt::Result = write!(
|
||||||
res,
|
res,
|
||||||
"Some(e.insert({}))",
|
"Some(e.insert({}))",
|
||||||
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
|
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
|
||||||
|
@ -562,7 +566,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
|
||||||
(
|
(
|
||||||
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
|
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
|
||||||
// Insertion into a map would return `None`, but the entry returns a mutable reference.
|
// Insertion into a map would return `None`, but the entry returns a mutable reference.
|
||||||
let _ = if is_expr_final_block_expr(cx.tcx, insertion.call) {
|
let _: fmt::Result = if is_expr_final_block_expr(cx.tcx, insertion.call) {
|
||||||
write!(
|
write!(
|
||||||
res,
|
res,
|
||||||
"e.insert({});\n{}None",
|
"e.insert({});\n{}None",
|
||||||
|
|
|
@ -4,12 +4,17 @@ use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::MultiSpan;
|
use rustc_errors::MultiSpan;
|
||||||
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
|
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate,
|
BodyId, ExprKind, GenericBound, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
|
||||||
|
PredicateOrigin, Ty, TyKind, WherePredicate,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_span::{def_id::DefId, Span};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
|
use rustc_span::{
|
||||||
|
def_id::{DefId, LocalDefId},
|
||||||
|
Span,
|
||||||
|
};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
@ -21,7 +26,6 @@ declare_clippy_lint! {
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// // unused type parameters
|
|
||||||
/// fn unused_ty<T>(x: u8) {
|
/// fn unused_ty<T>(x: u8) {
|
||||||
/// // ..
|
/// // ..
|
||||||
/// }
|
/// }
|
||||||
|
@ -37,13 +41,35 @@ declare_clippy_lint! {
|
||||||
complexity,
|
complexity,
|
||||||
"unused type parameters in function definitions"
|
"unused type parameters in function definitions"
|
||||||
}
|
}
|
||||||
declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
|
|
||||||
|
pub struct ExtraUnusedTypeParameters {
|
||||||
|
avoid_breaking_exported_api: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExtraUnusedTypeParameters {
|
||||||
|
pub fn new(avoid_breaking_exported_api: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
avoid_breaking_exported_api,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Don't lint external macros or functions with empty bodies. Also, don't lint public items if
|
||||||
|
/// the `avoid_breaking_exported_api` config option is set.
|
||||||
|
fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDefId, body_id: BodyId) -> bool {
|
||||||
|
let body = cx.tcx.hir().body(body_id).value;
|
||||||
|
let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none());
|
||||||
|
let is_exported = cx.effective_visibilities.is_exported(def_id);
|
||||||
|
in_external_macro(cx.sess(), span) || (self.avoid_breaking_exported_api && is_exported) || fn_empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
|
||||||
|
|
||||||
/// A visitor struct that walks a given function and gathers generic type parameters, plus any
|
/// A visitor struct that walks a given function and gathers generic type parameters, plus any
|
||||||
/// trait bounds those parameters have.
|
/// trait bounds those parameters have.
|
||||||
struct TypeWalker<'cx, 'tcx> {
|
struct TypeWalker<'cx, 'tcx> {
|
||||||
cx: &'cx LateContext<'tcx>,
|
cx: &'cx LateContext<'tcx>,
|
||||||
/// Collection of all the type parameters and their spans.
|
/// Collection of all the function's type parameters.
|
||||||
ty_params: FxHashMap<DefId, Span>,
|
ty_params: FxHashMap<DefId, Span>,
|
||||||
/// Collection of any (inline) trait bounds corresponding to each type parameter.
|
/// Collection of any (inline) trait bounds corresponding to each type parameter.
|
||||||
bounds: FxHashMap<DefId, Span>,
|
bounds: FxHashMap<DefId, Span>,
|
||||||
|
@ -64,8 +90,8 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|param| {
|
.filter_map(|param| {
|
||||||
if let GenericParamKind::Type { .. } = param.kind {
|
if let GenericParamKind::Type { synthetic, .. } = param.kind {
|
||||||
Some((param.def_id.into(), param.span))
|
(!synthetic).then_some((param.def_id.into(), param.span))
|
||||||
} else {
|
} else {
|
||||||
if !param.is_elided_lifetime() {
|
if !param.is_elided_lifetime() {
|
||||||
all_params_unused = false;
|
all_params_unused = false;
|
||||||
|
@ -74,6 +100,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
cx,
|
cx,
|
||||||
ty_params,
|
ty_params,
|
||||||
|
@ -83,6 +110,12 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mark_param_used(&mut self, def_id: DefId) {
|
||||||
|
if self.ty_params.remove(&def_id).is_some() {
|
||||||
|
self.all_params_unused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_lint(&self) {
|
fn emit_lint(&self) {
|
||||||
let (msg, help) = match self.ty_params.len() {
|
let (msg, help) = match self.ty_params.len() {
|
||||||
0 => return,
|
0 => return,
|
||||||
|
@ -96,7 +129,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let source_map = self.cx.tcx.sess.source_map();
|
let source_map = self.cx.sess().source_map();
|
||||||
let span = if self.all_params_unused {
|
let span = if self.all_params_unused {
|
||||||
self.generics.span.into() // Remove the entire list of generics
|
self.generics.span.into() // Remove the entire list of generics
|
||||||
} else {
|
} else {
|
||||||
|
@ -118,14 +151,18 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a generic bound, if the bound is for a trait that's not a `LangItem`, return the
|
||||||
|
/// `LocalDefId` for that trait.
|
||||||
|
fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
|
||||||
|
bound.trait_ref()?.trait_def_id()?.as_local()
|
||||||
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
||||||
type NestedFilter = nested_filter::OnlyBodies;
|
type NestedFilter = nested_filter::OnlyBodies;
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
|
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
|
||||||
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
|
if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
|
||||||
if self.ty_params.remove(&def_id).is_some() {
|
self.mark_param_used(def_id);
|
||||||
self.all_params_unused = false;
|
|
||||||
}
|
|
||||||
} else if let TyKind::OpaqueDef(id, _, _) = t.kind {
|
} else if let TyKind::OpaqueDef(id, _, _) = t.kind {
|
||||||
// Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
|
// Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
|
||||||
// `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
|
// `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
|
||||||
|
@ -139,12 +176,21 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
||||||
|
|
||||||
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
||||||
if let WherePredicate::BoundPredicate(predicate) = predicate {
|
if let WherePredicate::BoundPredicate(predicate) = predicate {
|
||||||
// Collect spans for bounds that appear in the list of generics (not in a where-clause)
|
// Collect spans for any bounds on type parameters. We only keep bounds that appear in
|
||||||
// for use in forming the help message
|
// the list of generics (not in a where-clause).
|
||||||
if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param()
|
if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() {
|
||||||
&& let PredicateOrigin::GenericParam = predicate.origin
|
// If the bound contains non-public traits, err on the safe side and don't lint the
|
||||||
{
|
// corresponding parameter.
|
||||||
self.bounds.insert(def_id, predicate.span);
|
if !predicate
|
||||||
|
.bounds
|
||||||
|
.iter()
|
||||||
|
.filter_map(bound_to_trait_def_id)
|
||||||
|
.all(|id| self.cx.effective_visibilities.is_exported(id))
|
||||||
|
{
|
||||||
|
self.mark_param_used(def_id);
|
||||||
|
} else if let PredicateOrigin::GenericParam = predicate.origin {
|
||||||
|
self.bounds.insert(def_id, predicate.span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Only walk the right-hand side of where-bounds
|
// Only walk the right-hand side of where-bounds
|
||||||
for bound in predicate.bounds {
|
for bound in predicate.bounds {
|
||||||
|
@ -160,7 +206,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||||
if let ItemKind::Fn(_, generics, _) = item.kind {
|
if let ItemKind::Fn(_, generics, body_id) = item.kind
|
||||||
|
&& !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
|
||||||
|
{
|
||||||
let mut walker = TypeWalker::new(cx, generics);
|
let mut walker = TypeWalker::new(cx, generics);
|
||||||
walk_item(&mut walker, item);
|
walk_item(&mut walker, item);
|
||||||
walker.emit_lint();
|
walker.emit_lint();
|
||||||
|
@ -169,7 +217,10 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
|
||||||
|
|
||||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
|
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
|
||||||
// Only lint on inherent methods, not trait methods.
|
// Only lint on inherent methods, not trait methods.
|
||||||
if let ImplItemKind::Fn(..) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
|
if let ImplItemKind::Fn(.., body_id) = item.kind
|
||||||
|
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
||||||
|
&& !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
|
||||||
|
{
|
||||||
let mut walker = TypeWalker::new(cx, item.generics);
|
let mut walker = TypeWalker::new(cx, item.generics);
|
||||||
walk_impl_item(&mut walker, item);
|
walk_impl_item(&mut walker, item);
|
||||||
walker.emit_lint();
|
walker.emit_lint();
|
||||||
|
|
|
@ -340,6 +340,7 @@ fn check_one_arg(
|
||||||
if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
|
if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
|
||||||
&& let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
|
&& let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
|
||||||
&& let [segment] = path.segments
|
&& let [segment] = path.segments
|
||||||
|
&& segment.args.is_none()
|
||||||
&& let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id)
|
&& let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id)
|
||||||
{
|
{
|
||||||
let replacement = match param.usage {
|
let replacement = match param.usage {
|
||||||
|
|
50
clippy_lints/src/functions/impl_trait_in_params.rs
Normal file
50
clippy_lints/src/functions/impl_trait_in_params.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function};
|
||||||
|
|
||||||
|
use rustc_hir::{intravisit::FnKind, Body, HirId};
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use super::IMPL_TRAIT_IN_PARAMS;
|
||||||
|
|
||||||
|
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
|
||||||
|
if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id)
|
||||||
|
{
|
||||||
|
if let FnKind::ItemFn(ident, generics, _) = kind {
|
||||||
|
for param in generics.params {
|
||||||
|
if param.is_impl_trait() {
|
||||||
|
// No generics with nested generics, and no generics like FnMut(x)
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
IMPL_TRAIT_IN_PARAMS,
|
||||||
|
param.span,
|
||||||
|
"'`impl Trait` used as a function parameter'",
|
||||||
|
|diag| {
|
||||||
|
if let Some(gen_span) = generics.span_for_param_suggestion() {
|
||||||
|
diag.span_suggestion_with_style(
|
||||||
|
gen_span,
|
||||||
|
"add a type paremeter",
|
||||||
|
format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]),
|
||||||
|
rustc_errors::Applicability::HasPlaceholders,
|
||||||
|
rustc_errors::SuggestionStyle::ShowAlways,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
diag.span_suggestion_with_style(
|
||||||
|
Span::new(
|
||||||
|
body.params[0].span.lo() - rustc_span::BytePos(1),
|
||||||
|
ident.span.hi(),
|
||||||
|
ident.span.ctxt(),
|
||||||
|
ident.span.parent(),
|
||||||
|
),
|
||||||
|
"add a type paremeter",
|
||||||
|
format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]),
|
||||||
|
rustc_errors::Applicability::HasPlaceholders,
|
||||||
|
rustc_errors::SuggestionStyle::ShowAlways,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod impl_trait_in_params;
|
||||||
mod misnamed_getters;
|
mod misnamed_getters;
|
||||||
mod must_use;
|
mod must_use;
|
||||||
mod not_unsafe_ptr_arg_deref;
|
mod not_unsafe_ptr_arg_deref;
|
||||||
|
@ -327,6 +328,32 @@ declare_clippy_lint! {
|
||||||
"getter method returning the wrong field"
|
"getter method returning the wrong field"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Lints when `impl Trait` is being used in a function's paremeters.
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// trait MyTrait {}
|
||||||
|
/// fn foo(a: impl MyTrait) {
|
||||||
|
/// // [...]
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// trait MyTrait {}
|
||||||
|
/// fn foo<T: MyTrait>(a: T) {
|
||||||
|
/// // [...]
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.68.0"]
|
||||||
|
pub IMPL_TRAIT_IN_PARAMS,
|
||||||
|
restriction,
|
||||||
|
"`impl Trait` is used in the function's parameters"
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Functions {
|
pub struct Functions {
|
||||||
too_many_arguments_threshold: u64,
|
too_many_arguments_threshold: u64,
|
||||||
|
@ -354,6 +381,7 @@ impl_lint_pass!(Functions => [
|
||||||
RESULT_UNIT_ERR,
|
RESULT_UNIT_ERR,
|
||||||
RESULT_LARGE_ERR,
|
RESULT_LARGE_ERR,
|
||||||
MISNAMED_GETTERS,
|
MISNAMED_GETTERS,
|
||||||
|
IMPL_TRAIT_IN_PARAMS,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for Functions {
|
impl<'tcx> LateLintPass<'tcx> for Functions {
|
||||||
|
@ -371,6 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
|
||||||
too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
|
too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
|
||||||
not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
|
not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
|
||||||
misnamed_getters::check_fn(cx, kind, decl, body, span);
|
misnamed_getters::check_fn(cx, kind, decl, body, span);
|
||||||
|
impl_trait_in_params::check_fn(cx, &kind, body, hir_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_hir::{self as hir, ExprKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::{self, Write as _};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
|
||||||
let mut fields_snippet = String::new();
|
let mut fields_snippet = String::new();
|
||||||
let (last_ident, idents) = ordered_fields.split_last().unwrap();
|
let (last_ident, idents) = ordered_fields.split_last().unwrap();
|
||||||
for ident in idents {
|
for ident in idents {
|
||||||
let _ = write!(fields_snippet, "{ident}, ");
|
let _: fmt::Result = write!(fields_snippet, "{ident}, ");
|
||||||
}
|
}
|
||||||
fields_snippet.push_str(&last_ident.to_string());
|
fields_snippet.push_str(&last_ident.to_string());
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,45 @@ declare_clippy_lint! {
|
||||||
"non-binding `let` on a future"
|
"non-binding `let` on a future"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for `let _ = <expr>` without a type annotation, and suggests to either provide one,
|
||||||
|
/// or remove the `let` keyword altogether.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// The `let _ = <expr>` expression ignores the value of `<expr>` but will remain doing so even
|
||||||
|
/// if the type were to change, thus potentially introducing subtle bugs. By supplying a type
|
||||||
|
/// annotation, one will be forced to re-visit the decision to ignore the value in such cases.
|
||||||
|
///
|
||||||
|
/// ### Known problems
|
||||||
|
/// The `_ = <expr>` is not properly supported by some tools (e.g. IntelliJ) and may seem odd
|
||||||
|
/// to many developers. This lint also partially overlaps with the other `let_underscore_*`
|
||||||
|
/// lints.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// fn foo() -> Result<u32, ()> {
|
||||||
|
/// Ok(123)
|
||||||
|
/// }
|
||||||
|
/// let _ = foo();
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// fn foo() -> Result<u32, ()> {
|
||||||
|
/// Ok(123)
|
||||||
|
/// }
|
||||||
|
/// // Either provide a type annotation:
|
||||||
|
/// let _: Result<u32, ()> = foo();
|
||||||
|
/// // …or drop the let keyword:
|
||||||
|
/// _ = foo();
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.69.0"]
|
||||||
|
pub LET_UNDERSCORE_UNTYPED,
|
||||||
|
pedantic,
|
||||||
|
"non-binding `let` without a type annotation"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE, LET_UNDERSCORE_UNTYPED]);
|
||||||
|
|
||||||
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
|
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
|
||||||
&paths::PARKING_LOT_MUTEX_GUARD,
|
&paths::PARKING_LOT_MUTEX_GUARD,
|
||||||
|
@ -148,6 +186,18 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
||||||
"consider explicitly using function result",
|
"consider explicitly using function result",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if local.pat.default_binding_modes && local.ty.is_none() {
|
||||||
|
// When `default_binding_modes` is true, the `let` keyword is present.
|
||||||
|
span_lint_and_help(
|
||||||
|
cx,
|
||||||
|
LET_UNDERSCORE_UNTYPED,
|
||||||
|
local.span,
|
||||||
|
"non-binding `let` without a type annotation",
|
||||||
|
None,
|
||||||
|
"consider adding a type annotation or removing the `let` keyword",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#![feature(binary_heap_into_iter_sorted)]
|
#![feature(binary_heap_into_iter_sorted)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
|
#![feature(if_let_guard)]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(lint_reasons)]
|
#![feature(lint_reasons)]
|
||||||
|
@ -219,6 +220,7 @@ mod neg_cmp_op_on_partial_ord;
|
||||||
mod neg_multiply;
|
mod neg_multiply;
|
||||||
mod new_without_default;
|
mod new_without_default;
|
||||||
mod no_effect;
|
mod no_effect;
|
||||||
|
mod no_mangle_with_rust_abi;
|
||||||
mod non_copy_const;
|
mod non_copy_const;
|
||||||
mod non_expressive_names;
|
mod non_expressive_names;
|
||||||
mod non_octal_unix_permissions;
|
mod non_octal_unix_permissions;
|
||||||
|
@ -243,6 +245,7 @@ mod ptr;
|
||||||
mod ptr_offset_with_cast;
|
mod ptr_offset_with_cast;
|
||||||
mod pub_use;
|
mod pub_use;
|
||||||
mod question_mark;
|
mod question_mark;
|
||||||
|
mod question_mark_used;
|
||||||
mod ranges;
|
mod ranges;
|
||||||
mod rc_clone_in_vec_init;
|
mod rc_clone_in_vec_init;
|
||||||
mod read_zero_byte_vec;
|
mod read_zero_byte_vec;
|
||||||
|
@ -264,6 +267,7 @@ mod semicolon_block;
|
||||||
mod semicolon_if_nothing_returned;
|
mod semicolon_if_nothing_returned;
|
||||||
mod serde_api;
|
mod serde_api;
|
||||||
mod shadow;
|
mod shadow;
|
||||||
|
mod significant_drop_tightening;
|
||||||
mod single_char_lifetime_names;
|
mod single_char_lifetime_names;
|
||||||
mod single_component_path_imports;
|
mod single_component_path_imports;
|
||||||
mod size_of_in_element_count;
|
mod size_of_in_element_count;
|
||||||
|
@ -559,6 +563,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
|
store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
|
||||||
store.register_late_pass(|_| Box::new(mut_mut::MutMut));
|
store.register_late_pass(|_| Box::new(mut_mut::MutMut));
|
||||||
store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
|
store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
|
||||||
|
store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
|
||||||
store.register_late_pass(|_| Box::new(len_zero::LenZero));
|
store.register_late_pass(|_| Box::new(len_zero::LenZero));
|
||||||
store.register_late_pass(|_| Box::new(attrs::Attributes));
|
store.register_late_pass(|_| Box::new(attrs::Attributes));
|
||||||
store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
|
store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
|
||||||
|
@ -665,12 +670,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
|
let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
|
||||||
|
let missing_docs_in_crate_items = conf.missing_docs_in_crate_items;
|
||||||
store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
|
store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
|
||||||
store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
|
store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
|
||||||
store.register_late_pass(|_| Box::new(mem_forget::MemForget));
|
store.register_late_pass(|_| Box::new(mem_forget::MemForget));
|
||||||
store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
|
store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
|
||||||
store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
|
store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
|
||||||
store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new()));
|
store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items)));
|
||||||
store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
|
store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
|
||||||
store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
|
store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
|
||||||
store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
|
store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
|
||||||
|
@ -694,6 +700,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
|
store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
|
||||||
store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
|
store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
|
||||||
store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
|
store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
|
||||||
|
store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
|
||||||
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
|
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
|
||||||
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
|
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
|
||||||
store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
|
store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
|
||||||
|
@ -911,7 +918,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
|
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(size_of_ref::SizeOfRef));
|
||||||
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
|
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
|
||||||
store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters));
|
store.register_late_pass(move |_| {
|
||||||
|
Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(
|
||||||
|
avoid_breaking_exported_api,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
|
||||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,10 @@ fn check_fn_inner<'tcx>(
|
||||||
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
|
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
|
||||||
|
|
||||||
for typ in types {
|
for typ in types {
|
||||||
|
if !typ.span.eq_ctxt(span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for pred in generics.bounds_for_param(typ.def_id) {
|
for pred in generics.bounds_for_param(typ.def_id) {
|
||||||
if pred.origin == PredicateOrigin::WhereClause {
|
if pred.origin == PredicateOrigin::WhereClause {
|
||||||
// has_where_lifetimes checked that this predicate contains no lifetime.
|
// has_where_lifetimes checked that this predicate contains no lifetime.
|
||||||
|
@ -181,6 +185,10 @@ fn check_fn_inner<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) {
|
if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) {
|
||||||
|
if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let lts = elidable_lts
|
let lts = elidable_lts
|
||||||
.iter()
|
.iter()
|
||||||
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
|
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
|
||||||
|
|
|
@ -210,7 +210,7 @@ impl WarningType {
|
||||||
cx,
|
cx,
|
||||||
UNUSUAL_BYTE_GROUPINGS,
|
UNUSUAL_BYTE_GROUPINGS,
|
||||||
span,
|
span,
|
||||||
"digits of hex or binary literal not grouped by four",
|
"digits of hex, binary or octal literal not in groups of equal size",
|
||||||
"consider",
|
"consider",
|
||||||
suggested_format,
|
suggested_format,
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
|
@ -427,8 +427,12 @@ impl LiteralDigitGrouping {
|
||||||
|
|
||||||
let first = groups.next().expect("At least one group");
|
let first = groups.next().expect("At least one group");
|
||||||
|
|
||||||
if (radix == Radix::Binary || radix == Radix::Hexadecimal) && groups.any(|i| i != 4 && i != 2) {
|
if radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal {
|
||||||
return Err(WarningType::UnusualByteGroupings);
|
if let Some(second_size) = groups.next() {
|
||||||
|
if !groups.all(|i| i == second_size) || first > second_size {
|
||||||
|
return Err(WarningType::UnusualByteGroupings);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(second) = groups.next() {
|
if let Some(second) = groups.next() {
|
||||||
|
@ -484,7 +488,7 @@ impl DecimalLiteralRepresentation {
|
||||||
then {
|
then {
|
||||||
let hex = format!("{val:#X}");
|
let hex = format!("{val:#X}");
|
||||||
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
|
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
|
||||||
let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
|
let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
|
||||||
warning_type.display(num_lit.format(), cx, span);
|
warning_type.display(num_lit.format(), cx, span);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub(super) fn check(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
||||||
|
NeverLoopResult::IgnoreUntilEnd(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +49,8 @@ enum NeverLoopResult {
|
||||||
AlwaysBreak,
|
AlwaysBreak,
|
||||||
// A continue may occur for the main loop.
|
// A continue may occur for the main loop.
|
||||||
MayContinueMainLoop,
|
MayContinueMainLoop,
|
||||||
|
// Ignore everything until the end of the block with this id
|
||||||
|
IgnoreUntilEnd(HirId),
|
||||||
Otherwise,
|
Otherwise,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +59,7 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
|
||||||
match arg {
|
match arg {
|
||||||
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
|
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
|
||||||
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
|
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
|
||||||
|
NeverLoopResult::IgnoreUntilEnd(id) => NeverLoopResult::IgnoreUntilEnd(id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,27 +67,26 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
|
fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
|
||||||
match first {
|
match first {
|
||||||
NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first,
|
NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop | NeverLoopResult::IgnoreUntilEnd(_) => {
|
||||||
NeverLoopResult::Otherwise => second,
|
first
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine two results where both parts are called but not necessarily in order.
|
|
||||||
#[must_use]
|
|
||||||
fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
|
|
||||||
match (left, right) {
|
|
||||||
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
|
|
||||||
NeverLoopResult::MayContinueMainLoop
|
|
||||||
},
|
},
|
||||||
(NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
|
NeverLoopResult::Otherwise => second,
|
||||||
(NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine two results where only one of the part may have been executed.
|
// Combine two results where only one of the part may have been executed.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
|
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirId]) -> NeverLoopResult {
|
||||||
match (b1, b2) {
|
match (b1, b2) {
|
||||||
|
(NeverLoopResult::IgnoreUntilEnd(a), NeverLoopResult::IgnoreUntilEnd(b)) => {
|
||||||
|
if ignore_ids.iter().find(|&e| e == &a || e == &b).unwrap() == &a {
|
||||||
|
NeverLoopResult::IgnoreUntilEnd(b)
|
||||||
|
} else {
|
||||||
|
NeverLoopResult::IgnoreUntilEnd(a)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(i @ NeverLoopResult::IgnoreUntilEnd(_), NeverLoopResult::AlwaysBreak)
|
||||||
|
| (NeverLoopResult::AlwaysBreak, i @ NeverLoopResult::IgnoreUntilEnd(_)) => i,
|
||||||
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
|
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
|
||||||
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
|
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
|
||||||
NeverLoopResult::MayContinueMainLoop
|
NeverLoopResult::MayContinueMainLoop
|
||||||
|
@ -103,7 +106,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
|
||||||
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||||
// els is an else block in a let...else binding
|
// els is an else block in a let...else binding
|
||||||
els.map_or(e, |els| {
|
els.map_or(e, |els| {
|
||||||
combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id))
|
combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id), ignore_ids)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.fold(NeverLoopResult::Otherwise, combine_seq)
|
.fold(NeverLoopResult::Otherwise, combine_seq)
|
||||||
|
@ -139,7 +142,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||||
ExprKind::Struct(_, fields, base) => {
|
ExprKind::Struct(_, fields, base) => {
|
||||||
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
|
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
|
||||||
if let Some(base) = base {
|
if let Some(base) = base {
|
||||||
combine_both(fields, never_loop_expr(base, ignore_ids, main_loop_id))
|
combine_seq(fields, never_loop_expr(base, ignore_ids, main_loop_id))
|
||||||
} else {
|
} else {
|
||||||
fields
|
fields
|
||||||
}
|
}
|
||||||
|
@ -159,7 +162,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||||
let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
|
let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
|
||||||
never_loop_expr(e, ignore_ids, main_loop_id)
|
never_loop_expr(e, ignore_ids, main_loop_id)
|
||||||
});
|
});
|
||||||
combine_seq(e1, combine_branches(e2, e3))
|
combine_seq(e1, combine_branches(e2, e3, ignore_ids))
|
||||||
},
|
},
|
||||||
ExprKind::Match(e, arms, _) => {
|
ExprKind::Match(e, arms, _) => {
|
||||||
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||||
|
@ -175,8 +178,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||||
ignore_ids.push(b.hir_id);
|
ignore_ids.push(b.hir_id);
|
||||||
}
|
}
|
||||||
let ret = never_loop_block(b, ignore_ids, main_loop_id);
|
let ret = never_loop_block(b, ignore_ids, main_loop_id);
|
||||||
ignore_ids.pop();
|
if l.is_some() {
|
||||||
ret
|
ignore_ids.pop();
|
||||||
|
}
|
||||||
|
match ret {
|
||||||
|
NeverLoopResult::IgnoreUntilEnd(a) if a == b.hir_id => NeverLoopResult::Otherwise,
|
||||||
|
_ => ret,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ExprKind::Continue(d) => {
|
ExprKind::Continue(d) => {
|
||||||
let id = d
|
let id = d
|
||||||
|
@ -190,8 +198,8 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||||
},
|
},
|
||||||
// checks if break targets a block instead of a loop
|
// checks if break targets a block instead of a loop
|
||||||
ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
|
ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
|
||||||
.map_or(NeverLoopResult::Otherwise, |e| {
|
.map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| {
|
||||||
combine_seq(never_loop_expr(e, ignore_ids, main_loop_id), NeverLoopResult::Otherwise)
|
never_loop_expr(e, ignore_ids, main_loop_id)
|
||||||
}),
|
}),
|
||||||
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
|
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
|
||||||
combine_seq(
|
combine_seq(
|
||||||
|
@ -218,7 +226,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
|
||||||
| InlineAsmOperand::SymFn { .. }
|
| InlineAsmOperand::SymFn { .. }
|
||||||
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
|
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
|
||||||
})
|
})
|
||||||
.fold(NeverLoopResult::Otherwise, combine_both),
|
.fold(NeverLoopResult::Otherwise, combine_seq),
|
||||||
ExprKind::Yield(_, _)
|
ExprKind::Yield(_, _)
|
||||||
| ExprKind::Closure { .. }
|
| ExprKind::Closure { .. }
|
||||||
| ExprKind::Path(_)
|
| ExprKind::Path(_)
|
||||||
|
@ -234,7 +242,7 @@ fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
||||||
main_loop_id: HirId,
|
main_loop_id: HirId,
|
||||||
) -> NeverLoopResult {
|
) -> NeverLoopResult {
|
||||||
es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
|
es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
|
||||||
.fold(NeverLoopResult::Otherwise, combine_both)
|
.fold(NeverLoopResult::Otherwise, combine_seq)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
||||||
|
@ -242,8 +250,9 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
||||||
ignore_ids: &mut Vec<HirId>,
|
ignore_ids: &mut Vec<HirId>,
|
||||||
main_loop_id: HirId,
|
main_loop_id: HirId,
|
||||||
) -> NeverLoopResult {
|
) -> NeverLoopResult {
|
||||||
e.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
|
e.fold(NeverLoopResult::AlwaysBreak, |a, b| {
|
||||||
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
|
combine_branches(a, never_loop_expr(b, ignore_ids, main_loop_id), ignore_ids)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
|
fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
|
||||||
|
|
|
@ -4,11 +4,12 @@ use clippy_utils::msrvs::{self, Msrv};
|
||||||
use clippy_utils::peel_blocks;
|
use clippy_utils::peel_blocks;
|
||||||
use clippy_utils::source::snippet_with_context;
|
use clippy_utils::source::snippet_with_context;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use clippy_utils::visitors::{for_each_expr, Descend};
|
use clippy_utils::visitors::{Descend, Visitable};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
|
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||||
|
use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
|
@ -115,6 +116,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
|
.find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
|
||||||
let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
|
let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
|
||||||
|
// If the non-diverging arm is the first one, its pattern can be reused in a let/else statement.
|
||||||
|
// However, if it arrives in second position, its pattern may cover some cases already covered
|
||||||
|
// by the diverging one.
|
||||||
|
// TODO: accept the non-diverging arm as a second position if patterns are disjointed.
|
||||||
|
if idx == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let pat_arm = &arms[1 - idx];
|
let pat_arm = &arms[1 - idx];
|
||||||
if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
|
if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
|
||||||
return;
|
return;
|
||||||
|
@ -162,61 +170,102 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
|
/// Check whether an expression is divergent. May give false negatives.
|
||||||
fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
|
fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
|
struct V<'cx, 'tcx> {
|
||||||
return ty.is_never();
|
cx: &'cx LateContext<'tcx>,
|
||||||
}
|
res: ControlFlow<(), Descend>,
|
||||||
false
|
|
||||||
}
|
}
|
||||||
// We can't just call is_never on expr and be done, because the type system
|
impl<'tcx> Visitor<'tcx> for V<'_, '_> {
|
||||||
// sometimes coerces the ! type to something different before we can get
|
fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
|
||||||
// our hands on it. So instead, we do a manual search. We do fall back to
|
fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
|
||||||
// is_never in some places when there is no better alternative.
|
if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
|
||||||
for_each_expr(expr, |ex| {
|
return ty.is_never();
|
||||||
match ex.kind {
|
|
||||||
ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
|
|
||||||
ExprKind::Call(call, _) => {
|
|
||||||
if is_never(cx, ex) || is_never(cx, call) {
|
|
||||||
return ControlFlow::Break(());
|
|
||||||
}
|
}
|
||||||
ControlFlow::Continue(Descend::Yes)
|
false
|
||||||
},
|
}
|
||||||
ExprKind::MethodCall(..) => {
|
|
||||||
if is_never(cx, ex) {
|
|
||||||
return ControlFlow::Break(());
|
|
||||||
}
|
|
||||||
ControlFlow::Continue(Descend::Yes)
|
|
||||||
},
|
|
||||||
ExprKind::If(if_expr, if_then, if_else) => {
|
|
||||||
let else_diverges = if_else.map_or(false, |ex| expr_diverges(cx, ex));
|
|
||||||
let diverges = expr_diverges(cx, if_expr) || (else_diverges && expr_diverges(cx, if_then));
|
|
||||||
if diverges {
|
|
||||||
return ControlFlow::Break(());
|
|
||||||
}
|
|
||||||
ControlFlow::Continue(Descend::No)
|
|
||||||
},
|
|
||||||
ExprKind::Match(match_expr, match_arms, _) => {
|
|
||||||
let diverges = expr_diverges(cx, match_expr)
|
|
||||||
|| match_arms.iter().all(|arm| {
|
|
||||||
let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body()));
|
|
||||||
guard_diverges || expr_diverges(cx, arm.body)
|
|
||||||
});
|
|
||||||
if diverges {
|
|
||||||
return ControlFlow::Break(());
|
|
||||||
}
|
|
||||||
ControlFlow::Continue(Descend::No)
|
|
||||||
},
|
|
||||||
|
|
||||||
// Don't continue into loops or labeled blocks, as they are breakable,
|
if self.res.is_break() {
|
||||||
// and we'd have to start checking labels.
|
return;
|
||||||
ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
|
}
|
||||||
|
|
||||||
// Default: descend
|
// We can't just call is_never on expr and be done, because the type system
|
||||||
_ => ControlFlow::Continue(Descend::Yes),
|
// sometimes coerces the ! type to something different before we can get
|
||||||
|
// our hands on it. So instead, we do a manual search. We do fall back to
|
||||||
|
// is_never in some places when there is no better alternative.
|
||||||
|
self.res = match e.kind {
|
||||||
|
ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
|
||||||
|
ExprKind::Call(call, _) => {
|
||||||
|
if is_never(self.cx, e) || is_never(self.cx, call) {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(Descend::Yes)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::MethodCall(..) => {
|
||||||
|
if is_never(self.cx, e) {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(Descend::Yes)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::If(if_expr, if_then, if_else) => {
|
||||||
|
let else_diverges = if_else.map_or(false, |ex| expr_diverges(self.cx, ex));
|
||||||
|
let diverges =
|
||||||
|
expr_diverges(self.cx, if_expr) || (else_diverges && expr_diverges(self.cx, if_then));
|
||||||
|
if diverges {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(Descend::No)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::Match(match_expr, match_arms, _) => {
|
||||||
|
let diverges = expr_diverges(self.cx, match_expr)
|
||||||
|
|| match_arms.iter().all(|arm| {
|
||||||
|
let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(self.cx, g.body()));
|
||||||
|
guard_diverges || expr_diverges(self.cx, arm.body)
|
||||||
|
});
|
||||||
|
if diverges {
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(Descend::No)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Don't continue into loops or labeled blocks, as they are breakable,
|
||||||
|
// and we'd have to start checking labels.
|
||||||
|
ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
|
||||||
|
|
||||||
|
// Default: descend
|
||||||
|
_ => ControlFlow::Continue(Descend::Yes),
|
||||||
|
};
|
||||||
|
if let ControlFlow::Continue(Descend::Yes) = self.res {
|
||||||
|
walk_expr(self, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.is_some()
|
fn visit_local(&mut self, local: &'tcx Local<'_>) {
|
||||||
|
// Don't visit the else block of a let/else statement as it will not make
|
||||||
|
// the statement divergent even though the else block is divergent.
|
||||||
|
if let Some(init) = local.init {
|
||||||
|
self.visit_expr(init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid unnecessary `walk_*` calls.
|
||||||
|
fn visit_ty(&mut self, _: &'tcx Ty<'tcx>) {}
|
||||||
|
fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
|
||||||
|
fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
|
||||||
|
// Avoid monomorphising all `visit_*` functions.
|
||||||
|
fn visit_nested_item(&mut self, _: ItemId) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut v = V {
|
||||||
|
cx,
|
||||||
|
res: ControlFlow::Continue(Descend::Yes),
|
||||||
|
};
|
||||||
|
expr.visit(&mut v);
|
||||||
|
v.res.is_break()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
|
fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
|
||||||
|
|
|
@ -5,6 +5,8 @@ use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, LangItem};
|
use rustc_hir::{Expr, LangItem};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
|
|
||||||
|
use crate::methods::method_call;
|
||||||
|
|
||||||
use super::BYTES_NTH;
|
use super::BYTES_NTH;
|
||||||
|
|
||||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) {
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) {
|
||||||
|
@ -16,18 +18,32 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
span_lint_and_sugg(
|
let receiver = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
|
||||||
cx,
|
let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability);
|
||||||
BYTES_NTH,
|
|
||||||
expr.span,
|
if let Some(parent) = clippy_utils::get_parent_expr(cx, expr)
|
||||||
&format!("called `.bytes().nth()` on a `{caller_type}`"),
|
&& let Some((name, _, _, _, _)) = method_call(parent)
|
||||||
"try",
|
&& name == "unwrap" {
|
||||||
format!(
|
span_lint_and_sugg(
|
||||||
"{}.as_bytes().get({})",
|
cx,
|
||||||
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
|
BYTES_NTH,
|
||||||
snippet_with_applicability(cx, n_arg.span, "..", &mut applicability)
|
parent.span,
|
||||||
),
|
&format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"),
|
||||||
applicability,
|
"try",
|
||||||
);
|
format!("{receiver}.as_bytes()[{n}]",),
|
||||||
|
applicability
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
BYTES_NTH,
|
||||||
|
expr.span,
|
||||||
|
&format!("called `.bytes().nth()` on a `{caller_type}`"),
|
||||||
|
"try",
|
||||||
|
format!("{receiver}.as_bytes().get({n}).copied()"),
|
||||||
|
applicability
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
use clippy_utils::diagnostics::span_lint_and_help;
|
||||||
use clippy_utils::is_in_cfg_test;
|
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
|
use clippy_utils::{is_in_cfg_test, is_in_test_function};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
@ -27,7 +27,7 @@ pub(super) fn check(
|
||||||
|
|
||||||
let method = if is_err { "expect_err" } else { "expect" };
|
let method = if is_err { "expect_err" } else { "expect" };
|
||||||
|
|
||||||
if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
|
if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,9 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir
|
||||||
"to_vec" => cx
|
"to_vec" => cx
|
||||||
.tcx
|
.tcx
|
||||||
.impl_of_method(method_def_id)
|
.impl_of_method(method_def_id)
|
||||||
.filter(|&impl_did| cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none())
|
.filter(|&impl_did| {
|
||||||
|
cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
|
||||||
|
})
|
||||||
.is_some(),
|
.is_some(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ mod skip_while_next;
|
||||||
mod stable_sort_primitive;
|
mod stable_sort_primitive;
|
||||||
mod str_splitn;
|
mod str_splitn;
|
||||||
mod string_extend_chars;
|
mod string_extend_chars;
|
||||||
|
mod suspicious_command_arg_space;
|
||||||
mod suspicious_map;
|
mod suspicious_map;
|
||||||
mod suspicious_splitn;
|
mod suspicious_splitn;
|
||||||
mod suspicious_to_owned;
|
mod suspicious_to_owned;
|
||||||
|
@ -3162,6 +3163,32 @@ declare_clippy_lint! {
|
||||||
"collecting an iterator when collect is not needed"
|
"collecting an iterator when collect is not needed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
///
|
||||||
|
/// Checks for `Command::arg()` invocations that look like they
|
||||||
|
/// should be multiple arguments instead, such as `arg("-t ext2")`.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
///
|
||||||
|
/// `Command::arg()` does not split arguments by space. An argument like `arg("-t ext2")`
|
||||||
|
/// will be passed as a single argument to the command,
|
||||||
|
/// which is likely not what was intended.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.67.0"]
|
||||||
|
pub SUSPICIOUS_COMMAND_ARG_SPACE,
|
||||||
|
suspicious,
|
||||||
|
"single command line argument that looks like it should be multiple arguments"
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Methods {
|
pub struct Methods {
|
||||||
avoid_breaking_exported_api: bool,
|
avoid_breaking_exported_api: bool,
|
||||||
msrv: Msrv,
|
msrv: Msrv,
|
||||||
|
@ -3289,6 +3316,7 @@ impl_lint_pass!(Methods => [
|
||||||
SEEK_FROM_CURRENT,
|
SEEK_FROM_CURRENT,
|
||||||
SEEK_TO_START_INSTEAD_OF_REWIND,
|
SEEK_TO_START_INSTEAD_OF_REWIND,
|
||||||
NEEDLESS_COLLECT,
|
NEEDLESS_COLLECT,
|
||||||
|
SUSPICIOUS_COMMAND_ARG_SPACE,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// Extracts a method call name, args, and `Span` of the method name.
|
/// Extracts a method call name, args, and `Span` of the method name.
|
||||||
|
@ -3496,6 +3524,9 @@ impl Methods {
|
||||||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
|
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
("arg", [arg]) => {
|
||||||
|
suspicious_command_arg_space::check(cx, recv, arg, span);
|
||||||
|
}
|
||||||
("as_deref" | "as_deref_mut", []) => {
|
("as_deref" | "as_deref_mut", []) => {
|
||||||
needless_option_as_deref::check(cx, expr, recv, name);
|
needless_option_as_deref::check(cx, expr, recv, name);
|
||||||
},
|
},
|
||||||
|
|
39
clippy_lints/src/methods/suspicious_command_arg_space.rs
Normal file
39
clippy_lints/src/methods/suspicious_command_arg_space.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::paths;
|
||||||
|
use clippy_utils::ty::match_type;
|
||||||
|
use rustc_ast as ast;
|
||||||
|
use rustc_errors::{Applicability, Diagnostic};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use super::SUSPICIOUS_COMMAND_ARG_SPACE;
|
||||||
|
|
||||||
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
|
||||||
|
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||||
|
|
||||||
|
if match_type(cx, ty, &paths::STD_PROCESS_COMMAND)
|
||||||
|
&& let hir::ExprKind::Lit(lit) = &arg.kind
|
||||||
|
&& let ast::LitKind::Str(s, _) = &lit.node
|
||||||
|
&& let Some((arg1, arg2)) = s.as_str().split_once(' ')
|
||||||
|
&& arg1.starts_with('-')
|
||||||
|
&& arg1.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
|
||||||
|
{
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
SUSPICIOUS_COMMAND_ARG_SPACE,
|
||||||
|
arg.span,
|
||||||
|
"single argument that looks like it should be multiple arguments",
|
||||||
|
|diag: &mut Diagnostic| {
|
||||||
|
diag.multipart_suggestion_verbose(
|
||||||
|
"consider splitting the argument",
|
||||||
|
vec![
|
||||||
|
(span, "args".to_string()),
|
||||||
|
(arg.span, format!("[{arg1:?}, {arg2:?}]")),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
use clippy_utils::diagnostics::span_lint_and_help;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use clippy_utils::{is_in_cfg_test, is_lint_allowed};
|
use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
@ -27,7 +27,7 @@ pub(super) fn check(
|
||||||
|
|
||||||
let method_suffix = if is_err { "_err" } else { "" };
|
let method_suffix = if is_err { "_err" } else { "" };
|
||||||
|
|
||||||
if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
|
if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
use clippy_utils::attrs::is_doc_hidden;
|
use clippy_utils::attrs::is_doc_hidden;
|
||||||
use clippy_utils::diagnostics::span_lint;
|
use clippy_utils::diagnostics::span_lint;
|
||||||
use clippy_utils::is_from_proc_macro;
|
use clippy_utils::is_from_proc_macro;
|
||||||
|
use hir::def_id::LocalDefId;
|
||||||
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::ty::DefIdTree;
|
use rustc_middle::ty::{DefIdTree, Visibility};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::def_id::CRATE_DEF_ID;
|
use rustc_span::def_id::CRATE_DEF_ID;
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
|
@ -34,6 +36,9 @@ declare_clippy_lint! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MissingDoc {
|
pub struct MissingDoc {
|
||||||
|
/// Whether to **only** check for missing documentation in items visible within the current
|
||||||
|
/// crate. For example, `pub(crate)` items.
|
||||||
|
crate_items_only: bool,
|
||||||
/// Stack of whether #[doc(hidden)] is set
|
/// Stack of whether #[doc(hidden)] is set
|
||||||
/// at each level which has lint attributes.
|
/// at each level which has lint attributes.
|
||||||
doc_hidden_stack: Vec<bool>,
|
doc_hidden_stack: Vec<bool>,
|
||||||
|
@ -42,14 +47,15 @@ pub struct MissingDoc {
|
||||||
impl Default for MissingDoc {
|
impl Default for MissingDoc {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MissingDoc {
|
impl MissingDoc {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new(crate_items_only: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
crate_items_only,
|
||||||
doc_hidden_stack: vec![false],
|
doc_hidden_stack: vec![false],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +81,7 @@ impl MissingDoc {
|
||||||
fn check_missing_docs_attrs(
|
fn check_missing_docs_attrs(
|
||||||
&self,
|
&self,
|
||||||
cx: &LateContext<'_>,
|
cx: &LateContext<'_>,
|
||||||
|
def_id: LocalDefId,
|
||||||
attrs: &[ast::Attribute],
|
attrs: &[ast::Attribute],
|
||||||
sp: Span,
|
sp: Span,
|
||||||
article: &'static str,
|
article: &'static str,
|
||||||
|
@ -95,6 +102,13 @@ impl MissingDoc {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.crate_items_only && def_id != CRATE_DEF_ID {
|
||||||
|
let vis = cx.tcx.visibility(def_id);
|
||||||
|
if vis == Visibility::Public || vis != Visibility::Restricted(CRATE_DEF_ID.into()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let has_doc = attrs
|
let has_doc = attrs
|
||||||
.iter()
|
.iter()
|
||||||
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
|
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
|
||||||
|
@ -123,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||||
|
|
||||||
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
||||||
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
|
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
|
||||||
self.check_missing_docs_attrs(cx, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
|
self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
||||||
|
@ -159,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||||
|
|
||||||
let attrs = cx.tcx.hir().attrs(it.hir_id());
|
let attrs = cx.tcx.hir().attrs(it.hir_id());
|
||||||
if !is_from_proc_macro(cx, it) {
|
if !is_from_proc_macro(cx, it) {
|
||||||
self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
|
self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||||
|
|
||||||
let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
|
let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
|
||||||
if !is_from_proc_macro(cx, trait_item) {
|
if !is_from_proc_macro(cx, trait_item) {
|
||||||
self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
|
self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||||
let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
|
let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
|
||||||
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
|
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
|
||||||
if !is_from_proc_macro(cx, impl_item) {
|
if !is_from_proc_macro(cx, impl_item) {
|
||||||
self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
|
self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||||
if !sf.is_positional() {
|
if !sf.is_positional() {
|
||||||
let attrs = cx.tcx.hir().attrs(sf.hir_id);
|
let attrs = cx.tcx.hir().attrs(sf.hir_id);
|
||||||
if !is_from_proc_macro(cx, sf) {
|
if !is_from_proc_macro(cx, sf) {
|
||||||
self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
|
self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +215,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||||
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
|
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
|
||||||
let attrs = cx.tcx.hir().attrs(v.hir_id);
|
let attrs = cx.tcx.hir().attrs(v.hir_id);
|
||||||
if !is_from_proc_macro(cx, v) {
|
if !is_from_proc_macro(cx, v) {
|
||||||
self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
|
self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ fn process_paths_for_mod_files<'a>(
|
||||||
mod_folders: &mut FxHashSet<&'a OsStr>,
|
mod_folders: &mut FxHashSet<&'a OsStr>,
|
||||||
) {
|
) {
|
||||||
let mut comp = path.components().rev().peekable();
|
let mut comp = path.components().rev().peekable();
|
||||||
let _ = comp.next();
|
let _: Option<_> = comp.next();
|
||||||
if path.ends_with("mod.rs") {
|
if path.ends_with("mod.rs") {
|
||||||
mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default());
|
mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default());
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,8 @@ impl MutableKeyType {
|
||||||
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
|
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
|
||||||
Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
|
Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
|
||||||
Array(inner_ty, size) => {
|
Array(inner_ty, size) => {
|
||||||
size.try_eval_target_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
size.try_eval_target_usize(cx.tcx, cx.param_env)
|
||||||
|
.map_or(true, |u| u != 0)
|
||||||
&& self.is_interior_mutable_type(cx, inner_ty)
|
&& self.is_interior_mutable_type(cx, inner_ty)
|
||||||
},
|
},
|
||||||
Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
|
Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
|
let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
|
||||||
let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);
|
let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
|
||||||
|
|
||||||
for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
|
for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
|
||||||
// All spans generated from a proc-macro invocation are the same...
|
// All spans generated from a proc-macro invocation are the same...
|
||||||
|
|
65
clippy_lints/src/no_mangle_with_rust_abi.rs
Normal file
65
clippy_lints/src/no_mangle_with_rust_abi.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{Item, ItemKind};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for Rust ABI functions with the `#[no_mangle]` attribute.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// The Rust ABI is not stable, but in many simple cases matches
|
||||||
|
/// enough with the C ABI that it is possible to forget to add
|
||||||
|
/// `extern "C"` to a function called from C. Changes to the
|
||||||
|
/// Rust ABI can break this at any point.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// #[no_mangle]
|
||||||
|
/// fn example(arg_one: u32, arg_two: usize) {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// #[no_mangle]
|
||||||
|
/// extern "C" fn example(arg_one: u32, arg_two: usize) {}
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.69.0"]
|
||||||
|
pub NO_MANGLE_WITH_RUST_ABI,
|
||||||
|
pedantic,
|
||||||
|
"convert Rust ABI functions to C ABI"
|
||||||
|
}
|
||||||
|
declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
|
||||||
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||||
|
if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
|
||||||
|
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||||
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability);
|
||||||
|
for attr in attrs {
|
||||||
|
if let Some(ident) = attr.ident()
|
||||||
|
&& ident.name == rustc_span::sym::no_mangle
|
||||||
|
&& fn_sig.header.abi == Abi::Rust
|
||||||
|
&& !snippet.contains("extern") {
|
||||||
|
|
||||||
|
let suggestion = snippet.split_once("fn")
|
||||||
|
.map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#));
|
||||||
|
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
NO_MANGLE_WITH_RUST_ABI,
|
||||||
|
fn_sig.span,
|
||||||
|
"attribute #[no_mangle] set on a Rust ABI function",
|
||||||
|
"try",
|
||||||
|
suggestion,
|
||||||
|
applicability
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
use super::ARITHMETIC_SIDE_EFFECTS;
|
use super::ARITHMETIC_SIDE_EFFECTS;
|
||||||
use clippy_utils::{
|
use clippy_utils::{
|
||||||
consts::{constant, constant_simple},
|
consts::{constant, constant_simple, Constant},
|
||||||
diagnostics::span_lint,
|
diagnostics::span_lint,
|
||||||
peel_hir_expr_refs, peel_hir_expr_unary,
|
is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary,
|
||||||
};
|
};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
@ -97,17 +97,19 @@ impl ArithmeticSideEffects {
|
||||||
self.expr_span = Some(expr.span);
|
self.expr_span = Some(expr.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `expr` is not a literal integer like `1`, returns `None`.
|
/// Returns the numeric value of a literal integer originated from `expr`, if any.
|
||||||
///
|
///
|
||||||
/// Returns the absolute value of the expression, if this is an integer literal.
|
/// Literal integers can be originated from adhoc declarations like `1`, associated constants
|
||||||
fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
|
/// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
|
||||||
|
fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
|
||||||
let actual = peel_hir_expr_unary(expr).0;
|
let actual = peel_hir_expr_unary(expr).0;
|
||||||
if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
|
if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
|
||||||
Some(n)
|
return Some(n)
|
||||||
}
|
}
|
||||||
else {
|
if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
|
||||||
None
|
return Some(n);
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manages when the lint should be triggered. Operations in constant environments, hard coded
|
/// Manages when the lint should be triggered. Operations in constant environments, hard coded
|
||||||
|
@ -143,7 +145,10 @@ impl ArithmeticSideEffects {
|
||||||
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
|
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
|
||||||
let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
|
let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
|
||||||
let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
|
let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
|
||||||
match (Self::literal_integer(actual_lhs), Self::literal_integer(actual_rhs)) {
|
match (
|
||||||
|
Self::literal_integer(cx, actual_lhs),
|
||||||
|
Self::literal_integer(cx, actual_rhs),
|
||||||
|
) {
|
||||||
(None, None) => false,
|
(None, None) => false,
|
||||||
(None, Some(n)) | (Some(n), None) => match (&op.node, n) {
|
(None, Some(n)) | (Some(n), None) => match (&op.node, n) {
|
||||||
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
|
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
|
||||||
|
@ -180,20 +185,22 @@ impl ArithmeticSideEffects {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let actual_un_expr = peel_hir_expr_refs(un_expr).0;
|
let actual_un_expr = peel_hir_expr_refs(un_expr).0;
|
||||||
if Self::literal_integer(actual_un_expr).is_some() {
|
if Self::literal_integer(cx, actual_un_expr).is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.issue_lint(cx, expr);
|
self.issue_lint(cx, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool {
|
fn should_skip_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||||
self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span))
|
is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id)
|
||||||
|
|| self.expr_span.is_some()
|
||||||
|
|| self.const_span.map_or(false, |sp| sp.contains(expr.span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
|
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
|
||||||
if self.should_skip_expr(expr) {
|
if self.should_skip_expr(cx, expr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
|
|
52
clippy_lints/src/question_mark_used.rs
Normal file
52
clippy_lints/src/question_mark_used.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_help;
|
||||||
|
|
||||||
|
use clippy_utils::macros::span_is_local;
|
||||||
|
use rustc_hir::{Expr, ExprKind, MatchSource};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for expressions that use the question mark operator and rejects them.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Sometimes code wants to avoid the question mark operator because for instance a local
|
||||||
|
/// block requires a macro to re-throw errors to attach additional information to the
|
||||||
|
/// error.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```ignore
|
||||||
|
/// let result = expr?;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Could be written:
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// utility_macro!(expr);
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "pre 1.29.0"]
|
||||||
|
pub QUESTION_MARK_USED,
|
||||||
|
restriction,
|
||||||
|
"complains if the question mark operator is used"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind {
|
||||||
|
if !span_is_local(expr.span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
span_lint_and_help(
|
||||||
|
cx,
|
||||||
|
QUESTION_MARK_USED,
|
||||||
|
expr.span,
|
||||||
|
"question mark operator was used",
|
||||||
|
None,
|
||||||
|
"consider using a custom macro or match expression",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
use rustc_span::{BytePos, Pos};
|
use rustc_span::{BytePos, Pos};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
@ -69,31 +70,41 @@ declare_clippy_lint! {
|
||||||
"using a return statement like `return expr;` where an expression would suffice"
|
"using a return statement like `return expr;` where an expression would suffice"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
enum RetReplacement {
|
enum RetReplacement<'tcx> {
|
||||||
Empty,
|
Empty,
|
||||||
Block,
|
Block,
|
||||||
Unit,
|
Unit,
|
||||||
|
IfSequence(Cow<'tcx, str>, Applicability),
|
||||||
|
Expr(Cow<'tcx, str>, Applicability),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RetReplacement {
|
impl<'tcx> RetReplacement<'tcx> {
|
||||||
fn sugg_help(self) -> &'static str {
|
fn sugg_help(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Empty => "remove `return`",
|
Self::Empty | Self::Expr(..) => "remove `return`",
|
||||||
Self::Block => "replace `return` with an empty block",
|
Self::Block => "replace `return` with an empty block",
|
||||||
Self::Unit => "replace `return` with a unit value",
|
Self::Unit => "replace `return` with a unit value",
|
||||||
|
Self::IfSequence(..) => "remove `return` and wrap the sequence with parentheses",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn applicability(&self) -> Option<Applicability> {
|
||||||
|
match self {
|
||||||
|
Self::Expr(_, ap) | Self::IfSequence(_, ap) => Some(*ap),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for RetReplacement {
|
impl<'tcx> ToString for RetReplacement<'tcx> {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match *self {
|
match self {
|
||||||
Self::Empty => "",
|
Self::Empty => String::new(),
|
||||||
Self::Block => "{}",
|
Self::Block => "{}".to_string(),
|
||||||
Self::Unit => "()",
|
Self::Unit => "()".to_string(),
|
||||||
|
Self::IfSequence(inner, _) => format!("({inner})"),
|
||||||
|
Self::Expr(inner, _) => inner.to_string(),
|
||||||
}
|
}
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,26 +215,12 @@ fn check_final_expr<'tcx>(
|
||||||
expr: &'tcx Expr<'tcx>,
|
expr: &'tcx Expr<'tcx>,
|
||||||
semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
|
semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
|
||||||
* needless return */
|
* needless return */
|
||||||
replacement: RetReplacement,
|
replacement: RetReplacement<'tcx>,
|
||||||
) {
|
) {
|
||||||
let peeled_drop_expr = expr.peel_drop_temps();
|
let peeled_drop_expr = expr.peel_drop_temps();
|
||||||
match &peeled_drop_expr.kind {
|
match &peeled_drop_expr.kind {
|
||||||
// simple return is always "bad"
|
// simple return is always "bad"
|
||||||
ExprKind::Ret(ref inner) => {
|
ExprKind::Ret(ref inner) => {
|
||||||
// if desugar of `do yeet`, don't lint
|
|
||||||
if let Some(inner_expr) = inner
|
|
||||||
&& let ExprKind::Call(path_expr, _) = inner_expr.kind
|
|
||||||
&& let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
|
|
||||||
if borrows {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// check if expr return nothing
|
// check if expr return nothing
|
||||||
let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
|
let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
|
||||||
extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
|
extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
|
||||||
|
@ -231,7 +228,34 @@ fn check_final_expr<'tcx>(
|
||||||
peeled_drop_expr.span
|
peeled_drop_expr.span
|
||||||
};
|
};
|
||||||
|
|
||||||
emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
|
let replacement = if let Some(inner_expr) = inner {
|
||||||
|
// if desugar of `do yeet`, don't lint
|
||||||
|
if let ExprKind::Call(path_expr, _) = inner_expr.kind
|
||||||
|
&& let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
|
||||||
|
if expr_contains_conjunctive_ifs(inner_expr) {
|
||||||
|
RetReplacement::IfSequence(snippet, applicability)
|
||||||
|
} else {
|
||||||
|
RetReplacement::Expr(snippet, applicability)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
replacement
|
||||||
|
};
|
||||||
|
|
||||||
|
if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
|
||||||
|
if borrows {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_return_lint(cx, ret_span, semi_spans, replacement);
|
||||||
},
|
},
|
||||||
ExprKind::If(_, then, else_clause_opt) => {
|
ExprKind::If(_, then, else_clause_opt) => {
|
||||||
check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
|
check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
|
||||||
|
@ -253,29 +277,25 @@ fn check_final_expr<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_return_lint(
|
fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool {
|
||||||
cx: &LateContext<'_>,
|
fn contains_if(expr: &Expr<'_>, on_if: bool) -> bool {
|
||||||
ret_span: Span,
|
match expr.kind {
|
||||||
semi_spans: Vec<Span>,
|
ExprKind::If(..) => on_if,
|
||||||
inner_span: Option<Span>,
|
ExprKind::Binary(_, left, right) => contains_if(left, true) || contains_if(right, true),
|
||||||
replacement: RetReplacement,
|
_ => false,
|
||||||
) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_if(expr, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>, replacement: RetReplacement<'_>) {
|
||||||
if ret_span.from_expansion() {
|
if ret_span.from_expansion() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable);
|
||||||
let return_replacement = inner_span.map_or_else(
|
let return_replacement = replacement.to_string();
|
||||||
|| replacement.to_string(),
|
let sugg_help = replacement.sugg_help();
|
||||||
|inner_span| {
|
|
||||||
let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability);
|
|
||||||
snippet.to_string()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let sugg_help = if inner_span.is_some() {
|
|
||||||
"remove `return`"
|
|
||||||
} else {
|
|
||||||
replacement.sugg_help()
|
|
||||||
};
|
|
||||||
span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
|
span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
|
||||||
diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability);
|
diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability);
|
||||||
// for each parent statement, we need to remove the semicolon
|
// for each parent statement, we need to remove the semicolon
|
||||||
|
|
399
clippy_lints/src/significant_drop_tightening.rs
Normal file
399
clippy_lints/src/significant_drop_tightening.rs
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
use crate::FxHashSet;
|
||||||
|
use clippy_utils::{
|
||||||
|
diagnostics::span_lint_and_then,
|
||||||
|
get_attr,
|
||||||
|
source::{indent_of, snippet},
|
||||||
|
};
|
||||||
|
use rustc_errors::{Applicability, Diagnostic};
|
||||||
|
use rustc_hir::{
|
||||||
|
self as hir,
|
||||||
|
intravisit::{walk_expr, Visitor},
|
||||||
|
};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
|
use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut};
|
||||||
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
|
use rustc_span::{symbol::Ident, Span, DUMMY_SP};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
///
|
||||||
|
/// Searches for elements marked with `#[clippy::significant_drop]` that could be early
|
||||||
|
/// dropped but are in fact dropped at the end of their scopes. In other words, enforces the
|
||||||
|
/// "tightening" of their possible lifetimes.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
///
|
||||||
|
/// Elements marked with `#[clippy::has_significant_drop]` are generally synchronizing
|
||||||
|
/// primitives that manage shared resources, as such, it is desired to release them as soon as
|
||||||
|
/// possible to avoid unnecessary resource contention.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// fn main() {
|
||||||
|
/// let lock = some_sync_resource.lock();
|
||||||
|
/// let owned_rslt = lock.do_stuff_with_resource();
|
||||||
|
/// // Only `owned_rslt` is needed but `lock` is still held.
|
||||||
|
/// do_heavy_computation_that_takes_time(owned_rslt);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// fn main() {
|
||||||
|
/// let owned_rslt = some_sync_resource.lock().do_stuff_with_resource();
|
||||||
|
/// do_heavy_computation_that_takes_time(owned_rslt);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.67.0"]
|
||||||
|
pub SIGNIFICANT_DROP_TIGHTENING,
|
||||||
|
nursery,
|
||||||
|
"Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes"
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]);
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SignificantDropTightening<'tcx> {
|
||||||
|
/// Auxiliary structure used to avoid having to verify the same type multiple times.
|
||||||
|
seen_types: FxHashSet<Ty<'tcx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> SignificantDropTightening<'tcx> {
|
||||||
|
/// Unifies the statements of a block with its return expression.
|
||||||
|
fn all_block_stmts<'ret, 'rslt, 'stmts>(
|
||||||
|
block_stmts: &'stmts [hir::Stmt<'tcx>],
|
||||||
|
dummy_ret_stmt: Option<&'ret hir::Stmt<'tcx>>,
|
||||||
|
) -> impl Iterator<Item = &'rslt hir::Stmt<'tcx>>
|
||||||
|
where
|
||||||
|
'ret: 'rslt,
|
||||||
|
'stmts: 'rslt,
|
||||||
|
{
|
||||||
|
block_stmts.iter().chain(dummy_ret_stmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Searches for at least one statement that could slow down the release of a significant drop.
|
||||||
|
fn at_least_one_stmt_is_expensive<'stmt>(stmts: impl Iterator<Item = &'stmt hir::Stmt<'tcx>>) -> bool
|
||||||
|
where
|
||||||
|
'tcx: 'stmt,
|
||||||
|
{
|
||||||
|
for stmt in stmts {
|
||||||
|
match stmt.kind {
|
||||||
|
hir::StmtKind::Expr(expr) if let hir::ExprKind::Path(_) = expr.kind => {}
|
||||||
|
hir::StmtKind::Local(local) if let Some(expr) = local.init
|
||||||
|
&& let hir::ExprKind::Path(_) = expr.kind => {},
|
||||||
|
_ => return true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies if the expression is of type `drop(some_lock_path)` to assert that the temporary
|
||||||
|
/// is already being dropped before the end of its scope.
|
||||||
|
fn has_drop(expr: &'tcx hir::Expr<'_>, init_bind_ident: Ident) -> bool {
|
||||||
|
if let hir::ExprKind::Call(fun, args) = expr.kind
|
||||||
|
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
|
||||||
|
&& let [fun_ident, ..] = fun_path.segments
|
||||||
|
&& fun_ident.ident.name == rustc_span::sym::drop
|
||||||
|
&& let [first_arg, ..] = args
|
||||||
|
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
|
||||||
|
&& let [first_arg_ps, .. ] = arg_path.segments
|
||||||
|
{
|
||||||
|
first_arg_ps.ident == init_bind_ident
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to find types marked with `#[has_significant_drop]` of an expression `expr` that is
|
||||||
|
/// originated from `stmt` and then performs common logic on `sdap`.
|
||||||
|
fn modify_sdap_if_sig_drop_exists(
|
||||||
|
&mut self,
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
expr: &'tcx hir::Expr<'_>,
|
||||||
|
idx: usize,
|
||||||
|
sdap: &mut SigDropAuxParams,
|
||||||
|
stmt: &hir::Stmt<'_>,
|
||||||
|
cb: impl Fn(&mut SigDropAuxParams),
|
||||||
|
) {
|
||||||
|
let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types);
|
||||||
|
sig_drop_finder.visit_expr(expr);
|
||||||
|
if sig_drop_finder.has_sig_drop {
|
||||||
|
cb(sdap);
|
||||||
|
if sdap.number_of_stmts > 0 {
|
||||||
|
sdap.last_use_stmt_idx = idx;
|
||||||
|
sdap.last_use_stmt_span = stmt.span;
|
||||||
|
if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
|
||||||
|
sdap.last_use_method_span = span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sdap.number_of_stmts = sdap.number_of_stmts.wrapping_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shows generic overall messages as well as specialized messages depending on the usage.
|
||||||
|
fn set_suggestions(cx: &LateContext<'tcx>, block_span: Span, diag: &mut Diagnostic, sdap: &SigDropAuxParams) {
|
||||||
|
match sdap.number_of_stmts {
|
||||||
|
0 | 1 => {},
|
||||||
|
2 => {
|
||||||
|
let indent = " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0));
|
||||||
|
let init_method = snippet(cx, sdap.init_method_span, "..");
|
||||||
|
let usage_method = snippet(cx, sdap.last_use_method_span, "..");
|
||||||
|
let stmt = if let Some(last_use_bind_span) = sdap.last_use_bind_span {
|
||||||
|
format!(
|
||||||
|
"\n{indent}let {} = {init_method}.{usage_method};",
|
||||||
|
snippet(cx, last_use_bind_span, ".."),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("\n{indent}{init_method}.{usage_method};")
|
||||||
|
};
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
sdap.init_stmt_span,
|
||||||
|
"merge the temporary construction with its single usage",
|
||||||
|
stmt,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
diag.span_suggestion(
|
||||||
|
sdap.last_use_stmt_span,
|
||||||
|
"remove separated single usage",
|
||||||
|
"",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
diag.span_suggestion(
|
||||||
|
sdap.last_use_stmt_span.shrink_to_hi(),
|
||||||
|
"drop the temporary after the end of its last usage",
|
||||||
|
format!(
|
||||||
|
"\n{}drop({});",
|
||||||
|
" ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)),
|
||||||
|
sdap.init_bind_ident
|
||||||
|
),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
diag.note("this might lead to unnecessary resource contention");
|
||||||
|
diag.span_label(
|
||||||
|
block_span,
|
||||||
|
format!(
|
||||||
|
"temporary `{}` is currently being dropped at the end of its contained scope",
|
||||||
|
sdap.init_bind_ident
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> {
|
||||||
|
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
|
||||||
|
let dummy_ret_stmt = block.expr.map(|expr| hir::Stmt {
|
||||||
|
hir_id: hir::HirId::INVALID,
|
||||||
|
kind: hir::StmtKind::Expr(expr),
|
||||||
|
span: DUMMY_SP,
|
||||||
|
});
|
||||||
|
let mut sdap = SigDropAuxParams::default();
|
||||||
|
for (idx, stmt) in Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).enumerate() {
|
||||||
|
match stmt.kind {
|
||||||
|
hir::StmtKind::Expr(expr) => self.modify_sdap_if_sig_drop_exists(
|
||||||
|
cx,
|
||||||
|
expr,
|
||||||
|
idx,
|
||||||
|
&mut sdap,
|
||||||
|
stmt,
|
||||||
|
|_| {}
|
||||||
|
),
|
||||||
|
hir::StmtKind::Local(local) if let Some(expr) = local.init => self.modify_sdap_if_sig_drop_exists(
|
||||||
|
cx,
|
||||||
|
expr,
|
||||||
|
idx,
|
||||||
|
&mut sdap,
|
||||||
|
stmt,
|
||||||
|
|local_sdap| {
|
||||||
|
if local_sdap.number_of_stmts == 0 {
|
||||||
|
if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
|
||||||
|
local_sdap.init_bind_ident = ident;
|
||||||
|
}
|
||||||
|
if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr.kind {
|
||||||
|
local_sdap.init_method_span = local_expr.span.to(span);
|
||||||
|
}
|
||||||
|
local_sdap.init_stmt_span = stmt.span;
|
||||||
|
}
|
||||||
|
else if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
|
||||||
|
local_sdap.last_use_bind_span = Some(ident.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
hir::StmtKind::Semi(expr) => {
|
||||||
|
if Self::has_drop(expr, sdap.init_bind_ident) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.modify_sdap_if_sig_drop_exists(cx, expr, idx, &mut sdap, stmt, |_| {});
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = sdap.last_use_stmt_idx.wrapping_add(1);
|
||||||
|
let stmts_after_last_use = Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).skip(idx);
|
||||||
|
if sdap.number_of_stmts > 1 && Self::at_least_one_stmt_is_expensive(stmts_after_last_use) {
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
SIGNIFICANT_DROP_TIGHTENING,
|
||||||
|
sdap.init_bind_ident.span,
|
||||||
|
"temporary with significant `Drop` can be early dropped",
|
||||||
|
|diag| {
|
||||||
|
Self::set_suggestions(cx, block.span, diag, &sdap);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auxiliary parameters used on each block check.
|
||||||
|
struct SigDropAuxParams {
|
||||||
|
/// The binding or variable that references the initial construction of the type marked with
|
||||||
|
/// `#[has_significant_drop]`.
|
||||||
|
init_bind_ident: Ident,
|
||||||
|
/// Similar to `init_bind_ident` but encompasses the right-hand method call.
|
||||||
|
init_method_span: Span,
|
||||||
|
/// Similar to `init_bind_ident` but encompasses the whole contained statement.
|
||||||
|
init_stmt_span: Span,
|
||||||
|
|
||||||
|
/// The last visited binding or variable span within a block that had any referenced inner type
|
||||||
|
/// marked with `#[has_significant_drop]`.
|
||||||
|
last_use_bind_span: Option<Span>,
|
||||||
|
/// Index of the last visited statement within a block that had any referenced inner type
|
||||||
|
/// marked with `#[has_significant_drop]`.
|
||||||
|
last_use_stmt_idx: usize,
|
||||||
|
/// Similar to `last_use_bind_span` but encompasses the whole contained statement.
|
||||||
|
last_use_stmt_span: Span,
|
||||||
|
/// Similar to `last_use_bind_span` but encompasses the right-hand method call.
|
||||||
|
last_use_method_span: Span,
|
||||||
|
|
||||||
|
/// Total number of statements within a block that have any referenced inner type marked with
|
||||||
|
/// `#[has_significant_drop]`.
|
||||||
|
number_of_stmts: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SigDropAuxParams {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
init_bind_ident: Ident::empty(),
|
||||||
|
init_method_span: DUMMY_SP,
|
||||||
|
init_stmt_span: DUMMY_SP,
|
||||||
|
last_use_bind_span: None,
|
||||||
|
last_use_method_span: DUMMY_SP,
|
||||||
|
last_use_stmt_idx: 0,
|
||||||
|
last_use_stmt_span: DUMMY_SP,
|
||||||
|
number_of_stmts: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks the existence of the `#[has_significant_drop]` attribute
|
||||||
|
struct SigDropChecker<'cx, 'sdt, 'tcx> {
|
||||||
|
cx: &'cx LateContext<'tcx>,
|
||||||
|
seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
|
||||||
|
pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self {
|
||||||
|
seen_types.clear();
|
||||||
|
Self { cx, seen_types }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
|
||||||
|
if let Some(adt) = ty.ty_adt_def() {
|
||||||
|
let mut iter = get_attr(
|
||||||
|
self.cx.sess(),
|
||||||
|
self.cx.tcx.get_attrs_unchecked(adt.did()),
|
||||||
|
"has_significant_drop",
|
||||||
|
);
|
||||||
|
if iter.next().is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match ty.kind() {
|
||||||
|
rustc_middle::ty::Adt(a, b) => {
|
||||||
|
for f in a.all_fields() {
|
||||||
|
let ty = f.ty(self.cx.tcx, b);
|
||||||
|
if !self.has_seen_ty(ty) && self.has_sig_drop_attr(ty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for generic_arg in b.iter() {
|
||||||
|
if let GenericArgKind::Type(ty) = generic_arg.unpack() {
|
||||||
|
if self.has_sig_drop_attr(ty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
},
|
||||||
|
rustc_middle::ty::Array(ty, _)
|
||||||
|
| rustc_middle::ty::RawPtr(TypeAndMut { ty, .. })
|
||||||
|
| rustc_middle::ty::Ref(_, ty, _)
|
||||||
|
| rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||||
|
!self.seen_types.insert(ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs recursive calls to find any inner type marked with `#[has_significant_drop]`.
|
||||||
|
struct SigDropFinder<'cx, 'sdt, 'tcx> {
|
||||||
|
cx: &'cx LateContext<'tcx>,
|
||||||
|
has_sig_drop: bool,
|
||||||
|
sig_drop_checker: SigDropChecker<'cx, 'sdt, 'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> {
|
||||||
|
fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self {
|
||||||
|
Self {
|
||||||
|
cx,
|
||||||
|
has_sig_drop: false,
|
||||||
|
sig_drop_checker: SigDropChecker::new(cx, seen_types),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> {
|
||||||
|
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) {
|
||||||
|
if self
|
||||||
|
.sig_drop_checker
|
||||||
|
.has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex))
|
||||||
|
{
|
||||||
|
self.has_sig_drop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match ex.kind {
|
||||||
|
hir::ExprKind::MethodCall(_, expr, ..) => {
|
||||||
|
self.visit_expr(expr);
|
||||||
|
},
|
||||||
|
hir::ExprKind::Array(..)
|
||||||
|
| hir::ExprKind::Assign(..)
|
||||||
|
| hir::ExprKind::AssignOp(..)
|
||||||
|
| hir::ExprKind::Binary(..)
|
||||||
|
| hir::ExprKind::Box(..)
|
||||||
|
| hir::ExprKind::Call(..)
|
||||||
|
| hir::ExprKind::Field(..)
|
||||||
|
| hir::ExprKind::If(..)
|
||||||
|
| hir::ExprKind::Index(..)
|
||||||
|
| hir::ExprKind::Match(..)
|
||||||
|
| hir::ExprKind::Repeat(..)
|
||||||
|
| hir::ExprKind::Ret(..)
|
||||||
|
| hir::ExprKind::Tup(..)
|
||||||
|
| hir::ExprKind::Unary(..)
|
||||||
|
| hir::ExprKind::Yield(..) => {
|
||||||
|
walk_expr(self, ex);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::{sym, symbol::Ident, Span};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
@ -174,55 +174,76 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||||
|
|
||||||
/// Implementation of the `ALMOST_SWAPPED` lint.
|
/// Implementation of the `ALMOST_SWAPPED` lint.
|
||||||
fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||||
for w in block.stmts.windows(2) {
|
for [first, second] in block.stmts.array_windows() {
|
||||||
if_chain! {
|
if let Some((lhs0, rhs0)) = parse(first)
|
||||||
if let StmtKind::Semi(first) = w[0].kind;
|
&& let Some((lhs1, rhs1)) = parse(second)
|
||||||
if let StmtKind::Semi(second) = w[1].kind;
|
&& first.span.eq_ctxt(second.span)
|
||||||
if first.span.ctxt() == second.span.ctxt();
|
&& is_same(cx, lhs0, rhs1)
|
||||||
if let ExprKind::Assign(lhs0, rhs0, _) = first.kind;
|
&& is_same(cx, lhs1, rhs0)
|
||||||
if let ExprKind::Assign(lhs1, rhs1, _) = second.kind;
|
&& let Some(lhs_sugg) = match &lhs0 {
|
||||||
if eq_expr_value(cx, lhs0, rhs1);
|
ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr),
|
||||||
if eq_expr_value(cx, lhs1, rhs0);
|
ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())),
|
||||||
then {
|
}
|
||||||
let lhs0 = Sugg::hir_opt(cx, lhs0);
|
&& let Some(rhs_sugg) = Sugg::hir_opt(cx, rhs0)
|
||||||
let rhs0 = Sugg::hir_opt(cx, rhs0);
|
{
|
||||||
let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
|
let span = first.span.to(rhs1.span);
|
||||||
(
|
let Some(sugg) = std_or_core(cx) else { return };
|
||||||
format!(" `{first}` and `{second}`"),
|
span_lint_and_then(
|
||||||
first.mut_addr().to_string(),
|
cx,
|
||||||
second.mut_addr().to_string(),
|
ALMOST_SWAPPED,
|
||||||
)
|
span,
|
||||||
} else {
|
&format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"),
|
||||||
(String::new(), String::new(), String::new())
|
|diag| {
|
||||||
};
|
diag.span_suggestion(
|
||||||
|
span,
|
||||||
|
"try",
|
||||||
|
format!("{sugg}::mem::swap({}, {})", lhs_sugg.mut_addr(), rhs_sugg.mut_addr()),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let span = first.span.to(second.span);
|
fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool {
|
||||||
let Some(sugg) = std_or_core(cx) else { return };
|
match lhs {
|
||||||
|
ExprOrIdent::Expr(expr) => eq_expr_value(cx, expr, rhs),
|
||||||
span_lint_and_then(cx,
|
ExprOrIdent::Ident(ident) => {
|
||||||
ALMOST_SWAPPED,
|
if let ExprKind::Path(QPath::Resolved(None, path)) = rhs.kind
|
||||||
span,
|
&& let [segment] = &path.segments
|
||||||
&format!("this looks like you are trying to swap{what}"),
|
&& segment.ident == ident
|
||||||
|diag| {
|
{
|
||||||
if !what.is_empty() {
|
true
|
||||||
diag.span_suggestion(
|
} else {
|
||||||
span,
|
false
|
||||||
"try",
|
|
||||||
format!(
|
|
||||||
"{sugg}::mem::swap({lhs}, {rhs})",
|
|
||||||
),
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
diag.note(
|
|
||||||
format!("or maybe you should use `{sugg}::mem::replace`?")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum ExprOrIdent<'a> {
|
||||||
|
Expr(&'a Expr<'a>),
|
||||||
|
Ident(Ident),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<'hir>)> {
|
||||||
|
if let StmtKind::Semi(expr) = stmt.kind {
|
||||||
|
if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
|
||||||
|
return Some((ExprOrIdent::Expr(lhs), rhs));
|
||||||
|
}
|
||||||
|
} else if let StmtKind::Local(expr) = stmt.kind {
|
||||||
|
if let Some(rhs) = expr.init {
|
||||||
|
if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind {
|
||||||
|
return Some((ExprOrIdent::Ident(ident_l), rhs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Implementation of the xor case for `MANUAL_SWAP` lint.
|
/// Implementation of the xor case for `MANUAL_SWAP` lint.
|
||||||
fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||||
for window in block.stmts.windows(3) {
|
for window in block.stmts.windows(3) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ mod transmute_float_to_int;
|
||||||
mod transmute_int_to_bool;
|
mod transmute_int_to_bool;
|
||||||
mod transmute_int_to_char;
|
mod transmute_int_to_char;
|
||||||
mod transmute_int_to_float;
|
mod transmute_int_to_float;
|
||||||
|
mod transmute_int_to_non_zero;
|
||||||
mod transmute_null_to_fn;
|
mod transmute_null_to_fn;
|
||||||
mod transmute_num_to_bytes;
|
mod transmute_num_to_bytes;
|
||||||
mod transmute_ptr_to_ptr;
|
mod transmute_ptr_to_ptr;
|
||||||
|
@ -253,6 +254,31 @@ declare_clippy_lint! {
|
||||||
"transmutes from an integer to a float"
|
"transmutes from an integer to a float"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked`
|
||||||
|
/// method instead.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Transmutes work on any types and thus might cause unsoundness when those types change
|
||||||
|
/// elsewhere. `new_unchecked` only works for the appropriate types instead.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// # use core::num::NonZeroU32;
|
||||||
|
/// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) };
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// # use core::num::NonZeroU32;
|
||||||
|
/// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) };
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.69.0"]
|
||||||
|
pub TRANSMUTE_INT_TO_NON_ZERO,
|
||||||
|
complexity,
|
||||||
|
"transmutes from an integer to a non-zero wrapper"
|
||||||
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Checks for transmutes from a float to an integer.
|
/// Checks for transmutes from a float to an integer.
|
||||||
|
@ -451,6 +477,7 @@ impl_lint_pass!(Transmute => [
|
||||||
TRANSMUTE_BYTES_TO_STR,
|
TRANSMUTE_BYTES_TO_STR,
|
||||||
TRANSMUTE_INT_TO_BOOL,
|
TRANSMUTE_INT_TO_BOOL,
|
||||||
TRANSMUTE_INT_TO_FLOAT,
|
TRANSMUTE_INT_TO_FLOAT,
|
||||||
|
TRANSMUTE_INT_TO_NON_ZERO,
|
||||||
TRANSMUTE_FLOAT_TO_INT,
|
TRANSMUTE_FLOAT_TO_INT,
|
||||||
TRANSMUTE_NUM_TO_BYTES,
|
TRANSMUTE_NUM_TO_BYTES,
|
||||||
UNSOUND_COLLECTION_TRANSMUTE,
|
UNSOUND_COLLECTION_TRANSMUTE,
|
||||||
|
@ -501,6 +528,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
|
||||||
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
|
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
|
||||||
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
|
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
|
||||||
| transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
|
| transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||||
|
| transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
|
||||||
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
|
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||||
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
|
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||||
| (
|
| (
|
||||||
|
|
61
clippy_lints/src/transmute/transmute_int_to_non_zero.rs
Normal file
61
clippy_lints/src/transmute/transmute_int_to_non_zero.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
use super::TRANSMUTE_INT_TO_NON_ZERO;
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::sugg;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::Expr;
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::{
|
||||||
|
query::Key,
|
||||||
|
ty::{self, Ty},
|
||||||
|
};
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
/// Checks for `transmute_int_to_non_zero` lint.
|
||||||
|
/// Returns `true` if it's triggered, otherwise returns `false`.
|
||||||
|
pub(super) fn check<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
e: &'tcx Expr<'_>,
|
||||||
|
from_ty: Ty<'tcx>,
|
||||||
|
to_ty: Ty<'tcx>,
|
||||||
|
arg: &'tcx Expr<'_>,
|
||||||
|
) -> bool {
|
||||||
|
let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if !matches!(
|
||||||
|
to_type_sym,
|
||||||
|
sym::NonZeroU8
|
||||||
|
| sym::NonZeroU16
|
||||||
|
| sym::NonZeroU32
|
||||||
|
| sym::NonZeroU64
|
||||||
|
| sym::NonZeroU128
|
||||||
|
| sym::NonZeroI8
|
||||||
|
| sym::NonZeroI16
|
||||||
|
| sym::NonZeroI32
|
||||||
|
| sym::NonZeroI64
|
||||||
|
| sym::NonZeroI128
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
TRANSMUTE_INT_TO_NON_ZERO,
|
||||||
|
e.span,
|
||||||
|
&format!("transmute from a `{from_ty}` to a `{to_type_sym}`"),
|
||||||
|
|diag| {
|
||||||
|
let arg = sugg::Sugg::hir(cx, arg, "..");
|
||||||
|
diag.span_suggestion(
|
||||||
|
e.span,
|
||||||
|
"consider using",
|
||||||
|
format!("{to_type_sym}::{}({arg})", sym::new_unchecked),
|
||||||
|
Applicability::Unspecified,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
|
@ -400,7 +400,7 @@ fn drain_matching(
|
||||||
|
|
||||||
// If `ThinVec` had the `drain_filter` method, this loop could be rewritten
|
// If `ThinVec` had the `drain_filter` method, this loop could be rewritten
|
||||||
// like so:
|
// like so:
|
||||||
//
|
//
|
||||||
// for pat in alternatives.drain_filter(|p| {
|
// for pat in alternatives.drain_filter(|p| {
|
||||||
// // Check if we should extract, but only if `idx >= start`.
|
// // Check if we should extract, but only if `idx >= start`.
|
||||||
// idx += 1;
|
// idx += 1;
|
||||||
|
@ -412,12 +412,12 @@ fn drain_matching(
|
||||||
while i < alternatives.len() {
|
while i < alternatives.len() {
|
||||||
idx += 1;
|
idx += 1;
|
||||||
// Check if we should extract, but only if `idx >= start`.
|
// Check if we should extract, but only if `idx >= start`.
|
||||||
if idx > start && predicate(&alternatives[i].kind) {
|
if idx > start && predicate(&alternatives[i].kind) {
|
||||||
let pat = alternatives.remove(i);
|
let pat = alternatives.remove(i);
|
||||||
tail_or.push(extract(pat.into_inner().kind));
|
tail_or.push(extract(pat.into_inner().kind));
|
||||||
} else {
|
} else {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tail_or
|
tail_or
|
||||||
|
|
|
@ -419,19 +419,19 @@ define_Conf! {
|
||||||
(max_include_file_size: u64 = 1_000_000),
|
(max_include_file_size: u64 = 1_000_000),
|
||||||
/// Lint: EXPECT_USED.
|
/// Lint: EXPECT_USED.
|
||||||
///
|
///
|
||||||
/// Whether `expect` should be allowed within `#[cfg(test)]`
|
/// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
|
||||||
(allow_expect_in_tests: bool = false),
|
(allow_expect_in_tests: bool = false),
|
||||||
/// Lint: UNWRAP_USED.
|
/// Lint: UNWRAP_USED.
|
||||||
///
|
///
|
||||||
/// Whether `unwrap` should be allowed in test cfg
|
/// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
|
||||||
(allow_unwrap_in_tests: bool = false),
|
(allow_unwrap_in_tests: bool = false),
|
||||||
/// Lint: DBG_MACRO.
|
/// Lint: DBG_MACRO.
|
||||||
///
|
///
|
||||||
/// Whether `dbg!` should be allowed in test functions
|
/// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
|
||||||
(allow_dbg_in_tests: bool = false),
|
(allow_dbg_in_tests: bool = false),
|
||||||
/// Lint: PRINT_STDOUT, PRINT_STDERR.
|
/// Lint: PRINT_STDOUT, PRINT_STDERR.
|
||||||
///
|
///
|
||||||
/// Whether print macros (ex. `println!`) should be allowed in test functions
|
/// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
|
||||||
(allow_print_in_tests: bool = false),
|
(allow_print_in_tests: bool = false),
|
||||||
/// Lint: RESULT_LARGE_ERR.
|
/// Lint: RESULT_LARGE_ERR.
|
||||||
///
|
///
|
||||||
|
@ -454,6 +454,11 @@ define_Conf! {
|
||||||
/// configuration will cause restriction lints to trigger even
|
/// configuration will cause restriction lints to trigger even
|
||||||
/// if no suggestion can be made.
|
/// if no suggestion can be made.
|
||||||
(suppress_restriction_lint_in_const: bool = false),
|
(suppress_restriction_lint_in_const: bool = false),
|
||||||
|
/// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS.
|
||||||
|
///
|
||||||
|
/// Whether to **only** check for missing documentation in items visible within the current
|
||||||
|
/// crate. For example, `pub(crate)` items.
|
||||||
|
(missing_docs_in_crate_items: bool = false),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for the configuration file.
|
/// Search for the configuration file.
|
||||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
|
use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
@ -44,7 +44,7 @@ impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct UnnecessaryDefPath {
|
pub struct UnnecessaryDefPath {
|
||||||
array_def_ids: FxHashSet<(DefId, Span)>,
|
array_def_ids: FxIndexSet<(DefId, Span)>,
|
||||||
linted_def_ids: FxHashSet<DefId>,
|
linted_def_ids: FxHashSet<DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -391,11 +391,18 @@ impl FormatString {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut unescaped = String::with_capacity(inner.len());
|
let mut unescaped = String::with_capacity(inner.len());
|
||||||
|
// Sometimes the original string comes from a macro which accepts a malformed string, such as in a
|
||||||
|
// #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the
|
||||||
|
// string from the span will not be possible, so we will just return None here.
|
||||||
|
let mut unparsable = false;
|
||||||
unescape_literal(inner, mode, &mut |_, ch| match ch {
|
unescape_literal(inner, mode, &mut |_, ch| match ch {
|
||||||
Ok(ch) => unescaped.push(ch),
|
Ok(ch) => unescaped.push(ch),
|
||||||
Err(e) if !e.is_fatal() => (),
|
Err(e) if !e.is_fatal() => (),
|
||||||
Err(e) => panic!("{e:?}"),
|
Err(_) => unparsable = true,
|
||||||
});
|
});
|
||||||
|
if unparsable {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let mut parts = Vec::new();
|
let mut parts = Vec::new();
|
||||||
let _: Option<!> = for_each_expr(pieces, |expr| {
|
let _: Option<!> = for_each_expr(pieces, |expr| {
|
||||||
|
|
|
@ -186,7 +186,7 @@ impl<'a> NumericLiteral<'a> {
|
||||||
// The exponent may have a sign, output it early, otherwise it will be
|
// The exponent may have a sign, output it early, otherwise it will be
|
||||||
// treated as a digit
|
// treated as a digit
|
||||||
if digits.clone().next() == Some('-') {
|
if digits.clone().next() == Some('-') {
|
||||||
let _ = digits.next();
|
let _: Option<char> = digits.next();
|
||||||
output.push('-');
|
output.push('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,7 @@ pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
|
||||||
pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
|
pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
|
||||||
pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
|
pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
|
||||||
pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
|
pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
|
||||||
|
pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"];
|
||||||
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
|
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
|
||||||
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
|
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
|
||||||
pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
|
pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc_middle::mir::{FakeReadCause, Mutability};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
|
use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::{Display, Write as _};
|
use std::fmt::{self, Display, Write as _};
|
||||||
use std::ops::{Add, Neg, Not, Sub};
|
use std::ops::{Add, Neg, Not, Sub};
|
||||||
|
|
||||||
/// A helper type to build suggestion correctly handling parentheses.
|
/// A helper type to build suggestion correctly handling parentheses.
|
||||||
|
@ -932,7 +932,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
|
||||||
if cmt.place.projections.is_empty() {
|
if cmt.place.projections.is_empty() {
|
||||||
// handle item without any projection, that needs an explicit borrowing
|
// handle item without any projection, that needs an explicit borrowing
|
||||||
// i.e.: suggest `&x` instead of `x`
|
// i.e.: suggest `&x` instead of `x`
|
||||||
let _ = write!(self.suggestion_start, "{start_snip}&{ident_str}");
|
let _: fmt::Result = write!(self.suggestion_start, "{start_snip}&{ident_str}");
|
||||||
} else {
|
} else {
|
||||||
// cases where a parent `Call` or `MethodCall` is using the item
|
// cases where a parent `Call` or `MethodCall` is using the item
|
||||||
// i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
|
// i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
|
||||||
|
@ -947,7 +947,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
|
||||||
// given expression is the self argument and will be handled completely by the compiler
|
// given expression is the self argument and will be handled completely by the compiler
|
||||||
// i.e.: `|x| x.is_something()`
|
// i.e.: `|x| x.is_something()`
|
||||||
ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
|
ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
|
||||||
let _ = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}");
|
let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}");
|
||||||
self.next_pos = span.hi();
|
self.next_pos = span.hi();
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
@ -1055,7 +1055,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = write!(self.suggestion_start, "{start_snip}{replacement_str}");
|
let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{replacement_str}");
|
||||||
}
|
}
|
||||||
self.next_pos = span.hi();
|
self.next_pos = span.hi();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ use rustc_lint::LateContext;
|
||||||
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
|
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
|
||||||
PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
|
PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||||
VariantDef, VariantDiscr, TypeVisitableExt,
|
TypeVisitor, UintTy, VariantDef, VariantDiscr,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
@ -894,16 +894,29 @@ impl AdtVariantInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the struct or enum variant from the given `Res`
|
/// Gets the struct or enum variant from the given `Res`
|
||||||
pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> {
|
pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<(AdtDef<'tcx>, &'tcx VariantDef)> {
|
||||||
match res {
|
match res {
|
||||||
Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()),
|
Res::Def(DefKind::Struct, id) => {
|
||||||
Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)),
|
let adt = cx.tcx.adt_def(id);
|
||||||
Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()),
|
Some((adt, adt.non_enum_variant()))
|
||||||
|
},
|
||||||
|
Res::Def(DefKind::Variant, id) => {
|
||||||
|
let adt = cx.tcx.adt_def(cx.tcx.parent(id));
|
||||||
|
Some((adt, adt.variant_with_id(id)))
|
||||||
|
},
|
||||||
|
Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => {
|
||||||
|
let adt = cx.tcx.adt_def(cx.tcx.parent(id));
|
||||||
|
Some((adt, adt.non_enum_variant()))
|
||||||
|
},
|
||||||
Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
|
Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
|
||||||
let var_id = cx.tcx.parent(id);
|
let var_id = cx.tcx.parent(id);
|
||||||
Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id))
|
let adt = cx.tcx.adt_def(cx.tcx.parent(var_id));
|
||||||
|
Some((adt, adt.variant_with_id(var_id)))
|
||||||
|
},
|
||||||
|
Res::SelfCtor(id) => {
|
||||||
|
let adt = cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap();
|
||||||
|
Some((adt, adt.non_enum_variant()))
|
||||||
},
|
},
|
||||||
Res::SelfCtor(id) => Some(cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap().non_enum_variant()),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ fn get_clap_config() -> ArgMatches {
|
||||||
.long("markdown")
|
.long("markdown")
|
||||||
.help("Change the reports table to use markdown links"),
|
.help("Change the reports table to use markdown links"),
|
||||||
Arg::new("recursive")
|
Arg::new("recursive")
|
||||||
.long("--recursive")
|
.long("recursive")
|
||||||
.help("Run clippy on the dependencies of crates specified in crates-toml")
|
.help("Run clippy on the dependencies of crates specified in crates-toml")
|
||||||
.conflicts_with("threads")
|
.conflicts_with("threads")
|
||||||
.conflicts_with("fix"),
|
.conflicts_with("fix"),
|
||||||
|
|
|
@ -17,9 +17,9 @@ use crate::recursive::LintcheckServer;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::env::consts::EXE_SUFFIX;
|
use std::env::consts::EXE_SUFFIX;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::{self, Write as _};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::ErrorKind;
|
use std::io::{self, ErrorKind};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
@ -145,8 +145,8 @@ impl ClippyWarning {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output = String::from("| ");
|
let mut output = String::from("| ");
|
||||||
let _ = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
|
let _: fmt::Result = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
|
||||||
let _ = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
|
let _: fmt::Result = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
output
|
output
|
||||||
} else {
|
} else {
|
||||||
|
@ -632,7 +632,7 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let server = config.recursive.then(|| {
|
let server = config.recursive.then(|| {
|
||||||
let _ = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
|
let _: io::Result<()> = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
|
||||||
|
|
||||||
LintcheckServer::spawn(recursive_options)
|
LintcheckServer::spawn(recursive_options)
|
||||||
});
|
});
|
||||||
|
@ -689,7 +689,7 @@ fn main() {
|
||||||
write!(text, "{}", all_msgs.join("")).unwrap();
|
write!(text, "{}", all_msgs.join("")).unwrap();
|
||||||
text.push_str("\n\n### ICEs:\n");
|
text.push_str("\n\n### ICEs:\n");
|
||||||
for (cratename, msg) in &ices {
|
for (cratename, msg) in &ices {
|
||||||
let _ = write!(text, "{cratename}: '{msg}'");
|
let _: fmt::Result = write!(text, "{cratename}: '{msg}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Writing logs to {}", config.lintcheck_results_path.display());
|
println!("Writing logs to {}", config.lintcheck_results_path.display());
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2023-02-10"
|
channel = "nightly-2023-02-25"
|
||||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||||
|
|
|
@ -209,10 +209,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
|
||||||
// Separate the output with an empty line
|
// Separate the output with an empty line
|
||||||
eprintln!();
|
eprintln!();
|
||||||
|
|
||||||
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
|
let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
|
||||||
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
|
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
|
||||||
rustc_errors::ColorConfig::Auto,
|
rustc_errors::ColorConfig::Auto,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
// rustc-env:RUST_BACKTRACE=0
|
// rustc-env:RUST_BACKTRACE=0
|
||||||
// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo"
|
// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo"
|
||||||
// normalize-stderr-test: "internal_lints.rs:\d*:\d*" -> "internal_lints.rs"
|
// normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs"
|
||||||
// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints"
|
// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints"
|
||||||
// normalize-stderr-test: "'rustc'" -> "'<unnamed>'"
|
// normalize-stderr-test: "'rustc'" -> "'<unnamed>'"
|
||||||
|
// normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> ""
|
||||||
|
|
||||||
#![deny(clippy::internal)]
|
#![deny(clippy::internal)]
|
||||||
#![allow(clippy::missing_clippy_version_attribute)]
|
#![allow(clippy::missing_clippy_version_attribute)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs:28:9
|
thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
|
|
||||||
error: internal compiler error: unexpected panic
|
error: internal compiler error: unexpected panic
|
||||||
|
@ -9,5 +9,3 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy
|
||||||
|
|
||||||
note: Clippy version: foo
|
note: Clippy version: foo
|
||||||
|
|
||||||
query stack during panic:
|
|
||||||
end of query stack
|
|
||||||
|
|
|
@ -1,12 +1,3 @@
|
||||||
error: hardcoded path to a diagnostic item
|
|
||||||
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
|
||||||
|
|
|
||||||
LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: convert all references to use `sym::deref_method`
|
|
||||||
= note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
|
|
||||||
|
|
||||||
error: hardcoded path to a diagnostic item
|
error: hardcoded path to a diagnostic item
|
||||||
--> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
|
--> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
|
||||||
|
|
|
|
||||||
|
@ -14,6 +5,7 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: convert all references to use `sym::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
|
error: hardcoded path to a language item
|
||||||
--> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
|
--> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
|
||||||
|
@ -23,5 +15,13 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
|
||||||
|
|
|
|
||||||
= help: convert all references to use `LangItem::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
|
||||||
|
|
|
||||||
|
LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: convert all references to use `sym::deref_method`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,18 @@ fn main() {
|
||||||
expect_result();
|
expect_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_expect_option() {
|
||||||
|
let opt = Some(0);
|
||||||
|
let _ = opt.expect("");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_expect_result() {
|
||||||
|
let res: Result<u8, ()> = Ok(0);
|
||||||
|
let _ = res.expect("");
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod issue9612 {
|
mod issue9612 {
|
||||||
// should not lint in `#[cfg(test)]` modules
|
// should not lint in `#[cfg(test)]` modules
|
||||||
|
|
1
tests/ui-toml/pub_crate_missing_docs/clippy.toml
Normal file
1
tests/ui-toml/pub_crate_missing_docs/clippy.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
missing-docs-in-crate-items = true
|
|
@ -0,0 +1,59 @@
|
||||||
|
//! this is crate
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
#![warn(clippy::missing_docs_in_private_items)]
|
||||||
|
|
||||||
|
/// this is mod
|
||||||
|
mod my_mod {
|
||||||
|
/// some docs
|
||||||
|
fn priv_with_docs() {}
|
||||||
|
fn priv_no_docs() {}
|
||||||
|
/// some docs
|
||||||
|
pub(crate) fn crate_with_docs() {}
|
||||||
|
pub(crate) fn crate_no_docs() {}
|
||||||
|
/// some docs
|
||||||
|
pub(super) fn super_with_docs() {}
|
||||||
|
pub(super) fn super_no_docs() {}
|
||||||
|
|
||||||
|
mod my_sub {
|
||||||
|
/// some docs
|
||||||
|
fn sub_priv_with_docs() {}
|
||||||
|
fn sub_priv_no_docs() {}
|
||||||
|
/// some docs
|
||||||
|
pub(crate) fn sub_crate_with_docs() {}
|
||||||
|
pub(crate) fn sub_crate_no_docs() {}
|
||||||
|
/// some docs
|
||||||
|
pub(super) fn sub_super_with_docs() {}
|
||||||
|
pub(super) fn sub_super_no_docs() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// some docs
|
||||||
|
pub(crate) struct CrateStructWithDocs {
|
||||||
|
/// some docs
|
||||||
|
pub(crate) crate_field_with_docs: (),
|
||||||
|
pub(crate) crate_field_no_docs: (),
|
||||||
|
/// some docs
|
||||||
|
priv_field_with_docs: (),
|
||||||
|
priv_field_no_docs: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct CrateStructNoDocs {
|
||||||
|
/// some docs
|
||||||
|
pub(crate) crate_field_with_docs: (),
|
||||||
|
pub(crate) crate_field_no_docs: (),
|
||||||
|
/// some docs
|
||||||
|
priv_field_with_docs: (),
|
||||||
|
priv_field_no_docs: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// some docs
|
||||||
|
type CrateTypedefWithDocs = String;
|
||||||
|
type CrateTypedefNoDocs = String;
|
||||||
|
/// some docs
|
||||||
|
pub type PubTypedefWithDocs = String;
|
||||||
|
pub type PubTypedefNoDocs = String;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
my_mod::crate_with_docs();
|
||||||
|
my_mod::crate_no_docs();
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
error: missing documentation for a function
|
||||||
|
--> $DIR/pub_crate_missing_doc.rs:12:5
|
||||||
|
|
|
||||||
|
LL | pub(crate) fn crate_no_docs() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: missing documentation for a function
|
||||||
|
--> $DIR/pub_crate_missing_doc.rs:15:5
|
||||||
|
|
|
||||||
|
LL | pub(super) fn super_no_docs() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: missing documentation for a function
|
||||||
|
--> $DIR/pub_crate_missing_doc.rs:23:9
|
||||||
|
|
|
||||||
|
LL | pub(crate) fn sub_crate_no_docs() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: missing documentation for a struct field
|
||||||
|
--> $DIR/pub_crate_missing_doc.rs:33:9
|
||||||
|
|
|
||||||
|
LL | pub(crate) crate_field_no_docs: (),
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: missing documentation for a struct
|
||||||
|
--> $DIR/pub_crate_missing_doc.rs:39:5
|
||||||
|
|
|
||||||
|
LL | / pub(crate) struct CrateStructNoDocs {
|
||||||
|
LL | | /// some docs
|
||||||
|
LL | | pub(crate) crate_field_with_docs: (),
|
||||||
|
LL | | pub(crate) crate_field_no_docs: (),
|
||||||
|
... |
|
||||||
|
LL | | priv_field_no_docs: (),
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: missing documentation for a struct field
|
||||||
|
--> $DIR/pub_crate_missing_doc.rs:42:9
|
||||||
|
|
|
||||||
|
LL | pub(crate) crate_field_no_docs: (),
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: missing documentation for a type alias
|
||||||
|
--> $DIR/pub_crate_missing_doc.rs:51:1
|
||||||
|
|
|
||||||
|
LL | type CrateTypedefNoDocs = String;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
|
@ -33,6 +33,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
|
||||||
max-struct-bools
|
max-struct-bools
|
||||||
max-suggested-slice-pattern-length
|
max-suggested-slice-pattern-length
|
||||||
max-trait-bounds
|
max-trait-bounds
|
||||||
|
missing-docs-in-crate-items
|
||||||
msrv
|
msrv
|
||||||
pass-by-value-size-limit
|
pass-by-value-size-limit
|
||||||
single-char-binding-names-threshold
|
single-char-binding-names-threshold
|
||||||
|
|
|
@ -66,6 +66,12 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
|
||||||
|
let _ = boxed_slice.get(1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod issue9612 {
|
mod issue9612 {
|
||||||
// should not lint in `#[cfg(test)]` modules
|
// should not lint in `#[cfg(test)]` modules
|
||||||
|
|
|
@ -188,10 +188,16 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
|
||||||
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/unwrap_used.rs:84:17
|
--> $DIR/unwrap_used.rs:72:13
|
||||||
|
|
|
||||||
|
LL | let _ = boxed_slice.get(1).unwrap();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
|
||||||
|
|
||||||
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
|
--> $DIR/unwrap_used.rs:90:17
|
||||||
|
|
|
|
||||||
LL | let _ = Box::new([0]).get(1).unwrap();
|
LL | let _ = Box::new([0]).get(1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]`
|
||||||
|
|
||||||
error: aborting due to 27 previous errors
|
error: aborting due to 28 previous errors
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
|
|
||||||
use core::num::{Saturating, Wrapping};
|
use core::num::{Saturating, Wrapping};
|
||||||
|
|
||||||
|
const ONE: i32 = 1;
|
||||||
|
const ZERO: i32 = 0;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Custom;
|
pub struct Custom;
|
||||||
|
|
||||||
|
@ -182,6 +185,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
|
||||||
_n += &0;
|
_n += &0;
|
||||||
_n -= 0;
|
_n -= 0;
|
||||||
_n -= &0;
|
_n -= &0;
|
||||||
|
_n += ZERO;
|
||||||
|
_n += &ZERO;
|
||||||
|
_n -= ZERO;
|
||||||
|
_n -= &ZERO;
|
||||||
_n /= 99;
|
_n /= 99;
|
||||||
_n /= &99;
|
_n /= &99;
|
||||||
_n %= 99;
|
_n %= 99;
|
||||||
|
@ -190,10 +197,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
|
||||||
_n *= &0;
|
_n *= &0;
|
||||||
_n *= 1;
|
_n *= 1;
|
||||||
_n *= &1;
|
_n *= &1;
|
||||||
|
_n *= ZERO;
|
||||||
|
_n *= &ZERO;
|
||||||
|
_n *= ONE;
|
||||||
|
_n *= &ONE;
|
||||||
_n += -0;
|
_n += -0;
|
||||||
_n += &-0;
|
_n += &-0;
|
||||||
_n -= -0;
|
_n -= -0;
|
||||||
_n -= &-0;
|
_n -= &-0;
|
||||||
|
_n += -ZERO;
|
||||||
|
_n += &-ZERO;
|
||||||
|
_n -= -ZERO;
|
||||||
|
_n -= &-ZERO;
|
||||||
_n /= -99;
|
_n /= -99;
|
||||||
_n /= &-99;
|
_n /= &-99;
|
||||||
_n %= -99;
|
_n %= -99;
|
||||||
|
@ -208,10 +223,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
|
||||||
_n = _n + &0;
|
_n = _n + &0;
|
||||||
_n = 0 + _n;
|
_n = 0 + _n;
|
||||||
_n = &0 + _n;
|
_n = &0 + _n;
|
||||||
|
_n = _n + ZERO;
|
||||||
|
_n = _n + &ZERO;
|
||||||
|
_n = ZERO + _n;
|
||||||
|
_n = &ZERO + _n;
|
||||||
_n = _n - 0;
|
_n = _n - 0;
|
||||||
_n = _n - &0;
|
_n = _n - &0;
|
||||||
_n = 0 - _n;
|
_n = 0 - _n;
|
||||||
_n = &0 - _n;
|
_n = &0 - _n;
|
||||||
|
_n = _n - ZERO;
|
||||||
|
_n = _n - &ZERO;
|
||||||
|
_n = ZERO - _n;
|
||||||
|
_n = &ZERO - _n;
|
||||||
_n = _n / 99;
|
_n = _n / 99;
|
||||||
_n = _n / &99;
|
_n = _n / &99;
|
||||||
_n = _n % 99;
|
_n = _n % 99;
|
||||||
|
@ -222,6 +245,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
|
||||||
_n = &0 * _n;
|
_n = &0 * _n;
|
||||||
_n = _n * 1;
|
_n = _n * 1;
|
||||||
_n = _n * &1;
|
_n = _n * &1;
|
||||||
|
_n = ZERO * _n;
|
||||||
|
_n = &ZERO * _n;
|
||||||
|
_n = _n * ONE;
|
||||||
|
_n = _n * &ONE;
|
||||||
_n = 1 * _n;
|
_n = 1 * _n;
|
||||||
_n = &1 * _n;
|
_n = &1 * _n;
|
||||||
_n = 23 + 85;
|
_n = 23 + 85;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:243:5
|
--> $DIR/arithmetic_side_effects.rs:270:5
|
||||||
|
|
|
|
||||||
LL | _n += 1;
|
LL | _n += 1;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
@ -7,589 +7,589 @@ LL | _n += 1;
|
||||||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:244:5
|
--> $DIR/arithmetic_side_effects.rs:271:5
|
||||||
|
|
|
|
||||||
LL | _n += &1;
|
LL | _n += &1;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:245:5
|
--> $DIR/arithmetic_side_effects.rs:272:5
|
||||||
|
|
|
|
||||||
LL | _n -= 1;
|
LL | _n -= 1;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:246:5
|
--> $DIR/arithmetic_side_effects.rs:273:5
|
||||||
|
|
|
|
||||||
LL | _n -= &1;
|
LL | _n -= &1;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:247:5
|
--> $DIR/arithmetic_side_effects.rs:274:5
|
||||||
|
|
|
|
||||||
LL | _n /= 0;
|
LL | _n /= 0;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:248:5
|
--> $DIR/arithmetic_side_effects.rs:275:5
|
||||||
|
|
|
|
||||||
LL | _n /= &0;
|
LL | _n /= &0;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:249:5
|
--> $DIR/arithmetic_side_effects.rs:276:5
|
||||||
|
|
|
|
||||||
LL | _n %= 0;
|
LL | _n %= 0;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:250:5
|
--> $DIR/arithmetic_side_effects.rs:277:5
|
||||||
|
|
|
|
||||||
LL | _n %= &0;
|
LL | _n %= &0;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:251:5
|
--> $DIR/arithmetic_side_effects.rs:278:5
|
||||||
|
|
|
|
||||||
LL | _n *= 2;
|
LL | _n *= 2;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:252:5
|
--> $DIR/arithmetic_side_effects.rs:279:5
|
||||||
|
|
|
|
||||||
LL | _n *= &2;
|
LL | _n *= &2;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:253:5
|
--> $DIR/arithmetic_side_effects.rs:280:5
|
||||||
|
|
|
|
||||||
LL | _n += -1;
|
LL | _n += -1;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:254:5
|
--> $DIR/arithmetic_side_effects.rs:281:5
|
||||||
|
|
|
|
||||||
LL | _n += &-1;
|
LL | _n += &-1;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:255:5
|
--> $DIR/arithmetic_side_effects.rs:282:5
|
||||||
|
|
|
|
||||||
LL | _n -= -1;
|
LL | _n -= -1;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:256:5
|
--> $DIR/arithmetic_side_effects.rs:283:5
|
||||||
|
|
|
|
||||||
LL | _n -= &-1;
|
LL | _n -= &-1;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:257:5
|
--> $DIR/arithmetic_side_effects.rs:284:5
|
||||||
|
|
|
|
||||||
LL | _n /= -0;
|
LL | _n /= -0;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:258:5
|
--> $DIR/arithmetic_side_effects.rs:285:5
|
||||||
|
|
|
|
||||||
LL | _n /= &-0;
|
LL | _n /= &-0;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:259:5
|
--> $DIR/arithmetic_side_effects.rs:286:5
|
||||||
|
|
|
|
||||||
LL | _n %= -0;
|
LL | _n %= -0;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:260:5
|
--> $DIR/arithmetic_side_effects.rs:287:5
|
||||||
|
|
|
|
||||||
LL | _n %= &-0;
|
LL | _n %= &-0;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:261:5
|
--> $DIR/arithmetic_side_effects.rs:288:5
|
||||||
|
|
|
|
||||||
LL | _n *= -2;
|
LL | _n *= -2;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:262:5
|
--> $DIR/arithmetic_side_effects.rs:289:5
|
||||||
|
|
|
|
||||||
LL | _n *= &-2;
|
LL | _n *= &-2;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:263:5
|
--> $DIR/arithmetic_side_effects.rs:290:5
|
||||||
|
|
|
|
||||||
LL | _custom += Custom;
|
LL | _custom += Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:264:5
|
--> $DIR/arithmetic_side_effects.rs:291:5
|
||||||
|
|
|
|
||||||
LL | _custom += &Custom;
|
LL | _custom += &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:265:5
|
--> $DIR/arithmetic_side_effects.rs:292:5
|
||||||
|
|
|
|
||||||
LL | _custom -= Custom;
|
LL | _custom -= Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:266:5
|
--> $DIR/arithmetic_side_effects.rs:293:5
|
||||||
|
|
|
|
||||||
LL | _custom -= &Custom;
|
LL | _custom -= &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:267:5
|
--> $DIR/arithmetic_side_effects.rs:294:5
|
||||||
|
|
|
|
||||||
LL | _custom /= Custom;
|
LL | _custom /= Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:268:5
|
--> $DIR/arithmetic_side_effects.rs:295:5
|
||||||
|
|
|
|
||||||
LL | _custom /= &Custom;
|
LL | _custom /= &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:269:5
|
--> $DIR/arithmetic_side_effects.rs:296:5
|
||||||
|
|
|
|
||||||
LL | _custom %= Custom;
|
LL | _custom %= Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:270:5
|
--> $DIR/arithmetic_side_effects.rs:297:5
|
||||||
|
|
|
|
||||||
LL | _custom %= &Custom;
|
LL | _custom %= &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:271:5
|
--> $DIR/arithmetic_side_effects.rs:298:5
|
||||||
|
|
|
|
||||||
LL | _custom *= Custom;
|
LL | _custom *= Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:272:5
|
--> $DIR/arithmetic_side_effects.rs:299:5
|
||||||
|
|
|
|
||||||
LL | _custom *= &Custom;
|
LL | _custom *= &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:273:5
|
--> $DIR/arithmetic_side_effects.rs:300:5
|
||||||
|
|
|
|
||||||
LL | _custom += -Custom;
|
LL | _custom += -Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:274:5
|
--> $DIR/arithmetic_side_effects.rs:301:5
|
||||||
|
|
|
|
||||||
LL | _custom += &-Custom;
|
LL | _custom += &-Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:275:5
|
--> $DIR/arithmetic_side_effects.rs:302:5
|
||||||
|
|
|
|
||||||
LL | _custom -= -Custom;
|
LL | _custom -= -Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:276:5
|
--> $DIR/arithmetic_side_effects.rs:303:5
|
||||||
|
|
|
|
||||||
LL | _custom -= &-Custom;
|
LL | _custom -= &-Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:277:5
|
--> $DIR/arithmetic_side_effects.rs:304:5
|
||||||
|
|
|
|
||||||
LL | _custom /= -Custom;
|
LL | _custom /= -Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:278:5
|
--> $DIR/arithmetic_side_effects.rs:305:5
|
||||||
|
|
|
|
||||||
LL | _custom /= &-Custom;
|
LL | _custom /= &-Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:279:5
|
--> $DIR/arithmetic_side_effects.rs:306:5
|
||||||
|
|
|
|
||||||
LL | _custom %= -Custom;
|
LL | _custom %= -Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:280:5
|
--> $DIR/arithmetic_side_effects.rs:307:5
|
||||||
|
|
|
|
||||||
LL | _custom %= &-Custom;
|
LL | _custom %= &-Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:281:5
|
--> $DIR/arithmetic_side_effects.rs:308:5
|
||||||
|
|
|
|
||||||
LL | _custom *= -Custom;
|
LL | _custom *= -Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:282:5
|
--> $DIR/arithmetic_side_effects.rs:309:5
|
||||||
|
|
|
|
||||||
LL | _custom *= &-Custom;
|
LL | _custom *= &-Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:285:10
|
--> $DIR/arithmetic_side_effects.rs:312:10
|
||||||
|
|
|
|
||||||
LL | _n = _n + 1;
|
LL | _n = _n + 1;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:286:10
|
--> $DIR/arithmetic_side_effects.rs:313:10
|
||||||
|
|
|
|
||||||
LL | _n = _n + &1;
|
LL | _n = _n + &1;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:287:10
|
--> $DIR/arithmetic_side_effects.rs:314:10
|
||||||
|
|
|
|
||||||
LL | _n = 1 + _n;
|
LL | _n = 1 + _n;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:288:10
|
--> $DIR/arithmetic_side_effects.rs:315:10
|
||||||
|
|
|
|
||||||
LL | _n = &1 + _n;
|
LL | _n = &1 + _n;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:289:10
|
--> $DIR/arithmetic_side_effects.rs:316:10
|
||||||
|
|
|
|
||||||
LL | _n = _n - 1;
|
LL | _n = _n - 1;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:290:10
|
--> $DIR/arithmetic_side_effects.rs:317:10
|
||||||
|
|
|
|
||||||
LL | _n = _n - &1;
|
LL | _n = _n - &1;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:291:10
|
--> $DIR/arithmetic_side_effects.rs:318:10
|
||||||
|
|
|
|
||||||
LL | _n = 1 - _n;
|
LL | _n = 1 - _n;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:292:10
|
--> $DIR/arithmetic_side_effects.rs:319:10
|
||||||
|
|
|
|
||||||
LL | _n = &1 - _n;
|
LL | _n = &1 - _n;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:293:10
|
--> $DIR/arithmetic_side_effects.rs:320:10
|
||||||
|
|
|
|
||||||
LL | _n = _n / 0;
|
LL | _n = _n / 0;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:294:10
|
--> $DIR/arithmetic_side_effects.rs:321:10
|
||||||
|
|
|
|
||||||
LL | _n = _n / &0;
|
LL | _n = _n / &0;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:295:10
|
--> $DIR/arithmetic_side_effects.rs:322:10
|
||||||
|
|
|
|
||||||
LL | _n = _n % 0;
|
LL | _n = _n % 0;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:296:10
|
--> $DIR/arithmetic_side_effects.rs:323:10
|
||||||
|
|
|
|
||||||
LL | _n = _n % &0;
|
LL | _n = _n % &0;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:297:10
|
--> $DIR/arithmetic_side_effects.rs:324:10
|
||||||
|
|
|
|
||||||
LL | _n = _n * 2;
|
LL | _n = _n * 2;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:298:10
|
--> $DIR/arithmetic_side_effects.rs:325:10
|
||||||
|
|
|
|
||||||
LL | _n = _n * &2;
|
LL | _n = _n * &2;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:299:10
|
--> $DIR/arithmetic_side_effects.rs:326:10
|
||||||
|
|
|
|
||||||
LL | _n = 2 * _n;
|
LL | _n = 2 * _n;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:300:10
|
--> $DIR/arithmetic_side_effects.rs:327:10
|
||||||
|
|
|
|
||||||
LL | _n = &2 * _n;
|
LL | _n = &2 * _n;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:301:10
|
--> $DIR/arithmetic_side_effects.rs:328:10
|
||||||
|
|
|
|
||||||
LL | _n = 23 + &85;
|
LL | _n = 23 + &85;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:302:10
|
--> $DIR/arithmetic_side_effects.rs:329:10
|
||||||
|
|
|
|
||||||
LL | _n = &23 + 85;
|
LL | _n = &23 + 85;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:303:10
|
--> $DIR/arithmetic_side_effects.rs:330:10
|
||||||
|
|
|
|
||||||
LL | _n = &23 + &85;
|
LL | _n = &23 + &85;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:304:15
|
--> $DIR/arithmetic_side_effects.rs:331:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom + _custom;
|
LL | _custom = _custom + _custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:305:15
|
--> $DIR/arithmetic_side_effects.rs:332:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom + &_custom;
|
LL | _custom = _custom + &_custom;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:306:15
|
--> $DIR/arithmetic_side_effects.rs:333:15
|
||||||
|
|
|
|
||||||
LL | _custom = Custom + _custom;
|
LL | _custom = Custom + _custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:307:15
|
--> $DIR/arithmetic_side_effects.rs:334:15
|
||||||
|
|
|
|
||||||
LL | _custom = &Custom + _custom;
|
LL | _custom = &Custom + _custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:308:15
|
--> $DIR/arithmetic_side_effects.rs:335:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom - Custom;
|
LL | _custom = _custom - Custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:309:15
|
--> $DIR/arithmetic_side_effects.rs:336:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom - &Custom;
|
LL | _custom = _custom - &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:310:15
|
--> $DIR/arithmetic_side_effects.rs:337:15
|
||||||
|
|
|
|
||||||
LL | _custom = Custom - _custom;
|
LL | _custom = Custom - _custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:311:15
|
--> $DIR/arithmetic_side_effects.rs:338:15
|
||||||
|
|
|
|
||||||
LL | _custom = &Custom - _custom;
|
LL | _custom = &Custom - _custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:312:15
|
--> $DIR/arithmetic_side_effects.rs:339:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom / Custom;
|
LL | _custom = _custom / Custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:313:15
|
--> $DIR/arithmetic_side_effects.rs:340:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom / &Custom;
|
LL | _custom = _custom / &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:314:15
|
--> $DIR/arithmetic_side_effects.rs:341:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom % Custom;
|
LL | _custom = _custom % Custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:315:15
|
--> $DIR/arithmetic_side_effects.rs:342:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom % &Custom;
|
LL | _custom = _custom % &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:316:15
|
--> $DIR/arithmetic_side_effects.rs:343:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom * Custom;
|
LL | _custom = _custom * Custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:317:15
|
--> $DIR/arithmetic_side_effects.rs:344:15
|
||||||
|
|
|
|
||||||
LL | _custom = _custom * &Custom;
|
LL | _custom = _custom * &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:318:15
|
--> $DIR/arithmetic_side_effects.rs:345:15
|
||||||
|
|
|
|
||||||
LL | _custom = Custom * _custom;
|
LL | _custom = Custom * _custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:319:15
|
--> $DIR/arithmetic_side_effects.rs:346:15
|
||||||
|
|
|
|
||||||
LL | _custom = &Custom * _custom;
|
LL | _custom = &Custom * _custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:320:15
|
--> $DIR/arithmetic_side_effects.rs:347:15
|
||||||
|
|
|
|
||||||
LL | _custom = Custom + &Custom;
|
LL | _custom = Custom + &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:321:15
|
--> $DIR/arithmetic_side_effects.rs:348:15
|
||||||
|
|
|
|
||||||
LL | _custom = &Custom + Custom;
|
LL | _custom = &Custom + Custom;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:322:15
|
--> $DIR/arithmetic_side_effects.rs:349:15
|
||||||
|
|
|
|
||||||
LL | _custom = &Custom + &Custom;
|
LL | _custom = &Custom + &Custom;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:325:10
|
--> $DIR/arithmetic_side_effects.rs:352:10
|
||||||
|
|
|
|
||||||
LL | _n = -_n;
|
LL | _n = -_n;
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:326:10
|
--> $DIR/arithmetic_side_effects.rs:353:10
|
||||||
|
|
|
|
||||||
LL | _n = -&_n;
|
LL | _n = -&_n;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:327:15
|
--> $DIR/arithmetic_side_effects.rs:354:15
|
||||||
|
|
|
|
||||||
LL | _custom = -_custom;
|
LL | _custom = -_custom;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:328:15
|
--> $DIR/arithmetic_side_effects.rs:355:15
|
||||||
|
|
|
|
||||||
LL | _custom = -&_custom;
|
LL | _custom = -&_custom;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:337:5
|
--> $DIR/arithmetic_side_effects.rs:364:5
|
||||||
|
|
|
|
||||||
LL | 1 + i;
|
LL | 1 + i;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:338:5
|
--> $DIR/arithmetic_side_effects.rs:365:5
|
||||||
|
|
|
|
||||||
LL | i * 2;
|
LL | i * 2;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:340:5
|
--> $DIR/arithmetic_side_effects.rs:367:5
|
||||||
|
|
|
|
||||||
LL | i - 2 + 2 - i;
|
LL | i - 2 + 2 - i;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:341:5
|
--> $DIR/arithmetic_side_effects.rs:368:5
|
||||||
|
|
|
|
||||||
LL | -i;
|
LL | -i;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:342:5
|
--> $DIR/arithmetic_side_effects.rs:369:5
|
||||||
|
|
|
|
||||||
LL | i >> 1;
|
LL | i >> 1;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:343:5
|
--> $DIR/arithmetic_side_effects.rs:370:5
|
||||||
|
|
|
|
||||||
LL | i << 1;
|
LL | i << 1;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:352:5
|
--> $DIR/arithmetic_side_effects.rs:379:5
|
||||||
|
|
|
|
||||||
LL | i += 1;
|
LL | i += 1;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:353:5
|
--> $DIR/arithmetic_side_effects.rs:380:5
|
||||||
|
|
|
|
||||||
LL | i -= 1;
|
LL | i -= 1;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:354:5
|
--> $DIR/arithmetic_side_effects.rs:381:5
|
||||||
|
|
|
|
||||||
LL | i *= 2;
|
LL | i *= 2;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:356:5
|
--> $DIR/arithmetic_side_effects.rs:383:5
|
||||||
|
|
|
|
||||||
LL | i /= 0;
|
LL | i /= 0;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:358:5
|
--> $DIR/arithmetic_side_effects.rs:385:5
|
||||||
|
|
|
|
||||||
LL | i /= var1;
|
LL | i /= var1;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:359:5
|
--> $DIR/arithmetic_side_effects.rs:386:5
|
||||||
|
|
|
|
||||||
LL | i /= var2;
|
LL | i /= var2;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:361:5
|
--> $DIR/arithmetic_side_effects.rs:388:5
|
||||||
|
|
|
|
||||||
LL | i %= 0;
|
LL | i %= 0;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:363:5
|
--> $DIR/arithmetic_side_effects.rs:390:5
|
||||||
|
|
|
|
||||||
LL | i %= var1;
|
LL | i %= var1;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:364:5
|
--> $DIR/arithmetic_side_effects.rs:391:5
|
||||||
|
|
|
|
||||||
LL | i %= var2;
|
LL | i %= var2;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:365:5
|
--> $DIR/arithmetic_side_effects.rs:392:5
|
||||||
|
|
|
|
||||||
LL | i <<= 3;
|
LL | i <<= 3;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||||
--> $DIR/arithmetic_side_effects.rs:366:5
|
--> $DIR/arithmetic_side_effects.rs:393:5
|
||||||
|
|
|
|
||||||
LL | i >>= 2;
|
LL | i >>= 2;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
@ -33,6 +33,7 @@ fn main() {
|
||||||
let _vec4: Box<_> = Box::<Vec<bool>>::default();
|
let _vec4: Box<_> = Box::<Vec<bool>>::default();
|
||||||
let _more = ret_ty_fn();
|
let _more = ret_ty_fn();
|
||||||
call_ty_fn(Box::default());
|
call_ty_fn(Box::default());
|
||||||
|
issue_10381();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ret_ty_fn() -> Box<bool> {
|
fn ret_ty_fn() -> Box<bool> {
|
||||||
|
@ -65,3 +66,20 @@ fn issue_10089() {
|
||||||
let _ = Box::<WeirdPathed>::default();
|
let _ = Box::<WeirdPathed>::default();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn issue_10381() {
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Foo {}
|
||||||
|
pub trait Bar {}
|
||||||
|
impl Bar for Foo {}
|
||||||
|
|
||||||
|
fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
Some(Box::<Foo>::default())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(maybe_get_bar(2).is_some());
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ fn main() {
|
||||||
let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
|
let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
|
||||||
let _more = ret_ty_fn();
|
let _more = ret_ty_fn();
|
||||||
call_ty_fn(Box::new(u8::default()));
|
call_ty_fn(Box::new(u8::default()));
|
||||||
|
issue_10381();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ret_ty_fn() -> Box<bool> {
|
fn ret_ty_fn() -> Box<bool> {
|
||||||
|
@ -65,3 +66,20 @@ fn issue_10089() {
|
||||||
let _ = Box::new(WeirdPathed::default());
|
let _ = Box::new(WeirdPathed::default());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn issue_10381() {
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Foo {}
|
||||||
|
pub trait Bar {}
|
||||||
|
impl Bar for Foo {}
|
||||||
|
|
||||||
|
fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
Some(Box::new(Foo::default()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(maybe_get_bar(2).is_some());
|
||||||
|
}
|
||||||
|
|
|
@ -73,22 +73,28 @@ LL | call_ty_fn(Box::new(u8::default()));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
|
||||||
|
|
||||||
error: `Box::new(_)` of default value
|
error: `Box::new(_)` of default value
|
||||||
--> $DIR/box_default.rs:39:5
|
--> $DIR/box_default.rs:40:5
|
||||||
|
|
|
|
||||||
LL | Box::new(bool::default())
|
LL | Box::new(bool::default())
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
|
||||||
|
|
||||||
error: `Box::new(_)` of default value
|
error: `Box::new(_)` of default value
|
||||||
--> $DIR/box_default.rs:56:28
|
--> $DIR/box_default.rs:57:28
|
||||||
|
|
|
|
||||||
LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
|
LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
|
||||||
|
|
||||||
error: `Box::new(_)` of default value
|
error: `Box::new(_)` of default value
|
||||||
--> $DIR/box_default.rs:65:17
|
--> $DIR/box_default.rs:66:17
|
||||||
|
|
|
|
||||||
LL | let _ = Box::new(WeirdPathed::default());
|
LL | let _ = Box::new(WeirdPathed::default());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
|
||||||
|
|
||||||
error: aborting due to 15 previous errors
|
error: `Box::new(_)` of default value
|
||||||
|
--> $DIR/box_default.rs:78:18
|
||||||
|
|
|
||||||
|
LL | Some(Box::new(Foo::default()))
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
|
||||||
|
|
||||||
|
error: aborting due to 16 previous errors
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let s = String::from("String");
|
let s = String::from("String");
|
||||||
let _ = s.as_bytes().get(3);
|
let _ = s.as_bytes().get(3).copied();
|
||||||
let _ = &s.as_bytes().get(3);
|
let _ = &s.as_bytes()[3];
|
||||||
let _ = s[..].as_bytes().get(3);
|
let _ = s[..].as_bytes().get(3).copied();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let s = String::from("String");
|
let s = String::from("String");
|
||||||
let _ = s.bytes().nth(3);
|
let _ = s.bytes().nth(3);
|
||||||
let _ = &s.bytes().nth(3);
|
let _ = &s.bytes().nth(3).unwrap();
|
||||||
let _ = s[..].bytes().nth(3);
|
let _ = s[..].bytes().nth(3);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,21 @@ error: called `.bytes().nth()` on a `String`
|
||||||
--> $DIR/bytes_nth.rs:8:13
|
--> $DIR/bytes_nth.rs:8:13
|
||||||
|
|
|
|
||||||
LL | let _ = s.bytes().nth(3);
|
LL | let _ = s.bytes().nth(3);
|
||||||
| ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
|
| ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3).copied()`
|
||||||
|
|
|
|
||||||
= note: `-D clippy::bytes-nth` implied by `-D warnings`
|
= note: `-D clippy::bytes-nth` implied by `-D warnings`
|
||||||
|
|
||||||
error: called `.bytes().nth()` on a `String`
|
error: called `.bytes().nth().unwrap()` on a `String`
|
||||||
--> $DIR/bytes_nth.rs:9:14
|
--> $DIR/bytes_nth.rs:9:14
|
||||||
|
|
|
|
||||||
LL | let _ = &s.bytes().nth(3);
|
LL | let _ = &s.bytes().nth(3).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.as_bytes()[3]`
|
||||||
|
|
||||||
error: called `.bytes().nth()` on a `str`
|
error: called `.bytes().nth()` on a `str`
|
||||||
--> $DIR/bytes_nth.rs:10:13
|
--> $DIR/bytes_nth.rs:10:13
|
||||||
|
|
|
|
||||||
LL | let _ = s[..].bytes().nth(3);
|
LL | let _ = s[..].bytes().nth(3);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)`
|
| ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3).copied()`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ error: casting `f32` to `i32` may truncate the value
|
||||||
LL | 1f32 as i32;
|
LL | 1f32 as i32;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
|
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
|
@ -55,7 +55,7 @@ error: casting `f32` to `u32` may truncate the value
|
||||||
LL | 1f32 as u32;
|
LL | 1f32 as u32;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | u32::try_from(1f32);
|
LL | u32::try_from(1f32);
|
||||||
|
@ -75,7 +75,7 @@ error: casting `f64` to `f32` may truncate the value
|
||||||
LL | 1f64 as f32;
|
LL | 1f64 as f32;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | f32::try_from(1f64);
|
LL | f32::try_from(1f64);
|
||||||
|
@ -87,7 +87,7 @@ error: casting `i32` to `i8` may truncate the value
|
||||||
LL | 1i32 as i8;
|
LL | 1i32 as i8;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | i8::try_from(1i32);
|
LL | i8::try_from(1i32);
|
||||||
|
@ -99,7 +99,7 @@ error: casting `i32` to `u8` may truncate the value
|
||||||
LL | 1i32 as u8;
|
LL | 1i32 as u8;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | u8::try_from(1i32);
|
LL | u8::try_from(1i32);
|
||||||
|
@ -111,7 +111,7 @@ error: casting `f64` to `isize` may truncate the value
|
||||||
LL | 1f64 as isize;
|
LL | 1f64 as isize;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | isize::try_from(1f64);
|
LL | isize::try_from(1f64);
|
||||||
|
@ -123,7 +123,7 @@ error: casting `f64` to `usize` may truncate the value
|
||||||
LL | 1f64 as usize;
|
LL | 1f64 as usize;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | usize::try_from(1f64);
|
LL | usize::try_from(1f64);
|
||||||
|
@ -141,7 +141,7 @@ error: casting `u32` to `u16` may truncate the value
|
||||||
LL | 1f32 as u32 as u16;
|
LL | 1f32 as u32 as u16;
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | u16::try_from(1f32 as u32);
|
LL | u16::try_from(1f32 as u32);
|
||||||
|
@ -153,7 +153,7 @@ error: casting `f32` to `u32` may truncate the value
|
||||||
LL | 1f32 as u32 as u16;
|
LL | 1f32 as u32 as u16;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | u32::try_from(1f32) as u16;
|
LL | u32::try_from(1f32) as u16;
|
||||||
|
@ -215,7 +215,7 @@ error: casting `i64` to `i8` may truncate the value
|
||||||
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
|
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: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | i8::try_from((-99999999999i64).min(1)); // should be linted because signed
|
LL | i8::try_from((-99999999999i64).min(1)); // should be linted because signed
|
||||||
|
@ -227,7 +227,7 @@ error: casting `u64` to `u8` may truncate the value
|
||||||
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
|
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: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted
|
LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted
|
||||||
|
@ -239,7 +239,7 @@ error: casting `main::E2` to `u8` may truncate the value
|
||||||
LL | let _ = self as u8;
|
LL | let _ = self as u8;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | let _ = u8::try_from(self);
|
LL | let _ = u8::try_from(self);
|
||||||
|
@ -259,7 +259,7 @@ error: casting `main::E5` to `i8` may truncate the value
|
||||||
LL | let _ = self as i8;
|
LL | let _ = self as i8;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | let _ = i8::try_from(self);
|
LL | let _ = i8::try_from(self);
|
||||||
|
@ -277,7 +277,7 @@ error: casting `main::E6` to `i16` may truncate the value
|
||||||
LL | let _ = self as i16;
|
LL | let _ = self as i16;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | let _ = i16::try_from(self);
|
LL | let _ = i16::try_from(self);
|
||||||
|
@ -289,7 +289,7 @@ error: casting `main::E7` to `usize` may truncate the value on targets with 32-b
|
||||||
LL | let _ = self as usize;
|
LL | let _ = self as usize;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | let _ = usize::try_from(self);
|
LL | let _ = usize::try_from(self);
|
||||||
|
@ -301,7 +301,7 @@ error: casting `main::E10` to `u16` may truncate the value
|
||||||
LL | let _ = self as u16;
|
LL | let _ = self as u16;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | let _ = u16::try_from(self);
|
LL | let _ = u16::try_from(self);
|
||||||
|
@ -313,7 +313,7 @@ error: casting `u32` to `u8` may truncate the value
|
||||||
LL | let c = (q >> 16) as u8;
|
LL | let c = (q >> 16) as u8;
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | let c = u8::try_from((q >> 16));
|
LL | let c = u8::try_from((q >> 16));
|
||||||
|
@ -325,7 +325,7 @@ error: casting `u32` to `u8` may truncate the value
|
||||||
LL | let c = (q / 1000) as u8;
|
LL | let c = (q / 1000) as u8;
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | let c = u8::try_from((q / 1000));
|
LL | let c = u8::try_from((q / 1000));
|
||||||
|
|
|
@ -4,7 +4,7 @@ error: casting `isize` to `i8` may truncate the value
|
||||||
LL | 1isize as i8;
|
LL | 1isize as i8;
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
|
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
|
@ -43,7 +43,7 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi
|
||||||
LL | 1isize as i32;
|
LL | 1isize as i32;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | i32::try_from(1isize);
|
LL | i32::try_from(1isize);
|
||||||
|
@ -55,7 +55,7 @@ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wi
|
||||||
LL | 1isize as u32;
|
LL | 1isize as u32;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | u32::try_from(1isize);
|
LL | u32::try_from(1isize);
|
||||||
|
@ -67,7 +67,7 @@ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wi
|
||||||
LL | 1usize as u32;
|
LL | 1usize as u32;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | u32::try_from(1usize);
|
LL | u32::try_from(1usize);
|
||||||
|
@ -79,7 +79,7 @@ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wi
|
||||||
LL | 1usize as i32;
|
LL | 1usize as i32;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | i32::try_from(1usize);
|
LL | i32::try_from(1usize);
|
||||||
|
@ -99,7 +99,7 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi
|
||||||
LL | 1i64 as isize;
|
LL | 1i64 as isize;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | isize::try_from(1i64);
|
LL | isize::try_from(1i64);
|
||||||
|
@ -111,7 +111,7 @@ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wi
|
||||||
LL | 1i64 as usize;
|
LL | 1i64 as usize;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | usize::try_from(1i64);
|
LL | usize::try_from(1i64);
|
||||||
|
@ -123,7 +123,7 @@ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wi
|
||||||
LL | 1u64 as isize;
|
LL | 1u64 as isize;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | isize::try_from(1u64);
|
LL | isize::try_from(1u64);
|
||||||
|
@ -141,7 +141,7 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi
|
||||||
LL | 1u64 as usize;
|
LL | 1u64 as usize;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
|
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
|
||||||
help: ... or use `try_from` and handle the error accordingly
|
help: ... or use `try_from` and handle the error accordingly
|
||||||
|
|
|
|
||||||
LL | usize::try_from(1u64);
|
LL | usize::try_from(1u64);
|
||||||
|
|
9
tests/ui/crashes/needless_pass_by_value-w-late-bound.rs
Normal file
9
tests/ui/crashes/needless_pass_by_value-w-late-bound.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// https://github.com/rust-lang/rust/issues/107147
|
||||||
|
|
||||||
|
#![warn(clippy::needless_pass_by_value)]
|
||||||
|
|
||||||
|
struct Foo<'a>(&'a [(); 100]);
|
||||||
|
|
||||||
|
fn test(x: Foo<'_>) {}
|
||||||
|
|
||||||
|
fn main() {}
|
15
tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr
Normal file
15
tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error: this argument is passed by value, but not consumed in the function body
|
||||||
|
--> $DIR/needless_pass_by_value-w-late-bound.rs:7:12
|
||||||
|
|
|
||||||
|
LL | fn test(x: Foo<'_>) {}
|
||||||
|
| ^^^^^^^ help: consider taking a reference instead: `&Foo<'_>`
|
||||||
|
|
|
||||||
|
help: consider marking this type as `Copy`
|
||||||
|
--> $DIR/needless_pass_by_value-w-late-bound.rs:5:1
|
||||||
|
|
|
||||||
|
LL | struct Foo<'a>(&'a [(); 100]);
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
= note: `-D clippy::needless-pass-by-value` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -78,7 +78,7 @@ fn test_allowed() {
|
||||||
/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
|
/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
|
||||||
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
|
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
|
||||||
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
|
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
|
||||||
/// It can also be [`inline_link2`].
|
/// It can also be [inline_link2]. A link to [StackOverflow](https://stackoverflow.com) is also acceptable.
|
||||||
///
|
///
|
||||||
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
|
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
|
||||||
/// [inline_link]: https://foobar
|
/// [inline_link]: https://foobar
|
||||||
|
|
|
@ -75,10 +75,10 @@ fn test_units() {
|
||||||
fn test_allowed() {
|
fn test_allowed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
|
/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
|
||||||
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
|
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
|
||||||
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
|
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
|
||||||
/// It can also be [inline_link2].
|
/// It can also be [inline_link2]. A link to [StackOverflow](https://stackoverflow.com) is also acceptable.
|
||||||
///
|
///
|
||||||
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
|
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
|
||||||
/// [inline_link]: https://foobar
|
/// [inline_link]: https://foobar
|
||||||
|
|
|
@ -142,28 +142,6 @@ help: try
|
||||||
LL | /// `be_sure_we_got_to_the_end_of_it`
|
LL | /// `be_sure_we_got_to_the_end_of_it`
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: item in documentation is missing backticks
|
|
||||||
--> $DIR/doc-fixable.rs:78:22
|
|
||||||
|
|
|
||||||
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
help: try
|
|
||||||
|
|
|
||||||
LL | /// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
|
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
error: item in documentation is missing backticks
|
|
||||||
--> $DIR/doc-fixable.rs:81:21
|
|
||||||
|
|
|
||||||
LL | /// It can also be [inline_link2].
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
help: try
|
|
||||||
|
|
|
||||||
LL | /// It can also be [`inline_link2`].
|
|
||||||
| ~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
error: item in documentation is missing backticks
|
error: item in documentation is missing backticks
|
||||||
--> $DIR/doc-fixable.rs:91:5
|
--> $DIR/doc-fixable.rs:91:5
|
||||||
|
|
|
|
||||||
|
@ -329,5 +307,5 @@ help: try
|
||||||
LL | /// An iterator over `mycrate::Collection`'s values.
|
LL | /// An iterator over `mycrate::Collection`'s values.
|
||||||
| ~~~~~~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 30 previous errors
|
error: aborting due to 28 previous errors
|
||||||
|
|
||||||
|
|
|
@ -152,4 +152,18 @@ fn hash_map<K: Eq + Hash + Copy, V: Copy>(m: &mut HashMap<K, V>, m2: &mut HashMa
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue 10331
|
||||||
|
// do not suggest a bad expansion because the compiler unrolls the first
|
||||||
|
// occurrence of the loop
|
||||||
|
pub fn issue_10331() {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
let mut i = 0;
|
||||||
|
let mut x = 0;
|
||||||
|
while !m.contains_key(&x) {
|
||||||
|
m.insert(x, i);
|
||||||
|
i += 1;
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -156,4 +156,18 @@ fn hash_map<K: Eq + Hash + Copy, V: Copy>(m: &mut HashMap<K, V>, m2: &mut HashMa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue 10331
|
||||||
|
// do not suggest a bad expansion because the compiler unrolls the first
|
||||||
|
// occurrence of the loop
|
||||||
|
pub fn issue_10331() {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
let mut i = 0;
|
||||||
|
let mut x = 0;
|
||||||
|
while !m.contains_key(&x) {
|
||||||
|
m.insert(x, i);
|
||||||
|
i += 1;
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -269,6 +269,9 @@ fn main() {
|
||||||
|
|
||||||
trait WithAssoc {
|
trait WithAssoc {
|
||||||
type Assoc: ?Sized;
|
type Assoc: ?Sized;
|
||||||
|
fn to_assoc(&self) -> &Self::Assoc {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl WithAssoc for String {
|
impl WithAssoc for String {
|
||||||
type Assoc = str;
|
type Assoc = str;
|
||||||
|
@ -281,4 +284,15 @@ fn main() {
|
||||||
// Issue #9901
|
// Issue #9901
|
||||||
fn takes_ref(_: &i32) {}
|
fn takes_ref(_: &i32) {}
|
||||||
takes_ref(*Box::new(&0i32));
|
takes_ref(*Box::new(&0i32));
|
||||||
|
|
||||||
|
// Issue #10384
|
||||||
|
impl<'a> WithAssoc for &'a u32 {
|
||||||
|
type Assoc = dyn core::fmt::Display;
|
||||||
|
fn to_assoc(&self) -> &Self::Assoc {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
|
||||||
|
*x
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,6 +269,9 @@ fn main() {
|
||||||
|
|
||||||
trait WithAssoc {
|
trait WithAssoc {
|
||||||
type Assoc: ?Sized;
|
type Assoc: ?Sized;
|
||||||
|
fn to_assoc(&self) -> &Self::Assoc {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl WithAssoc for String {
|
impl WithAssoc for String {
|
||||||
type Assoc = str;
|
type Assoc = str;
|
||||||
|
@ -281,4 +284,15 @@ fn main() {
|
||||||
// Issue #9901
|
// Issue #9901
|
||||||
fn takes_ref(_: &i32) {}
|
fn takes_ref(_: &i32) {}
|
||||||
takes_ref(*Box::new(&0i32));
|
takes_ref(*Box::new(&0i32));
|
||||||
|
|
||||||
|
// Issue #10384
|
||||||
|
impl<'a> WithAssoc for &'a u32 {
|
||||||
|
type Assoc = dyn core::fmt::Display;
|
||||||
|
fn to_assoc(&self) -> &Self::Assoc {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
|
||||||
|
*x
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
#![allow(unused, clippy::needless_lifetimes)]
|
#![allow(unused, clippy::needless_lifetimes)]
|
||||||
#![warn(clippy::extra_unused_type_parameters)]
|
#![warn(clippy::extra_unused_type_parameters)]
|
||||||
|
|
||||||
fn unused_ty<T>(x: u8) {}
|
fn unused_ty<T>(x: u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn unused_multi<T, U>(x: u8) {}
|
fn unused_multi<T, U>(x: u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn unused_with_lt<'a, T>(x: &'a u8) {}
|
fn unused_with_lt<'a, T>(x: &'a u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn used_ty<T>(x: T, y: u8) {}
|
fn used_ty<T>(x: T, y: u8) {}
|
||||||
|
|
||||||
|
@ -15,15 +21,20 @@ fn used_ret<T: Default>(x: u8) -> T {
|
||||||
T::default()
|
T::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unused_bounded<T: Default, U>(x: U) {}
|
fn unused_bounded<T: Default, U>(x: U) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn unused_where_clause<T, U>(x: U)
|
fn unused_where_clause<T, U>(x: U)
|
||||||
where
|
where
|
||||||
T: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
|
fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
|
fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
|
||||||
iter.count()
|
iter.count()
|
||||||
|
@ -46,7 +57,9 @@ fn used_closure<T: Default + ToString>() -> impl Fn() {
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
impl S {
|
impl S {
|
||||||
fn unused_ty_impl<T>(&self) {}
|
fn unused_ty_impl<T>(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't lint on trait methods
|
// Don't lint on trait methods
|
||||||
|
@ -66,4 +79,32 @@ where
|
||||||
.filter_map(move |(i, a)| if i == index { None } else { Some(a) })
|
.filter_map(move |(i, a)| if i == index { None } else { Some(a) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unused_opaque<A, B>(dummy: impl Default) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
mod unexported_trait_bounds {
|
||||||
|
mod private {
|
||||||
|
pub trait Private {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn priv_trait_bound<T: private::Private>() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unused_with_priv_trait_bound<T: private::Private, U>() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod issue10319 {
|
||||||
|
fn assert_send<T: Send>() {}
|
||||||
|
|
||||||
|
fn assert_send_where<T>()
|
||||||
|
where
|
||||||
|
T: Send,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:4:13
|
--> $DIR/extra_unused_type_parameters.rs:4:13
|
||||||
|
|
|
|
||||||
LL | fn unused_ty<T>(x: u8) {}
|
LL | fn unused_ty<T>(x: u8) {
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= help: consider removing the parameter
|
= help: consider removing the parameter
|
||||||
= note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
|
= note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
|
||||||
|
|
||||||
error: type parameters go unused in function definition
|
error: type parameters go unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:6:16
|
--> $DIR/extra_unused_type_parameters.rs:8:16
|
||||||
|
|
|
|
||||||
LL | fn unused_multi<T, U>(x: u8) {}
|
LL | fn unused_multi<T, U>(x: u8) {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider removing the parameters
|
= help: consider removing the parameters
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:8:23
|
--> $DIR/extra_unused_type_parameters.rs:12:23
|
||||||
|
|
|
|
||||||
LL | fn unused_with_lt<'a, T>(x: &'a u8) {}
|
LL | fn unused_with_lt<'a, T>(x: &'a u8) {
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= help: consider removing the parameter
|
= help: consider removing the parameter
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:18:19
|
--> $DIR/extra_unused_type_parameters.rs:24:19
|
||||||
|
|
|
|
||||||
LL | fn unused_bounded<T: Default, U>(x: U) {}
|
LL | fn unused_bounded<T: Default, U>(x: U) {
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: consider removing the parameter
|
= help: consider removing the parameter
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:20:24
|
--> $DIR/extra_unused_type_parameters.rs:28:24
|
||||||
|
|
|
|
||||||
LL | fn unused_where_clause<T, U>(x: U)
|
LL | fn unused_where_clause<T, U>(x: U)
|
||||||
| ^^
|
| ^^
|
||||||
|
@ -40,20 +40,36 @@ LL | fn unused_where_clause<T, U>(x: U)
|
||||||
= help: consider removing the parameter
|
= help: consider removing the parameter
|
||||||
|
|
||||||
error: type parameters go unused in function definition
|
error: type parameters go unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:26:16
|
--> $DIR/extra_unused_type_parameters.rs:35:16
|
||||||
|
|
|
|
||||||
LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
|
LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
|
||||||
| ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
|
| ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
|
||||||
|
|
|
|
||||||
= help: consider removing the parameters
|
= help: consider removing the parameters
|
||||||
|
|
||||||
error: type parameter goes unused in function definition
|
error: type parameter goes unused in function definition
|
||||||
--> $DIR/extra_unused_type_parameters.rs:49:22
|
--> $DIR/extra_unused_type_parameters.rs:60:22
|
||||||
|
|
|
|
||||||
LL | fn unused_ty_impl<T>(&self) {}
|
LL | fn unused_ty_impl<T>(&self) {
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
= help: consider removing the parameter
|
= help: consider removing the parameter
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: type parameters go unused in function definition
|
||||||
|
--> $DIR/extra_unused_type_parameters.rs:82:17
|
||||||
|
|
|
||||||
|
LL | fn unused_opaque<A, B>(dummy: impl Default) {
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider removing the parameters
|
||||||
|
|
||||||
|
error: type parameter goes unused in function definition
|
||||||
|
--> $DIR/extra_unused_type_parameters.rs:95:58
|
||||||
|
|
|
||||||
|
LL | fn unused_with_priv_trait_bound<T: private::Private, U>() {
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= help: consider removing the parameter
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// run-rustfix
|
// run-rustfix
|
||||||
|
// aux-build: proc_macro_with_span.rs
|
||||||
#![warn(clippy::useless_format)]
|
#![warn(clippy::useless_format)]
|
||||||
#![allow(
|
#![allow(
|
||||||
unused_tuple_struct_fields,
|
unused_tuple_struct_fields,
|
||||||
|
@ -9,6 +10,8 @@
|
||||||
clippy::uninlined_format_args
|
clippy::uninlined_format_args
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
extern crate proc_macro_with_span;
|
||||||
|
|
||||||
struct Foo(pub String);
|
struct Foo(pub String);
|
||||||
|
|
||||||
macro_rules! foo {
|
macro_rules! foo {
|
||||||
|
@ -87,4 +90,7 @@ fn main() {
|
||||||
let _ = abc.to_string();
|
let _ = abc.to_string();
|
||||||
let xx = "xx";
|
let xx = "xx";
|
||||||
let _ = xx.to_string();
|
let _ = xx.to_string();
|
||||||
|
|
||||||
|
// Issue #10148
|
||||||
|
println!(proc_macro_with_span::with_span!(""something ""));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// run-rustfix
|
// run-rustfix
|
||||||
|
// aux-build: proc_macro_with_span.rs
|
||||||
#![warn(clippy::useless_format)]
|
#![warn(clippy::useless_format)]
|
||||||
#![allow(
|
#![allow(
|
||||||
unused_tuple_struct_fields,
|
unused_tuple_struct_fields,
|
||||||
|
@ -9,6 +10,8 @@
|
||||||
clippy::uninlined_format_args
|
clippy::uninlined_format_args
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
extern crate proc_macro_with_span;
|
||||||
|
|
||||||
struct Foo(pub String);
|
struct Foo(pub String);
|
||||||
|
|
||||||
macro_rules! foo {
|
macro_rules! foo {
|
||||||
|
@ -89,4 +92,7 @@ fn main() {
|
||||||
let _ = format!("{abc}");
|
let _ = format!("{abc}");
|
||||||
let xx = "xx";
|
let xx = "xx";
|
||||||
let _ = format!("{xx}");
|
let _ = format!("{xx}");
|
||||||
|
|
||||||
|
// Issue #10148
|
||||||
|
println!(proc_macro_with_span::with_span!(""something ""));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:19:5
|
--> $DIR/format.rs:22:5
|
||||||
|
|
|
|
||||||
LL | format!("foo");
|
LL | format!("foo");
|
||||||
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||||
|
@ -7,19 +7,19 @@ LL | format!("foo");
|
||||||
= note: `-D clippy::useless-format` implied by `-D warnings`
|
= note: `-D clippy::useless-format` implied by `-D warnings`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:20:5
|
--> $DIR/format.rs:23:5
|
||||||
|
|
|
|
||||||
LL | format!("{{}}");
|
LL | format!("{{}}");
|
||||||
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
|
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:21:5
|
--> $DIR/format.rs:24:5
|
||||||
|
|
|
|
||||||
LL | format!("{{}} abc {{}}");
|
LL | format!("{{}} abc {{}}");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:22:5
|
--> $DIR/format.rs:25:5
|
||||||
|
|
|
|
||||||
LL | / format!(
|
LL | / format!(
|
||||||
LL | | r##"foo {{}}
|
LL | | r##"foo {{}}
|
||||||
|
@ -34,67 +34,67 @@ LL ~ " bar"##.to_string();
|
||||||
|
|
|
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:27:13
|
--> $DIR/format.rs:30:13
|
||||||
|
|
|
|
||||||
LL | let _ = format!("");
|
LL | let _ = format!("");
|
||||||
| ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
|
| ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:29:5
|
--> $DIR/format.rs:32:5
|
||||||
|
|
|
|
||||||
LL | format!("{}", "foo");
|
LL | format!("{}", "foo");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:37:5
|
--> $DIR/format.rs:40:5
|
||||||
|
|
|
|
||||||
LL | format!("{}", arg);
|
LL | format!("{}", arg);
|
||||||
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:67:5
|
--> $DIR/format.rs:70:5
|
||||||
|
|
|
|
||||||
LL | format!("{}", 42.to_string());
|
LL | format!("{}", 42.to_string());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:69:5
|
--> $DIR/format.rs:72:5
|
||||||
|
|
|
|
||||||
LL | format!("{}", x.display().to_string());
|
LL | format!("{}", x.display().to_string());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:73:18
|
--> $DIR/format.rs:76:18
|
||||||
|
|
|
|
||||||
LL | let _ = Some(format!("{}", a + "bar"));
|
LL | let _ = Some(format!("{}", a + "bar"));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:77:22
|
--> $DIR/format.rs:80:22
|
||||||
|
|
|
|
||||||
LL | let _s: String = format!("{}", &*v.join("/n"));
|
LL | let _s: String = format!("{}", &*v.join("/n"));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:83:13
|
--> $DIR/format.rs:86:13
|
||||||
|
|
|
|
||||||
LL | let _ = format!("{x}");
|
LL | let _ = format!("{x}");
|
||||||
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:85:13
|
--> $DIR/format.rs:88:13
|
||||||
|
|
|
|
||||||
LL | let _ = format!("{y}", y = x);
|
LL | let _ = format!("{y}", y = x);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:89:13
|
--> $DIR/format.rs:92:13
|
||||||
|
|
|
|
||||||
LL | let _ = format!("{abc}");
|
LL | let _ = format!("{abc}");
|
||||||
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
|
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
|
||||||
|
|
||||||
error: useless use of `format!`
|
error: useless use of `format!`
|
||||||
--> $DIR/format.rs:91:13
|
--> $DIR/format.rs:94:13
|
||||||
|
|
|
|
||||||
LL | let _ = format!("{xx}");
|
LL | let _ = format!("{xx}");
|
||||||
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
|
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
|
||||||
|
|
17
tests/ui/impl_trait_in_params.rs
Normal file
17
tests/ui/impl_trait_in_params.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
#![warn(clippy::impl_trait_in_params)]
|
||||||
|
|
||||||
|
pub trait Trait {}
|
||||||
|
pub trait AnotherTrait<T> {}
|
||||||
|
|
||||||
|
// Should warn
|
||||||
|
pub fn a(_: impl Trait) {}
|
||||||
|
pub fn c<C: Trait>(_: C, _: impl Trait) {}
|
||||||
|
fn d(_: impl AnotherTrait<u32>) {}
|
||||||
|
|
||||||
|
// Shouldn't warn
|
||||||
|
|
||||||
|
pub fn b<B: Trait>(_: B) {}
|
||||||
|
fn e<T: AnotherTrait<u32>>(_: T) {}
|
||||||
|
|
||||||
|
fn main() {}
|
25
tests/ui/impl_trait_in_params.stderr
Normal file
25
tests/ui/impl_trait_in_params.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
error: '`impl Trait` used as a function parameter'
|
||||||
|
--> $DIR/impl_trait_in_params.rs:8:13
|
||||||
|
|
|
||||||
|
LL | pub fn a(_: impl Trait) {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
|
||||||
|
help: add a type paremeter
|
||||||
|
|
|
||||||
|
LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {}
|
||||||
|
| +++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error: '`impl Trait` used as a function parameter'
|
||||||
|
--> $DIR/impl_trait_in_params.rs:9:29
|
||||||
|
|
|
||||||
|
LL | pub fn c<C: Trait>(_: C, _: impl Trait) {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: add a type paremeter
|
||||||
|
|
|
||||||
|
LL | pub fn c<C: Trait, { /* Generic name */ }: Trait>(_: C, _: impl Trait) {}
|
||||||
|
| +++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -11,7 +11,7 @@ fn main() {
|
||||||
let _good = (
|
let _good = (
|
||||||
0b1011_i64,
|
0b1011_i64,
|
||||||
0o1_234_u32,
|
0o1_234_u32,
|
||||||
0x0123_4567,
|
0x1_234_567,
|
||||||
1_2345_6789,
|
1_2345_6789,
|
||||||
1234_f32,
|
1234_f32,
|
||||||
1_234.12_f32,
|
1_234.12_f32,
|
||||||
|
@ -19,7 +19,7 @@ fn main() {
|
||||||
1.123_4_f32,
|
1.123_4_f32,
|
||||||
);
|
);
|
||||||
let _bad = (
|
let _bad = (
|
||||||
0b11_0110_i64,
|
0b1_10110_i64,
|
||||||
0xdead_beef_usize,
|
0xdead_beef_usize,
|
||||||
123_456_f32,
|
123_456_f32,
|
||||||
123_456.12_f32,
|
123_456.12_f32,
|
||||||
|
|
|
@ -1,22 +1,10 @@
|
||||||
error: digits of hex or binary literal not grouped by four
|
error: digits of hex, binary or octal literal not in groups of equal size
|
||||||
--> $DIR/large_digit_groups.rs:14:9
|
|
||||||
|
|
|
||||||
LL | 0x1_234_567,
|
|
||||||
| ^^^^^^^^^^^ help: consider: `0x0123_4567`
|
|
||||||
|
|
|
||||||
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
|
|
||||||
|
|
||||||
error: digits of hex or binary literal not grouped by four
|
|
||||||
--> $DIR/large_digit_groups.rs:22:9
|
|
||||||
|
|
|
||||||
LL | 0b1_10110_i64,
|
|
||||||
| ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
|
|
||||||
|
|
||||||
error: digits of hex or binary literal not grouped by four
|
|
||||||
--> $DIR/large_digit_groups.rs:23:9
|
--> $DIR/large_digit_groups.rs:23:9
|
||||||
|
|
|
|
||||||
LL | 0xd_e_adbee_f_usize,
|
LL | 0xd_e_adbee_f_usize,
|
||||||
| ^^^^^^^^^^^^^^^^^^^ help: consider: `0xdead_beef_usize`
|
| ^^^^^^^^^^^^^^^^^^^ help: consider: `0xdead_beef_usize`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
|
||||||
|
|
||||||
error: digit groups should be smaller
|
error: digit groups should be smaller
|
||||||
--> $DIR/large_digit_groups.rs:24:9
|
--> $DIR/large_digit_groups.rs:24:9
|
||||||
|
@ -44,5 +32,5 @@ error: digit groups should be smaller
|
||||||
LL | 1_23456.12345_6_f64,
|
LL | 1_23456.12345_6_f64,
|
||||||
| ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64`
|
| ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64`
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
|
54
tests/ui/let_underscore_untyped.rs
Normal file
54
tests/ui/let_underscore_untyped.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#![allow(unused)]
|
||||||
|
#![warn(clippy::let_underscore_untyped)]
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
use std::{boxed::Box, fmt::Display};
|
||||||
|
|
||||||
|
fn a() -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b<T>(x: T) -> T {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() -> impl Display {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn d(x: &u32) -> &u32 {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn e() -> Result<u32, ()> {
|
||||||
|
Ok(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() -> Box<dyn Display> {
|
||||||
|
Box::new(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = a();
|
||||||
|
let _ = b(1);
|
||||||
|
let _ = c();
|
||||||
|
let _ = d(&1);
|
||||||
|
let _ = e();
|
||||||
|
let _ = f();
|
||||||
|
|
||||||
|
_ = a();
|
||||||
|
_ = b(1);
|
||||||
|
_ = c();
|
||||||
|
_ = d(&1);
|
||||||
|
_ = e();
|
||||||
|
_ = f();
|
||||||
|
|
||||||
|
let _: u32 = a();
|
||||||
|
let _: u32 = b(1);
|
||||||
|
let _: &u32 = d(&1);
|
||||||
|
let _: Result<_, _> = e();
|
||||||
|
let _: Box<_> = f();
|
||||||
|
|
||||||
|
#[allow(clippy::let_underscore_untyped)]
|
||||||
|
let _ = a();
|
||||||
|
}
|
51
tests/ui/let_underscore_untyped.stderr
Normal file
51
tests/ui/let_underscore_untyped.stderr
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
error: non-binding `let` without a type annotation
|
||||||
|
--> $DIR/let_underscore_untyped.rs:32:5
|
||||||
|
|
|
||||||
|
LL | let _ = a();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a type annotation or removing the `let` keyword
|
||||||
|
= note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: non-binding `let` without a type annotation
|
||||||
|
--> $DIR/let_underscore_untyped.rs:33:5
|
||||||
|
|
|
||||||
|
LL | let _ = b(1);
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a type annotation or removing the `let` keyword
|
||||||
|
|
||||||
|
error: non-binding `let` without a type annotation
|
||||||
|
--> $DIR/let_underscore_untyped.rs:34:5
|
||||||
|
|
|
||||||
|
LL | let _ = c();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a type annotation or removing the `let` keyword
|
||||||
|
|
||||||
|
error: non-binding `let` without a type annotation
|
||||||
|
--> $DIR/let_underscore_untyped.rs:35:5
|
||||||
|
|
|
||||||
|
LL | let _ = d(&1);
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a type annotation or removing the `let` keyword
|
||||||
|
|
||||||
|
error: non-binding `let` without a type annotation
|
||||||
|
--> $DIR/let_underscore_untyped.rs:36:5
|
||||||
|
|
|
||||||
|
LL | let _ = e();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a type annotation or removing the `let` keyword
|
||||||
|
|
||||||
|
error: non-binding `let` without a type annotation
|
||||||
|
--> $DIR/let_underscore_untyped.rs:37:5
|
||||||
|
|
|
||||||
|
LL | let _ = f();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding a type annotation or removing the `let` keyword
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
|
@ -121,7 +121,7 @@ error: digits grouped inconsistently by underscores
|
||||||
LL | let fail23 = 3__16___23;
|
LL | let fail23 = 3__16___23;
|
||||||
| ^^^^^^^^^^ help: consider: `31_623`
|
| ^^^^^^^^^^ help: consider: `31_623`
|
||||||
|
|
||||||
error: digits of hex or binary literal not grouped by four
|
error: digits of hex, binary or octal literal not in groups of equal size
|
||||||
--> $DIR/literals.rs:38:18
|
--> $DIR/literals.rs:38:18
|
||||||
|
|
|
|
||||||
LL | let fail24 = 0xAB_ABC_AB;
|
LL | let fail24 = 0xAB_ABC_AB;
|
||||||
|
@ -129,12 +129,6 @@ LL | let fail24 = 0xAB_ABC_AB;
|
||||||
|
|
|
|
||||||
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
|
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
|
||||||
|
|
||||||
error: digits of hex or binary literal not grouped by four
|
|
||||||
--> $DIR/literals.rs:39:18
|
|
||||||
|
|
|
||||||
LL | let fail25 = 0b01_100_101;
|
|
||||||
| ^^^^^^^^^^^^ help: consider: `0b0110_0101`
|
|
||||||
|
|
||||||
error: this is a decimal constant
|
error: this is a decimal constant
|
||||||
--> $DIR/literals.rs:46:13
|
--> $DIR/literals.rs:46:13
|
||||||
|
|
|
|
||||||
|
@ -168,5 +162,5 @@ help: if you mean to use a decimal constant, remove the `0` to avoid confusion
|
||||||
LL | let _ = 89;
|
LL | let _ = 89;
|
||||||
| ~~
|
| ~~
|
||||||
|
|
||||||
error: aborting due to 21 previous errors
|
error: aborting due to 20 previous errors
|
||||||
|
|
||||||
|
|
|
@ -248,4 +248,15 @@ fn not_fire() {
|
||||||
Some(value) => value,
|
Some(value) => value,
|
||||||
_ => macro_call!(),
|
_ => macro_call!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Issue 10296
|
||||||
|
// The let/else block in the else part is not divergent despite the presence of return
|
||||||
|
let _x = if let Some(x) = Some(1) {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
let Some(_z) = Some(3) else {
|
||||||
|
return
|
||||||
|
};
|
||||||
|
1
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,13 @@ fn fire() {
|
||||||
loop {
|
loop {
|
||||||
// More complex pattern for the identity arm and diverging arm
|
// More complex pattern for the identity arm and diverging arm
|
||||||
let v = match h() {
|
let v = match h() {
|
||||||
(Some(_), Some(_)) | (None, None) => continue,
|
|
||||||
(Some(v), None) | (None, Some(v)) => v,
|
(Some(v), None) | (None, Some(v)) => v,
|
||||||
|
(Some(_), Some(_)) | (None, None) => continue,
|
||||||
};
|
};
|
||||||
// Custom enums are supported as long as the "else" arm is a simple _
|
// Custom enums are supported as long as the "else" arm is a simple _
|
||||||
let v = match build_enum() {
|
let v = match build_enum() {
|
||||||
_ => continue,
|
|
||||||
Variant::Bar(v) | Variant::Baz(v) => v,
|
Variant::Bar(v) | Variant::Baz(v) => v,
|
||||||
|
_ => continue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,12 @@ fn fire() {
|
||||||
Variant::Bar(_) | Variant::Baz(_) => (),
|
Variant::Bar(_) | Variant::Baz(_) => (),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let data = [1_u8, 2, 3, 4, 0, 0, 0, 0];
|
||||||
|
let data = match data.as_slice() {
|
||||||
|
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn not_fire() {
|
fn not_fire() {
|
||||||
|
@ -125,4 +131,23 @@ fn not_fire() {
|
||||||
Ok(v) | Err(Variant::Bar(v) | Variant::Baz(v)) => v,
|
Ok(v) | Err(Variant::Bar(v) | Variant::Baz(v)) => v,
|
||||||
Err(Variant::Foo) => return,
|
Err(Variant::Foo) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Issue 10241
|
||||||
|
// The non-divergent arm arrives in second position and
|
||||||
|
// may cover values already matched in the first arm.
|
||||||
|
let v = match h() {
|
||||||
|
(Some(_), Some(_)) | (None, None) => return,
|
||||||
|
(Some(v), _) | (None, Some(v)) => v,
|
||||||
|
};
|
||||||
|
|
||||||
|
let v = match build_enum() {
|
||||||
|
_ => return,
|
||||||
|
Variant::Bar(v) | Variant::Baz(v) => v,
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = [1_u8, 2, 3, 4, 0, 0, 0, 0];
|
||||||
|
let data = match data.as_slice() {
|
||||||
|
[] | [0, 0] => return,
|
||||||
|
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else_match.rs:44:9
|
--> $DIR/manual_let_else_match.rs:44:9
|
||||||
|
|
|
|
||||||
LL | / let v = match h() {
|
LL | / let v = match h() {
|
||||||
LL | | (Some(_), Some(_)) | (None, None) => continue,
|
|
||||||
LL | | (Some(v), None) | (None, Some(v)) => v,
|
LL | | (Some(v), None) | (None, Some(v)) => v,
|
||||||
|
LL | | (Some(_), Some(_)) | (None, None) => continue,
|
||||||
LL | | };
|
LL | | };
|
||||||
| |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
|
| |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
|
||||||
|
|
||||||
|
@ -31,8 +31,8 @@ error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else_match.rs:49:9
|
--> $DIR/manual_let_else_match.rs:49:9
|
||||||
|
|
|
|
||||||
LL | / let v = match build_enum() {
|
LL | / let v = match build_enum() {
|
||||||
LL | | _ => continue,
|
|
||||||
LL | | Variant::Bar(v) | Variant::Baz(v) => v,
|
LL | | Variant::Bar(v) | Variant::Baz(v) => v,
|
||||||
|
LL | | _ => continue,
|
||||||
LL | | };
|
LL | | };
|
||||||
| |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
|
| |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
|
||||||
|
|
||||||
|
@ -63,5 +63,14 @@ LL | | _ => return,
|
||||||
LL | | };
|
LL | | };
|
||||||
| |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
|
| |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error: this could be rewritten as `let...else`
|
||||||
|
--> $DIR/manual_let_else_match.rs:76:5
|
||||||
|
|
|
||||||
|
LL | / let data = match data.as_slice() {
|
||||||
|
LL | | [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data,
|
||||||
|
LL | | _ => return,
|
||||||
|
LL | | };
|
||||||
|
| |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };`
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// run-rustfix
|
// run-rustfix
|
||||||
|
|
||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
#![allow(clippy::let_underscore_untyped)]
|
||||||
#![allow(clippy::missing_docs_in_private_items)]
|
#![allow(clippy::missing_docs_in_private_items)]
|
||||||
#![allow(clippy::map_identity)]
|
#![allow(clippy::map_identity)]
|
||||||
#![allow(clippy::redundant_closure)]
|
#![allow(clippy::redundant_closure)]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// run-rustfix
|
// run-rustfix
|
||||||
|
|
||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
#![allow(clippy::let_underscore_untyped)]
|
||||||
#![allow(clippy::missing_docs_in_private_items)]
|
#![allow(clippy::missing_docs_in_private_items)]
|
||||||
#![allow(clippy::map_identity)]
|
#![allow(clippy::map_identity)]
|
||||||
#![allow(clippy::redundant_closure)]
|
#![allow(clippy::redundant_closure)]
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue