commit
0aaa9ea5c0
1501 changed files with 30073 additions and 9904 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 985d561f0bb9b76ec043a2b12511790ec7a2b954
|
||||
Subproject commit 3c5af6bed9a1a243a693e8e22ee2486bd5b82a6c
|
||||
|
|
@ -157,6 +157,11 @@ jobs:
|
|||
- name: Test metadata collection
|
||||
run: cargo collect-metadata
|
||||
|
||||
- name: Test lint_configuration.md is up-to-date
|
||||
run: |
|
||||
echo "run \`cargo collect-metadata\` if this fails"
|
||||
git update-index --refresh
|
||||
|
||||
integration_build:
|
||||
needs: changelog
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
|
|
@ -6,11 +6,204 @@ document.
|
|||
|
||||
## Unreleased / Beta / In Rust Nightly
|
||||
|
||||
[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
|
||||
[d822110d...master](https://github.com/rust-lang/rust-clippy/compare/d822110d...master)
|
||||
|
||||
## Rust 1.67
|
||||
|
||||
Current stable, released 2023-01-26
|
||||
|
||||
[4f142aa1...d822110d](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...d822110d)
|
||||
|
||||
### New Lints
|
||||
|
||||
* [`seek_from_current`]
|
||||
[#9681](https://github.com/rust-lang/rust-clippy/pull/9681)
|
||||
* [`from_raw_with_void_ptr`]
|
||||
[#9690](https://github.com/rust-lang/rust-clippy/pull/9690)
|
||||
* [`misnamed_getters`]
|
||||
[#9770](https://github.com/rust-lang/rust-clippy/pull/9770)
|
||||
* [`seek_to_start_instead_of_rewind`]
|
||||
[#9667](https://github.com/rust-lang/rust-clippy/pull/9667)
|
||||
* [`suspicious_xor_used_as_pow`]
|
||||
[#9506](https://github.com/rust-lang/rust-clippy/pull/9506)
|
||||
* [`unnecessary_safety_doc`]
|
||||
[#9822](https://github.com/rust-lang/rust-clippy/pull/9822)
|
||||
* [`unchecked_duration_subtraction`]
|
||||
[#9570](https://github.com/rust-lang/rust-clippy/pull/9570)
|
||||
* [`manual_is_ascii_check`]
|
||||
[#9765](https://github.com/rust-lang/rust-clippy/pull/9765)
|
||||
* [`unnecessary_safety_comment`]
|
||||
[#9851](https://github.com/rust-lang/rust-clippy/pull/9851)
|
||||
* [`let_underscore_future`]
|
||||
[#9760](https://github.com/rust-lang/rust-clippy/pull/9760)
|
||||
* [`manual_let_else`]
|
||||
[#8437](https://github.com/rust-lang/rust-clippy/pull/8437)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Moved [`uninlined_format_args`] to `style` (Now warn-by-default)
|
||||
[#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
|
||||
* Moved [`needless_collect`] to `nursery` (Now allow-by-default)
|
||||
[#9705](https://github.com/rust-lang/rust-clippy/pull/9705)
|
||||
* Moved [`or_fun_call`] to `nursery` (Now allow-by-default)
|
||||
[#9829](https://github.com/rust-lang/rust-clippy/pull/9829)
|
||||
* Uplifted [`let_underscore_lock`] into rustc
|
||||
[#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
|
||||
* Uplifted [`let_underscore_drop`] into rustc
|
||||
[#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
|
||||
* Moved [`bool_to_int_with_if`] to `pedantic` (Now allow-by-default)
|
||||
[#9830](https://github.com/rust-lang/rust-clippy/pull/9830)
|
||||
* Move `index_refutable_slice` to `pedantic` (Now warn-by-default)
|
||||
[#9975](https://github.com/rust-lang/rust-clippy/pull/9975)
|
||||
* Moved [`manual_clamp`] to `nursery` (Now allow-by-default)
|
||||
[#10101](https://github.com/rust-lang/rust-clippy/pull/10101)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* The scope of `#![clippy::msrv]` is now tracked correctly
|
||||
[#9924](https://github.com/rust-lang/rust-clippy/pull/9924)
|
||||
* `#[clippy::msrv]` can now be used as an outer attribute
|
||||
[#9860](https://github.com/rust-lang/rust-clippy/pull/9860)
|
||||
* Clippy will now avoid Cargo's cache, if `Cargo.toml` or `clippy.toml` have changed
|
||||
[#9707](https://github.com/rust-lang/rust-clippy/pull/9707)
|
||||
* [`uninlined_format_args`]: Added a new config `allow-mixed-uninlined-format-args` to allow the
|
||||
lint, if only some arguments can be inlined
|
||||
[#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
|
||||
* [`needless_lifetimes`]: Now provides suggests for individual lifetimes
|
||||
[#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
|
||||
* [`needless_collect`]: Now detects needless `is_empty` and `contains` calls
|
||||
[#8744](https://github.com/rust-lang/rust-clippy/pull/8744)
|
||||
* [`blanket_clippy_restriction_lints`]: Now lints, if `clippy::restriction` is enabled via the
|
||||
command line arguments
|
||||
[#9755](https://github.com/rust-lang/rust-clippy/pull/9755)
|
||||
* [`mutable_key_type`]: Now has the `ignore-interior-mutability` configuration, to add types which
|
||||
should be ignored by the lint
|
||||
[#9692](https://github.com/rust-lang/rust-clippy/pull/9692)
|
||||
* [`uninlined_format_args`]: Now works for multiline `format!` expressions
|
||||
[#9945](https://github.com/rust-lang/rust-clippy/pull/9945)
|
||||
* [`cognitive_complexity`]: Now works for async functions
|
||||
[#9828](https://github.com/rust-lang/rust-clippy/pull/9828)
|
||||
[#9836](https://github.com/rust-lang/rust-clippy/pull/9836)
|
||||
* [`vec_box`]: Now avoids an off-by-one error when using the `vec-box-size-threshold` configuration
|
||||
[#9848](https://github.com/rust-lang/rust-clippy/pull/9848)
|
||||
* [`never_loop`]: Now correctly handles breaks in nested labeled blocks
|
||||
[#9858](https://github.com/rust-lang/rust-clippy/pull/9858)
|
||||
[#9837](https://github.com/rust-lang/rust-clippy/pull/9837)
|
||||
* [`disallowed_methods`], [`disallowed_types`], [`disallowed_macros`]: Now correctly resolve
|
||||
paths, if a crate is used multiple times with different versions
|
||||
[#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
|
||||
* [`disallowed_methods`]: Can now be used for local methods
|
||||
[#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
|
||||
* [`print_stdout`], [`print_stderr`]: Can now be enabled in test with the `allow-print-in-tests`
|
||||
config value
|
||||
[#9797](https://github.com/rust-lang/rust-clippy/pull/9797)
|
||||
* [`from_raw_with_void_ptr`]: Now works for `Rc`, `Arc`, `alloc::rc::Weak` and
|
||||
`alloc::sync::Weak` types.
|
||||
[#9700](https://github.com/rust-lang/rust-clippy/pull/9700)
|
||||
* [`needless_borrowed_reference`]: Now works for struct and tuple patterns with wildcards
|
||||
[#9855](https://github.com/rust-lang/rust-clippy/pull/9855)
|
||||
* [`or_fun_call`]: Now supports `map_or` methods
|
||||
[#9689](https://github.com/rust-lang/rust-clippy/pull/9689)
|
||||
* [`unwrap_used`], [`expect_used`]: No longer lints in test code
|
||||
[#9686](https://github.com/rust-lang/rust-clippy/pull/9686)
|
||||
* [`fn_params_excessive_bools`]: Is now emitted with the lint level at the linted function
|
||||
[#9698](https://github.com/rust-lang/rust-clippy/pull/9698)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`new_ret_no_self`]: No longer lints when `impl Trait<Self>` is returned
|
||||
[#9733](https://github.com/rust-lang/rust-clippy/pull/9733)
|
||||
* [`unnecessary_lazy_evaluations`]: No longer lints, if the type has a significant drop
|
||||
[#9750](https://github.com/rust-lang/rust-clippy/pull/9750)
|
||||
* [`option_if_let_else`]: No longer lints, if any arm has guard
|
||||
[#9747](https://github.com/rust-lang/rust-clippy/pull/9747)
|
||||
* [`explicit_auto_deref`]: No longer lints, if the target type is a projection with generic
|
||||
arguments
|
||||
[#9813](https://github.com/rust-lang/rust-clippy/pull/9813)
|
||||
* [`unnecessary_to_owned`]: No longer lints, if the suggestion effects types
|
||||
[#9796](https://github.com/rust-lang/rust-clippy/pull/9796)
|
||||
* [`needless_borrow`]: No longer lints, if the suggestion is affected by `Deref`
|
||||
[#9674](https://github.com/rust-lang/rust-clippy/pull/9674)
|
||||
* [`unused_unit`]: No longer lints, if lifetimes are bound to the return type
|
||||
[#9849](https://github.com/rust-lang/rust-clippy/pull/9849)
|
||||
* [`mut_mut`]: No longer lints cases with unsized mutable references
|
||||
[#9835](https://github.com/rust-lang/rust-clippy/pull/9835)
|
||||
* [`bool_to_int_with_if`]: No longer lints in const context
|
||||
[#9738](https://github.com/rust-lang/rust-clippy/pull/9738)
|
||||
* [`use_self`]: No longer lints in macros
|
||||
[#9704](https://github.com/rust-lang/rust-clippy/pull/9704)
|
||||
* [`unnecessary_operation`]: No longer lints, if multiple macros are involved
|
||||
[#9981](https://github.com/rust-lang/rust-clippy/pull/9981)
|
||||
* [`allow_attributes_without_reason`]: No longer lints inside external macros
|
||||
[#9630](https://github.com/rust-lang/rust-clippy/pull/9630)
|
||||
* [`question_mark`]: No longer lints for `if let Err()` with an `else` branch
|
||||
[#9722](https://github.com/rust-lang/rust-clippy/pull/9722)
|
||||
* [`unnecessary_cast`]: No longer lints if the identifier and cast originate from different macros
|
||||
[#9980](https://github.com/rust-lang/rust-clippy/pull/9980)
|
||||
* [`arithmetic_side_effects`]: Now detects operations with associated constants
|
||||
[#9592](https://github.com/rust-lang/rust-clippy/pull/9592)
|
||||
* [`explicit_auto_deref`]: No longer lints, if the initial value is not a reference or reference
|
||||
receiver
|
||||
[#9997](https://github.com/rust-lang/rust-clippy/pull/9997)
|
||||
* [`module_name_repetitions`], [`single_component_path_imports`]: Now handle `#[allow]`
|
||||
attributes correctly
|
||||
[#9879](https://github.com/rust-lang/rust-clippy/pull/9879)
|
||||
* [`bool_to_int_with_if`]: No longer lints `if let` statements
|
||||
[#9714](https://github.com/rust-lang/rust-clippy/pull/9714)
|
||||
* [`needless_borrow`]: No longer lints, `if`-`else`-statements that require the borrow
|
||||
[#9791](https://github.com/rust-lang/rust-clippy/pull/9791)
|
||||
* [`needless_borrow`]: No longer lints borrows, if moves were illegal
|
||||
[#9711](https://github.com/rust-lang/rust-clippy/pull/9711)
|
||||
* [`manual_swap`]: No longer lints in const context
|
||||
[#9871](https://github.com/rust-lang/rust-clippy/pull/9871)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`missing_safety_doc`], [`missing_errors_doc`], [`missing_panics_doc`]: No longer show the
|
||||
entire item in the lint emission.
|
||||
[#9772](https://github.com/rust-lang/rust-clippy/pull/9772)
|
||||
* [`needless_lifetimes`]: Only suggests `'_` when it's applicable
|
||||
[#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
|
||||
* [`use_self`]: Now suggests full paths correctly
|
||||
[#9726](https://github.com/rust-lang/rust-clippy/pull/9726)
|
||||
* [`redundant_closure_call`]: Now correctly deals with macros during suggestion creation
|
||||
[#9987](https://github.com/rust-lang/rust-clippy/pull/9987)
|
||||
* [`unnecessary_cast`]: Suggestions now correctly deal with references
|
||||
[#9996](https://github.com/rust-lang/rust-clippy/pull/9996)
|
||||
* [`unnecessary_join`]: Suggestions now correctly use [turbofish] operators
|
||||
[#9779](https://github.com/rust-lang/rust-clippy/pull/9779)
|
||||
* [`equatable_if_let`]: Can now suggest `matches!` replacements
|
||||
[#9368](https://github.com/rust-lang/rust-clippy/pull/9368)
|
||||
* [`string_extend_chars`]: Suggestions now correctly work for `str` slices
|
||||
[#9741](https://github.com/rust-lang/rust-clippy/pull/9741)
|
||||
* [`redundant_closure_for_method_calls`]: Suggestions now include angle brackets and generic
|
||||
arguments if needed
|
||||
[#9745](https://github.com/rust-lang/rust-clippy/pull/9745)
|
||||
* [`manual_let_else`]: Suggestions no longer expand macro calls
|
||||
[#9943](https://github.com/rust-lang/rust-clippy/pull/9943)
|
||||
* [`infallible_destructuring_match`]: Suggestions now preserve references
|
||||
[#9850](https://github.com/rust-lang/rust-clippy/pull/9850)
|
||||
* [`result_large_err`]: The error now shows the largest enum variant
|
||||
[#9662](https://github.com/rust-lang/rust-clippy/pull/9662)
|
||||
* [`needless_return`]: Suggestions are now formatted better
|
||||
[#9967](https://github.com/rust-lang/rust-clippy/pull/9967)
|
||||
* [`unused_rounding`]: The suggestion now preserves the original float literal notation
|
||||
[#9870](https://github.com/rust-lang/rust-clippy/pull/9870)
|
||||
|
||||
[turbofish]: https://turbo.fish/::%3CClippy%3E
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* [`result_large_err`]: Fixed ICE for empty enums
|
||||
[#10007](https://github.com/rust-lang/rust-clippy/pull/10007)
|
||||
* [`redundant_allocation`]: Fixed ICE for types with bounded variables
|
||||
[#9773](https://github.com/rust-lang/rust-clippy/pull/9773)
|
||||
* [`unused_rounding`]: Fixed ICE, if `_` was used as a separator
|
||||
[#10001](https://github.com/rust-lang/rust-clippy/pull/10001)
|
||||
|
||||
## Rust 1.66
|
||||
|
||||
Current stable, released 2022-12-15
|
||||
Released 2022-12-15
|
||||
|
||||
[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
|
||||
|
||||
|
|
@ -166,6 +359,7 @@ Current stable, released 2022-12-15
|
|||
|
||||
* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
|
||||
[#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
|
||||
[#10027](https://github.com/rust-lang/rust-clippy/pull/10027)
|
||||
* [`manual_range_contains`]: No longer ICEs on values behind references
|
||||
[#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
|
||||
* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
|
||||
|
|
@ -4383,6 +4577,7 @@ Released 2018-09-13
|
|||
[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
|
||||
[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
|
||||
[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
|
||||
[`multiple_unsafe_ops_per_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block
|
||||
[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
|
||||
[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
|
||||
[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
|||
|
|
@ -194,11 +194,21 @@ value` mapping e.g.
|
|||
```toml
|
||||
avoid-breaking-exported-api = false
|
||||
disallowed-names = ["toto", "tata", "titi"]
|
||||
cognitive-complexity-threshold = 30
|
||||
```
|
||||
|
||||
See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
|
||||
the lint descriptions contain the names and meanings of these configuration variables.
|
||||
The [table of configurations](https://doc.rust-lang.org/nightly/clippy/lint_configuration.html)
|
||||
contains all config values, their default, and a list of lints they affect.
|
||||
Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
|
||||
, also contains information about these values.
|
||||
|
||||
For configurations that are a list type with default values such as
|
||||
[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
|
||||
you can use the unique value `".."` to extend the default values instead of replacing them.
|
||||
|
||||
```toml
|
||||
# default of disallowed-names is ["foo", "baz", "quux"]
|
||||
disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
|
||||
```
|
||||
|
||||
> **Note**
|
||||
>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
- [Installation](installation.md)
|
||||
- [Usage](usage.md)
|
||||
- [Configuration](configuration.md)
|
||||
- [Lint Configuration](lint_configuration.md)
|
||||
- [Clippy's Lints](lints.md)
|
||||
- [Continuous Integration](continuous_integration/README.md)
|
||||
- [GitHub Actions](continuous_integration/github_actions.md)
|
||||
|
|
|
|||
|
|
@ -8,11 +8,21 @@ basic `variable = value` mapping eg.
|
|||
```toml
|
||||
avoid-breaking-exported-api = false
|
||||
disallowed-names = ["toto", "tata", "titi"]
|
||||
cognitive-complexity-threshold = 30
|
||||
```
|
||||
|
||||
See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
|
||||
the lint descriptions contain the names and meanings of these configuration variables.
|
||||
The [table of configurations](./lint_configuration.md)
|
||||
contains all config values, their default, and a list of lints they affect.
|
||||
Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
|
||||
, also contains information about these values.
|
||||
|
||||
For configurations that are a list type with default values such as
|
||||
[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
|
||||
you can use the unique value `".."` to extend the default values instead of replacing them.
|
||||
|
||||
```toml
|
||||
# default of disallowed-names is ["foo", "baz", "quux"]
|
||||
disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
|
||||
```
|
||||
|
||||
To deactivate the "for further information visit *lint-link*" message you can define the `CLIPPY_DISABLE_DOCS_LINKS`
|
||||
environment variable.
|
||||
|
|
|
|||
|
|
@ -146,7 +146,8 @@ For cargo lints, the process of testing differs in that we are interested in the
|
|||
manifest.
|
||||
|
||||
If our new lint is named e.g. `foo_categories`, after running `cargo dev
|
||||
new_lint` we will find by default two new crates, each with its manifest file:
|
||||
new_lint --name=foo_categories --type=cargo --category=cargo` we will find by
|
||||
default two new crates, each with its manifest file:
|
||||
|
||||
* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the
|
||||
new lint to raise an error.
|
||||
|
|
@ -699,6 +700,10 @@ for some users. Adding a configuration is done in the following steps:
|
|||
`clippy.toml` file with the configuration value and a rust file that
|
||||
should be linted by Clippy. The test can otherwise be written as usual.
|
||||
|
||||
5. Update [Lint Configuration](../lint_configuration.md)
|
||||
|
||||
Run `cargo collect-metadata` to generate documentation changes for the book.
|
||||
|
||||
[`clippy_lints::utils::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/conf.rs
|
||||
[`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
|
||||
[`tests/ui`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
This document explains how to make additions and changes to the Clippy book, the
|
||||
guide to Clippy that you're reading right now. The Clippy book is formatted with
|
||||
[Markdown](https://www.markdownguide.org) and generated by
|
||||
[mdbook](https://github.com/rust-lang/mdBook).
|
||||
[mdBook](https://github.com/rust-lang/mdBook).
|
||||
|
||||
- [Get mdbook](#get-mdbook)
|
||||
- [Get mdBook](#get-mdbook)
|
||||
- [Make changes](#make-changes)
|
||||
|
||||
## Get mdbook
|
||||
## Get mdBook
|
||||
|
||||
While not strictly necessary since the book source is simply Markdown text
|
||||
files, having mdbook locally will allow you to build, test and serve the book
|
||||
files, having mdBook locally will allow you to build, test and serve the book
|
||||
locally to view changes before you commit them to the repository. You likely
|
||||
already have `cargo` installed, so the easiest option is to simply:
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ already have `cargo` installed, so the easiest option is to simply:
|
|||
cargo install mdbook
|
||||
```
|
||||
|
||||
See the mdbook [installation](https://github.com/rust-lang/mdBook#installation)
|
||||
See the mdBook [installation](https://github.com/rust-lang/mdBook#installation)
|
||||
instructions for other options.
|
||||
|
||||
## Make changes
|
||||
|
|
@ -27,7 +27,7 @@ instructions for other options.
|
|||
The book's
|
||||
[src](https://github.com/rust-lang/rust-clippy/tree/master/book/src)
|
||||
directory contains all of the markdown files used to generate the book. If you
|
||||
want to see your changes in real time, you can use the mdbook `serve` command to
|
||||
want to see your changes in real time, you can use the mdBook `serve` command to
|
||||
run a web server locally that will automatically update changes as they are
|
||||
made. From the top level of your `rust-clippy` directory:
|
||||
|
||||
|
|
@ -38,5 +38,5 @@ mdbook serve book --open
|
|||
Then navigate to `http://localhost:3000` to see the generated book. While the
|
||||
server is running, changes you make will automatically be updated.
|
||||
|
||||
For more information, see the mdbook
|
||||
For more information, see the mdBook
|
||||
[guide](https://rust-lang.github.io/mdBook/).
|
||||
|
|
|
|||
|
|
@ -95,11 +95,23 @@ As section headers, we use:
|
|||
Please also be sure to update the Beta/Unreleased sections at the top with the
|
||||
relevant commit ranges.
|
||||
|
||||
If you have the time, it would be appreciated if you double-check, that the
|
||||
`#[clippy::version]` attributes for the added lints contains the correct version.
|
||||
#### 3.1 Include `beta-accepted` PRs
|
||||
|
||||
Look for the [`beta-accepted`] label and make sure to also include the PRs with
|
||||
that label in the changelog. If you can, remove the `beta-accepted` labels
|
||||
**after** the changelog PR was merged.
|
||||
|
||||
> _Note:_ Some of those PRs might even got backported to the previous `beta`.
|
||||
> Those have to be included in the changelog of the _previous_ release.
|
||||
|
||||
### 4. Update `clippy::version` attributes
|
||||
|
||||
Next, make sure to check that the `#[clippy::version]` attributes for the added
|
||||
lints contain the correct version.
|
||||
|
||||
[changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md
|
||||
[forge]: https://forge.rust-lang.org/
|
||||
[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy
|
||||
[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy
|
||||
[rust_stable_tools]: https://github.com/rust-lang/rust/releases
|
||||
[`beta-accepted`]: https://github.com/rust-lang/rust-clippy/issues?q=label%3Abeta-accepted+
|
||||
|
|
|
|||
523
src/tools/clippy/book/src/lint_configuration.md
Normal file
523
src/tools/clippy/book/src/lint_configuration.md
Normal file
|
|
@ -0,0 +1,523 @@
|
|||
<!--
|
||||
This file is generated by `cargo collect-metadata`.
|
||||
Please use that command to update the file and do not edit it by hand.
|
||||
-->
|
||||
|
||||
## Lint Configuration Options
|
||||
| <div style="width:290px">Option</div> | Default Value |
|
||||
|--|--|
|
||||
| [arithmetic-side-effects-allowed](#arithmetic-side-effects-allowed) | `{}` |
|
||||
| [arithmetic-side-effects-allowed-binary](#arithmetic-side-effects-allowed-binary) | `[]` |
|
||||
| [arithmetic-side-effects-allowed-unary](#arithmetic-side-effects-allowed-unary) | `{}` |
|
||||
| [avoid-breaking-exported-api](#avoid-breaking-exported-api) | `true` |
|
||||
| [msrv](#msrv) | `None` |
|
||||
| [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
|
||||
| [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
|
||||
| [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
|
||||
| [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
|
||||
| [type-complexity-threshold](#type-complexity-threshold) | `250` |
|
||||
| [single-char-binding-names-threshold](#single-char-binding-names-threshold) | `4` |
|
||||
| [too-large-for-stack](#too-large-for-stack) | `200` |
|
||||
| [enum-variant-name-threshold](#enum-variant-name-threshold) | `3` |
|
||||
| [enum-variant-size-threshold](#enum-variant-size-threshold) | `200` |
|
||||
| [verbose-bit-mask-threshold](#verbose-bit-mask-threshold) | `1` |
|
||||
| [literal-representation-threshold](#literal-representation-threshold) | `16384` |
|
||||
| [trivial-copy-size-limit](#trivial-copy-size-limit) | `None` |
|
||||
| [pass-by-value-size-limit](#pass-by-value-size-limit) | `256` |
|
||||
| [too-many-lines-threshold](#too-many-lines-threshold) | `100` |
|
||||
| [array-size-threshold](#array-size-threshold) | `512000` |
|
||||
| [vec-box-size-threshold](#vec-box-size-threshold) | `4096` |
|
||||
| [max-trait-bounds](#max-trait-bounds) | `3` |
|
||||
| [max-struct-bools](#max-struct-bools) | `3` |
|
||||
| [max-fn-params-bools](#max-fn-params-bools) | `3` |
|
||||
| [warn-on-all-wildcard-imports](#warn-on-all-wildcard-imports) | `false` |
|
||||
| [disallowed-macros](#disallowed-macros) | `[]` |
|
||||
| [disallowed-methods](#disallowed-methods) | `[]` |
|
||||
| [disallowed-types](#disallowed-types) | `[]` |
|
||||
| [unreadable-literal-lint-fractions](#unreadable-literal-lint-fractions) | `true` |
|
||||
| [upper-case-acronyms-aggressive](#upper-case-acronyms-aggressive) | `false` |
|
||||
| [matches-for-let-else](#matches-for-let-else) | `WellKnownTypes` |
|
||||
| [cargo-ignore-publish](#cargo-ignore-publish) | `false` |
|
||||
| [standard-macro-braces](#standard-macro-braces) | `[]` |
|
||||
| [enforced-import-renames](#enforced-import-renames) | `[]` |
|
||||
| [allowed-scripts](#allowed-scripts) | `["Latin"]` |
|
||||
| [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` |
|
||||
| [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` |
|
||||
| [max-include-file-size](#max-include-file-size) | `1000000` |
|
||||
| [allow-expect-in-tests](#allow-expect-in-tests) | `false` |
|
||||
| [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` |
|
||||
| [allow-dbg-in-tests](#allow-dbg-in-tests) | `false` |
|
||||
| [allow-print-in-tests](#allow-print-in-tests) | `false` |
|
||||
| [large-error-threshold](#large-error-threshold) | `128` |
|
||||
| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` |
|
||||
| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` |
|
||||
| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` |
|
||||
|
||||
### arithmetic-side-effects-allowed
|
||||
Suppress checking of the passed type names in all types of operations.
|
||||
|
||||
If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
|
||||
|
||||
#### Example
|
||||
|
||||
```toml
|
||||
arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
|
||||
```
|
||||
|
||||
#### Noteworthy
|
||||
|
||||
A type, say `SomeType`, listed in this configuration has the same behavior of
|
||||
`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
|
||||
|
||||
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
|
||||
|
||||
* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
|
||||
|
||||
|
||||
### arithmetic-side-effects-allowed-binary
|
||||
Suppress checking of the passed type pair names in binary operations like addition or
|
||||
multiplication.
|
||||
|
||||
Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
|
||||
of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
|
||||
|
||||
Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
|
||||
`["AnotherType", "SomeType"]`.
|
||||
|
||||
#### Example
|
||||
|
||||
```toml
|
||||
arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
|
||||
```
|
||||
|
||||
**Default Value:** `[]` (`Vec<[String; 2]>`)
|
||||
|
||||
* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
|
||||
|
||||
|
||||
### arithmetic-side-effects-allowed-unary
|
||||
Suppress checking of the passed type names in unary operations like "negation" (`-`).
|
||||
|
||||
#### Example
|
||||
|
||||
```toml
|
||||
arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
|
||||
```
|
||||
|
||||
**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
|
||||
|
||||
* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
|
||||
|
||||
|
||||
### avoid-breaking-exported-api
|
||||
Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
|
||||
**Default Value:** `true` (`bool`)
|
||||
|
||||
* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
|
||||
* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
|
||||
* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
|
||||
* [unnecessary_wraps](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps)
|
||||
* [unused_self](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self)
|
||||
* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
|
||||
* [wrong_self_convention](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention)
|
||||
* [box_collection](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection)
|
||||
* [redundant_allocation](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation)
|
||||
* [rc_buffer](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
|
||||
* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
|
||||
* [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option)
|
||||
* [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist)
|
||||
* [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
|
||||
|
||||
|
||||
### msrv
|
||||
The minimum rust version that the project supports
|
||||
|
||||
**Default Value:** `None` (`Option<String>`)
|
||||
|
||||
* [manual_split_once](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
|
||||
* [manual_str_repeat](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
|
||||
* [cloned_instead_of_copied](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied)
|
||||
* [redundant_field_names](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names)
|
||||
* [redundant_static_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes)
|
||||
* [filter_map_next](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next)
|
||||
* [checked_conversions](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions)
|
||||
* [manual_range_contains](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains)
|
||||
* [use_self](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
|
||||
* [mem_replace_with_default](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default)
|
||||
* [manual_non_exhaustive](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)
|
||||
* [option_as_ref_deref](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref)
|
||||
* [map_unwrap_or](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or)
|
||||
* [match_like_matches_macro](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro)
|
||||
* [manual_strip](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
|
||||
* [missing_const_for_fn](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn)
|
||||
* [unnested_or_patterns](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns)
|
||||
* [from_over_into](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into)
|
||||
* [ptr_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr)
|
||||
* [if_then_some_else_none](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none)
|
||||
* [approx_constant](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant)
|
||||
* [deprecated_cfg_attr](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr)
|
||||
* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
|
||||
* [map_clone](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone)
|
||||
* [borrow_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr)
|
||||
* [manual_bits](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
|
||||
* [err_expect](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect)
|
||||
* [cast_abs_to_unsigned](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned)
|
||||
* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
|
||||
* [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
|
||||
* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
|
||||
* [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction)
|
||||
|
||||
|
||||
### cognitive-complexity-threshold
|
||||
The maximum cognitive complexity a function can have
|
||||
|
||||
**Default Value:** `25` (`u64`)
|
||||
|
||||
* [cognitive_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity)
|
||||
|
||||
|
||||
### disallowed-names
|
||||
The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
|
||||
`".."` can be used as part of the list to indicate, that the configured values should be appended to the
|
||||
default configuration of Clippy. By default any configuration will replace the default value.
|
||||
|
||||
**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`)
|
||||
|
||||
* [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
|
||||
|
||||
|
||||
### doc-valid-idents
|
||||
The list of words this lint should not consider as identifiers needing ticks. The value
|
||||
`".."` can be used as part of the list to indicate, that the configured values should be appended to the
|
||||
default configuration of Clippy. By default any configuraction will replace the default value. For example:
|
||||
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
|
||||
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
|
||||
|
||||
Default list:
|
||||
|
||||
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`)
|
||||
|
||||
* [doc_markdown](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown)
|
||||
|
||||
|
||||
### too-many-arguments-threshold
|
||||
The maximum number of argument a function or method can have
|
||||
|
||||
**Default Value:** `7` (`u64`)
|
||||
|
||||
* [too_many_arguments](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments)
|
||||
|
||||
|
||||
### type-complexity-threshold
|
||||
The maximum complexity a type can have
|
||||
|
||||
**Default Value:** `250` (`u64`)
|
||||
|
||||
* [type_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity)
|
||||
|
||||
|
||||
### single-char-binding-names-threshold
|
||||
The maximum number of single char bindings a scope may have
|
||||
|
||||
**Default Value:** `4` (`u64`)
|
||||
|
||||
* [many_single_char_names](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names)
|
||||
|
||||
|
||||
### too-large-for-stack
|
||||
The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
|
||||
|
||||
**Default Value:** `200` (`u64`)
|
||||
|
||||
* [boxed_local](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local)
|
||||
* [useless_vec](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec)
|
||||
|
||||
|
||||
### enum-variant-name-threshold
|
||||
The minimum number of enum variants for the lints about variant names to trigger
|
||||
|
||||
**Default Value:** `3` (`u64`)
|
||||
|
||||
* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
|
||||
|
||||
|
||||
### enum-variant-size-threshold
|
||||
The maximum size of an enum's variant to avoid box suggestion
|
||||
|
||||
**Default Value:** `200` (`u64`)
|
||||
|
||||
* [large_enum_variant](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant)
|
||||
|
||||
|
||||
### verbose-bit-mask-threshold
|
||||
The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
|
||||
|
||||
**Default Value:** `1` (`u64`)
|
||||
|
||||
* [verbose_bit_mask](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask)
|
||||
|
||||
|
||||
### literal-representation-threshold
|
||||
The lower bound for linting decimal literals
|
||||
|
||||
**Default Value:** `16384` (`u64`)
|
||||
|
||||
* [decimal_literal_representation](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation)
|
||||
|
||||
|
||||
### trivial-copy-size-limit
|
||||
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
|
||||
|
||||
**Default Value:** `None` (`Option<u64>`)
|
||||
|
||||
* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
|
||||
|
||||
|
||||
### pass-by-value-size-limit
|
||||
The minimum size (in bytes) to consider a type for passing by reference instead of by value.
|
||||
|
||||
**Default Value:** `256` (`u64`)
|
||||
|
||||
* [large_type_pass_by_move](https://rust-lang.github.io/rust-clippy/master/index.html#large_type_pass_by_move)
|
||||
|
||||
|
||||
### too-many-lines-threshold
|
||||
The maximum number of lines a function or method can have
|
||||
|
||||
**Default Value:** `100` (`u64`)
|
||||
|
||||
* [too_many_lines](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines)
|
||||
|
||||
|
||||
### array-size-threshold
|
||||
The maximum allowed size for arrays on the stack
|
||||
|
||||
**Default Value:** `512000` (`u128`)
|
||||
|
||||
* [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays)
|
||||
* [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays)
|
||||
|
||||
|
||||
### vec-box-size-threshold
|
||||
The size of the boxed type in bytes, where boxing in a `Vec` is allowed
|
||||
|
||||
**Default Value:** `4096` (`u64`)
|
||||
|
||||
* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
|
||||
|
||||
|
||||
### max-trait-bounds
|
||||
The maximum number of bounds a trait can have to be linted
|
||||
|
||||
**Default Value:** `3` (`u64`)
|
||||
|
||||
* [type_repetition_in_bounds](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
|
||||
|
||||
|
||||
### max-struct-bools
|
||||
The maximum number of bool fields a struct can have
|
||||
|
||||
**Default Value:** `3` (`u64`)
|
||||
|
||||
* [struct_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools)
|
||||
|
||||
|
||||
### max-fn-params-bools
|
||||
The maximum number of bool parameters a function can have
|
||||
|
||||
**Default Value:** `3` (`u64`)
|
||||
|
||||
* [fn_params_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools)
|
||||
|
||||
|
||||
### warn-on-all-wildcard-imports
|
||||
Whether to allow certain wildcard imports (prelude, super in tests).
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [wildcard_imports](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports)
|
||||
|
||||
|
||||
### disallowed-macros
|
||||
The list of disallowed macros, written as fully qualified paths.
|
||||
|
||||
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
|
||||
|
||||
* [disallowed_macros](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros)
|
||||
|
||||
|
||||
### disallowed-methods
|
||||
The list of disallowed methods, written as fully qualified paths.
|
||||
|
||||
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
|
||||
|
||||
* [disallowed_methods](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods)
|
||||
|
||||
|
||||
### disallowed-types
|
||||
The list of disallowed types, written as fully qualified paths.
|
||||
|
||||
**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
|
||||
|
||||
* [disallowed_types](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types)
|
||||
|
||||
|
||||
### unreadable-literal-lint-fractions
|
||||
Should the fraction of a decimal be linted to include separators.
|
||||
|
||||
**Default Value:** `true` (`bool`)
|
||||
|
||||
* [unreadable_literal](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal)
|
||||
|
||||
|
||||
### upper-case-acronyms-aggressive
|
||||
Enables verbose mode. Triggers if there is more than one uppercase char next to each other
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
|
||||
|
||||
|
||||
### matches-for-let-else
|
||||
Whether the matches should be considered by the lint, and whether there should
|
||||
be filtering for common types.
|
||||
|
||||
**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`)
|
||||
|
||||
* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
|
||||
|
||||
|
||||
### cargo-ignore-publish
|
||||
For internal testing only, ignores the current `publish` settings in the Cargo manifest.
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [_cargo_common_metadata](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata)
|
||||
|
||||
|
||||
### standard-macro-braces
|
||||
Enforce the named macros always use the braces specified.
|
||||
|
||||
A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
|
||||
is could be used with a full path two `MacroMatcher`s have to be added one with the full path
|
||||
`crate_name::macro_name` and one with just the macro name.
|
||||
|
||||
**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`)
|
||||
|
||||
* [nonstandard_macro_braces](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces)
|
||||
|
||||
|
||||
### enforced-import-renames
|
||||
The list of imports to always rename, a fully qualified path followed by the rename.
|
||||
|
||||
**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`)
|
||||
|
||||
* [missing_enforced_import_renames](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames)
|
||||
|
||||
|
||||
### allowed-scripts
|
||||
The list of unicode scripts allowed to be used in the scope.
|
||||
|
||||
**Default Value:** `["Latin"]` (`Vec<String>`)
|
||||
|
||||
* [disallowed_script_idents](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents)
|
||||
|
||||
|
||||
### enable-raw-pointer-heuristic-for-send
|
||||
Whether to apply the raw pointer heuristic to determine if a type is `Send`.
|
||||
|
||||
**Default Value:** `true` (`bool`)
|
||||
|
||||
* [non_send_fields_in_send_ty](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty)
|
||||
|
||||
|
||||
### max-suggested-slice-pattern-length
|
||||
When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
|
||||
the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
|
||||
For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
|
||||
|
||||
**Default Value:** `3` (`u64`)
|
||||
|
||||
* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
|
||||
|
||||
|
||||
### max-include-file-size
|
||||
The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
|
||||
|
||||
**Default Value:** `1000000` (`u64`)
|
||||
|
||||
* [large_include_file](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file)
|
||||
|
||||
|
||||
### allow-expect-in-tests
|
||||
Whether `expect` should be allowed within `#[cfg(test)]`
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [expect_used](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used)
|
||||
|
||||
|
||||
### allow-unwrap-in-tests
|
||||
Whether `unwrap` should be allowed in test cfg
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [unwrap_used](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used)
|
||||
|
||||
|
||||
### allow-dbg-in-tests
|
||||
Whether `dbg!` should be allowed in test functions
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [dbg_macro](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro)
|
||||
|
||||
|
||||
### allow-print-in-tests
|
||||
Whether print macros (ex. `println!`) should be allowed in test functions
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [print_stdout](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout)
|
||||
* [print_stderr](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr)
|
||||
|
||||
|
||||
### large-error-threshold
|
||||
The maximum size of the `Err`-variant in a `Result` returned from a function
|
||||
|
||||
**Default Value:** `128` (`u64`)
|
||||
|
||||
* [result_large_err](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
|
||||
|
||||
|
||||
### ignore-interior-mutability
|
||||
A list of paths to types that should be treated like `Arc`, i.e. ignored but
|
||||
for the generic parameters for determining interior mutability
|
||||
|
||||
**Default Value:** `["bytes::Bytes"]` (`Vec<String>`)
|
||||
|
||||
* [mutable_key](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key)
|
||||
|
||||
|
||||
### allow-mixed-uninlined-format-args
|
||||
Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
|
||||
|
||||
**Default Value:** `true` (`bool`)
|
||||
|
||||
* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
|
||||
|
||||
|
||||
### suppress-restriction-lint-in-const
|
||||
In same
|
||||
cases the restructured operation might not be unavoidable, as the
|
||||
suggested counterparts are unavailable in constant code. This
|
||||
configuration will cause restriction lints to trigger even
|
||||
if no suggestion can be made.
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing)
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
|
||||
use clippy_utils::ty::{implements_trait, is_copy};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Lit};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
||||
|
|
@ -43,9 +44,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool {
|
|||
) && !e.span.from_expansion()
|
||||
}
|
||||
|
||||
fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(e);
|
||||
|
||||
fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
cx.tcx
|
||||
.lang_items()
|
||||
.not_trait()
|
||||
|
|
@ -77,31 +76,57 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
|
|||
return;
|
||||
}
|
||||
let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
|
||||
if !(is_bool_lit(a) ^ is_bool_lit(b)) {
|
||||
|
||||
let a_span = a.span.source_callsite();
|
||||
let b_span = b.span.source_callsite();
|
||||
|
||||
let (lit_span, non_lit_expr) = match (is_bool_lit(a), is_bool_lit(b)) {
|
||||
// assert_eq!(true, b)
|
||||
// ^^^^^^
|
||||
(true, false) => (a_span.until(b_span), b),
|
||||
// assert_eq!(a, true)
|
||||
// ^^^^^^
|
||||
(false, true) => (b_span.with_lo(a_span.hi()), a),
|
||||
// If there are two boolean arguments, we definitely don't understand
|
||||
// what's going on, so better leave things as is...
|
||||
//
|
||||
// Or there is simply no boolean and then we can leave things as is!
|
||||
return;
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
|
||||
let non_lit_ty = cx.typeck_results().expr_ty(non_lit_expr);
|
||||
|
||||
if !is_impl_not_trait_with_bool_out(cx, non_lit_ty) {
|
||||
// At this point the expression which is not a boolean
|
||||
// literal does not implement Not trait with a bool output,
|
||||
// so we cannot suggest to rewrite our code
|
||||
return;
|
||||
}
|
||||
|
||||
if !is_copy(cx, non_lit_ty) {
|
||||
// Only lint with types that are `Copy` because `assert!(x)` takes
|
||||
// ownership of `x` whereas `assert_eq(x, true)` does not
|
||||
return;
|
||||
}
|
||||
|
||||
let macro_name = macro_name.as_str();
|
||||
let non_eq_mac = ¯o_name[..macro_name.len() - 3];
|
||||
span_lint_and_sugg(
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
BOOL_ASSERT_COMPARISON,
|
||||
macro_call.span,
|
||||
&format!("used `{macro_name}!` with a literal bool"),
|
||||
"replace it with",
|
||||
format!("{non_eq_mac}!(..)"),
|
||||
Applicability::MaybeIncorrect,
|
||||
|diag| {
|
||||
// assert_eq!(...)
|
||||
// ^^^^^^^^^
|
||||
let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
|
||||
|
||||
diag.multipart_suggestion(
|
||||
format!("replace it with `{non_eq_mac}!(..)`"),
|
||||
vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ use if_chain::if_chain;
|
|||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp};
|
||||
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::sym;
|
||||
|
||||
|
|
@ -82,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
|
|||
_: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
_: Span,
|
||||
_: HirId,
|
||||
_: LocalDefId,
|
||||
) {
|
||||
NonminimalBoolVisitor { cx }.visit_body(body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
|||
&& let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
|
||||
&& method_name.ident.name == rustc_span::sym::as_ptr
|
||||
&& let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
|
||||
&& let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did)
|
||||
&& let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).subst_identity()
|
||||
&& let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
|
||||
&& let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
|
||||
&& let Some(recv) = snippet_opt(cx, receiver.span)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::expr_or_init;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, FloatTy, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::IntegerType;
|
||||
|
||||
use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
|
||||
|
|
@ -74,7 +77,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
cast_expr: &Expr<'_>,
|
||||
cast_from: Ty<'_>,
|
||||
cast_to: Ty<'_>,
|
||||
cast_to_span: Span,
|
||||
) {
|
||||
let msg = match (cast_from.kind(), cast_to.is_integral()) {
|
||||
(ty::Int(_) | ty::Uint(_), true) => {
|
||||
let from_nbits = apply_reductions(
|
||||
|
|
@ -139,7 +149,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
|||
);
|
||||
return;
|
||||
}
|
||||
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
|
||||
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
|
||||
},
|
||||
|
||||
(ty::Float(_), true) => {
|
||||
|
|
@ -153,5 +163,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
|||
_ => return,
|
||||
};
|
||||
|
||||
span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg);
|
||||
let name_of_cast_from = snippet(cx, cast_expr.span, "..");
|
||||
let cast_to_snip = snippet(cx, cast_to_span, "..");
|
||||
let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
|
||||
|
||||
span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
|
||||
diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...");
|
||||
diag.span_suggestion_with_style(
|
||||
expr.span,
|
||||
"... or use `try_from` and handle the error accordingly",
|
||||
suggestion,
|
||||
Applicability::Unspecified,
|
||||
// always show the suggestion in a separate line
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ declare_clippy_lint! {
|
|||
/// ### What it does
|
||||
/// Checks for casts between numerical types that may
|
||||
/// truncate large values. This is expected behavior, so the cast is `Allow` by
|
||||
/// default.
|
||||
/// default. It suggests user either explicitly ignore the lint,
|
||||
/// or use `try_from()` and handle the truncation, default, or panic explicitly.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// In some problem domains, it is good practice to avoid
|
||||
|
|
@ -93,6 +94,21 @@ declare_clippy_lint! {
|
|||
/// x as u8
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```
|
||||
/// fn as_u8(x: u64) -> u8 {
|
||||
/// if let Ok(x) = u8::try_from(x) {
|
||||
/// x
|
||||
/// } else {
|
||||
/// todo!();
|
||||
/// }
|
||||
/// }
|
||||
/// // Or
|
||||
/// #[allow(clippy::cast_possible_truncation)]
|
||||
/// fn as_u16(x: u64) -> u16 {
|
||||
/// x as u16
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub CAST_POSSIBLE_TRUNCATION,
|
||||
pedantic,
|
||||
|
|
@ -712,7 +728,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
|
|||
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
|
||||
if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
|
||||
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
|
||||
if cast_from.is_numeric() {
|
||||
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
|
||||
cast_precision_loss::check(cx, expr, cast_from, cast_to);
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack};
|
|||
use core::ops::ControlFlow;
|
||||
use rustc_ast::ast::Attribute;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::{sym, BytePos};
|
||||
|
||||
|
|
@ -140,9 +141,8 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
|
|||
decl: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let def_id = cx.tcx.hir().local_def_id(hir_id);
|
||||
if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
|
||||
let expr = if is_async_fn(kind) {
|
||||
match get_async_fn_body(cx.tcx, body) {
|
||||
|
|
|
|||
|
|
@ -422,6 +422,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::module_style::MOD_MODULE_FILES_INFO,
|
||||
crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
|
||||
crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
|
||||
crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO,
|
||||
crate::mut_key::MUTABLE_KEY_TYPE_INFO,
|
||||
crate::mut_mut::MUT_MUT_INFO,
|
||||
crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
|||
|
||||
ExprKind::MethodCall(_, receiver, args, _) => {
|
||||
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||
let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
|
||||
let fn_sig = self.cx.tcx.fn_sig(def_id).subst_identity().skip_binder();
|
||||
for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
|
||||
self.ty_bounds.push((*bound).into());
|
||||
self.visit_expr(expr);
|
||||
|
|
@ -215,7 +215,7 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
|
|||
let node_ty = cx.typeck_results().node_type_opt(hir_id)?;
|
||||
// We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs.
|
||||
match node_ty.kind() {
|
||||
ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id)),
|
||||
ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).subst_identity()),
|
||||
ty::FnPtr(fn_sig) => Some(*fn_sig),
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ fn walk_parents<'tcx>(
|
|||
}) if span.ctxt() == ctxt => {
|
||||
let output = cx
|
||||
.tcx
|
||||
.erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).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))
|
||||
},
|
||||
|
||||
|
|
@ -778,20 +778,20 @@ fn walk_parents<'tcx>(
|
|||
|
||||
Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
|
||||
ExprKind::Ret(_) => {
|
||||
let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
|
||||
let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap());
|
||||
Some(
|
||||
if let Node::Expr(
|
||||
closure_expr @ Expr {
|
||||
kind: ExprKind::Closure(closure),
|
||||
..
|
||||
},
|
||||
) = cx.tcx.hir().get(owner_id)
|
||||
) = cx.tcx.hir().get_by_def_id(owner_id)
|
||||
{
|
||||
closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
|
||||
} else {
|
||||
let output = cx
|
||||
.tcx
|
||||
.erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).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)
|
||||
},
|
||||
)
|
||||
|
|
@ -858,7 +858,7 @@ fn walk_parents<'tcx>(
|
|||
&& let subs = cx
|
||||
.typeck_results()
|
||||
.node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
|
||||
&& let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
|
||||
&& let impl_ty = if cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[0].is_ref() {
|
||||
// Trait methods taking `&self`
|
||||
sub_ty
|
||||
} else {
|
||||
|
|
@ -879,7 +879,7 @@ fn walk_parents<'tcx>(
|
|||
return Some(Position::MethodReceiver);
|
||||
}
|
||||
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
|
||||
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
|
||||
let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i + 1];
|
||||
// `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
|
||||
if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
|
||||
|
|
@ -896,7 +896,7 @@ fn walk_parents<'tcx>(
|
|||
} else {
|
||||
ty_auto_deref_stability(
|
||||
cx,
|
||||
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
|
||||
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().input(i + 1)),
|
||||
precedence,
|
||||
)
|
||||
.position_for_arg()
|
||||
|
|
@ -1093,7 +1093,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
|
|||
let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
|
||||
|
||||
let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
|
||||
let substs_with_expr_ty = cx
|
||||
.typeck_results()
|
||||
.node_substs(if let ExprKind::Call(callee, _) = parent.kind {
|
||||
|
|
@ -1221,7 +1221,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
|
|||
.in_definition_order()
|
||||
.any(|assoc_item| {
|
||||
if assoc_item.fn_has_self_parameter {
|
||||
let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0];
|
||||
let self_ty = cx.tcx.fn_sig(assoc_item.def_id).subst_identity().skip_binder().inputs()[0];
|
||||
matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
|
||||
} else {
|
||||
false
|
||||
|
|
@ -1419,6 +1419,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
|
|||
| ty::FnDef(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
|
||||
use rustc_hir::{
|
||||
self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, UnsafeSource,
|
||||
self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource,
|
||||
Unsafety,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -18,6 +18,7 @@ use rustc_middle::ty::{
|
|||
TraitPredicate, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::sym;
|
||||
|
||||
|
|
@ -425,7 +426,7 @@ struct UnsafeVisitor<'a, 'tcx> {
|
|||
impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: HirId) {
|
||||
fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
|
||||
if self.has_unsafe {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ use rustc_parse::maybe_new_parser_from_source_str;
|
|||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span};
|
||||
use rustc_span::{sym, FileName, Pos};
|
||||
|
|
@ -251,7 +250,7 @@ declare_clippy_lint! {
|
|||
/// unimplemented!();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub UNNECESSARY_SAFETY_DOC,
|
||||
restriction,
|
||||
"`pub fn` or `pub trait` with `# Safety` docs"
|
||||
|
|
@ -302,7 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(body.value);
|
||||
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
|
||||
lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
},
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
|
|
@ -338,7 +337,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
|
||||
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
|
||||
if !in_external_macro(cx.tcx.sess, item.span) {
|
||||
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, None, None);
|
||||
lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -357,20 +356,20 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(body.value);
|
||||
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
|
||||
lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_for_missing_headers(
|
||||
cx: &LateContext<'_>,
|
||||
def_id: LocalDefId,
|
||||
owner_id: hir::OwnerId,
|
||||
sig: &hir::FnSig<'_>,
|
||||
headers: DocHeaders,
|
||||
body_id: Option<hir::BodyId>,
|
||||
panic_span: Option<Span>,
|
||||
) {
|
||||
if !cx.effective_visibilities.is_exported(def_id) {
|
||||
if !cx.effective_visibilities.is_exported(owner_id.def_id) {
|
||||
return; // Private functions do not require doc comments
|
||||
}
|
||||
|
||||
|
|
@ -378,13 +377,13 @@ fn lint_for_missing_headers(
|
|||
if cx
|
||||
.tcx
|
||||
.hir()
|
||||
.parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
|
||||
.parent_iter(owner_id.into())
|
||||
.any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let span = cx.tcx.def_span(def_id);
|
||||
let span = cx.tcx.def_span(owner_id);
|
||||
match (headers.safety, sig.header.unsafety) {
|
||||
(false, hir::Unsafety::Unsafe) => span_lint(
|
||||
cx,
|
||||
|
|
@ -411,8 +410,7 @@ fn lint_for_missing_headers(
|
|||
);
|
||||
}
|
||||
if !headers.errors {
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
|
||||
span_lint(
|
||||
cx,
|
||||
MISSING_ERRORS_DOC,
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ impl LateLintPass<'_> for EnumVariantNames {
|
|||
Some(c) if is_word_beginning(c) => span_lint(
|
||||
cx,
|
||||
MODULE_NAME_REPETITIONS,
|
||||
item.span,
|
||||
item.ident.span,
|
||||
"item name starts with its containing module's name",
|
||||
),
|
||||
_ => (),
|
||||
|
|
@ -287,7 +287,7 @@ impl LateLintPass<'_> for EnumVariantNames {
|
|||
span_lint(
|
||||
cx,
|
||||
MODULE_NAME_REPETITIONS,
|
||||
item.span,
|
||||
item.ident.span,
|
||||
"item name ends with its containing module's name",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_middle::mir::FakeReadCause;
|
|||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, TraitRef, Ty};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
|
@ -63,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
_: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
_: Span,
|
||||
hir_id: HirId,
|
||||
fn_def_id: LocalDefId,
|
||||
) {
|
||||
if let Some(header) = fn_kind.header() {
|
||||
if header.abi != Abi::Rust {
|
||||
|
|
@ -71,7 +72,11 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
}
|
||||
}
|
||||
|
||||
let parent_id = cx.tcx.hir().get_parent_item(hir_id).def_id;
|
||||
let parent_id = cx
|
||||
.tcx
|
||||
.hir()
|
||||
.get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(fn_def_id))
|
||||
.def_id;
|
||||
let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
|
||||
|
||||
let mut trait_self_ty = None;
|
||||
|
|
@ -84,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
// find `self` ty for this trait if relevant
|
||||
if let ItemKind::Trait(_, _, _, _, items) = item.kind {
|
||||
for trait_item in items {
|
||||
if trait_item.id.hir_id() == hir_id {
|
||||
if trait_item.id.owner_id.def_id == fn_def_id {
|
||||
// be sure we have `self` parameter in this function
|
||||
if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
|
||||
trait_self_ty = Some(
|
||||
|
|
@ -105,7 +110,6 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
too_large_for_stack: self.too_large_for_stack,
|
||||
};
|
||||
|
||||
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
|
||||
let infcx = cx.tcx.infer_ctxt().build();
|
||||
ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl, HirId, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
|
||||
use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -168,8 +169,9 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
|||
fn_decl: &'tcx FnDecl<'tcx>,
|
||||
_: &'tcx Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
if let Some(fn_header) = fn_kind.header()
|
||||
&& fn_header.abi == Abi::Rust
|
||||
&& get_parent_as_impl(cx.tcx, hir_id)
|
||||
|
|
|
|||
|
|
@ -79,8 +79,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
|
|||
then {
|
||||
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
|
||||
if v.fields().iter().any(|f| {
|
||||
let def_id = cx.tcx.hir().local_def_id(f.hir_id);
|
||||
!cx.tcx.visibility(def_id).is_public()
|
||||
!cx.tcx.visibility(f.def_id).is_public()
|
||||
}) {
|
||||
// skip structs with private fields
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ use clippy_utils::macros::{
|
|||
};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_errors::{
|
||||
Applicability,
|
||||
SuggestionStyle::{CompletelyHidden, ShowCode},
|
||||
};
|
||||
use rustc_hir::{Expr, ExprKind, HirId, QPath};
|
||||
use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
||||
use rustc_middle::ty::Ty;
|
||||
|
|
@ -237,7 +237,7 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
|
|||
);
|
||||
}
|
||||
|
||||
if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() {
|
||||
if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNUSED_FORMAT_SPECS,
|
||||
|
|
@ -311,6 +311,10 @@ fn check_uninlined_args(
|
|||
// in those cases, make the code suggestion hidden
|
||||
let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span));
|
||||
|
||||
// Suggest removing each argument only once, for example in `format!("{0} {0}", arg)`.
|
||||
fixes.sort_unstable_by_key(|(span, _)| *span);
|
||||
fixes.dedup_by_key(|(span, _)| *span);
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNINLINED_FORMAT_ARGS,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ declare_clippy_lint! {
|
|||
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
|
||||
/// ```
|
||||
///
|
||||
#[clippy::version = "1.66.0"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub FROM_RAW_WITH_VOID_PTR,
|
||||
suspicious,
|
||||
"creating a `Box` from a void raw pointer"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, HirId, ImplicitSelfKind, Unsafety};
|
||||
use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -16,7 +16,6 @@ pub fn check_fn(
|
|||
decl: &FnDecl<'_>,
|
||||
body: &Body<'_>,
|
||||
span: Span,
|
||||
_hir_id: HirId,
|
||||
) {
|
||||
let FnKind::Method(ref ident, sig) = kind else {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::intravisit;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -363,12 +364,13 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
|
|||
decl: &'tcx hir::FnDecl<'_>,
|
||||
body: &'tcx hir::Body<'_>,
|
||||
span: Span,
|
||||
hir_id: hir::HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_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, hir_id);
|
||||
misnamed_getters::check_fn(cx, kind, decl, body, span, hir_id);
|
||||
not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
|
||||
misnamed_getters::check_fn(cx, kind, decl, body, span);
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_ast::ast::Attribute;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::{DefIdSet, LocalDefId};
|
||||
use rustc_hir::def_id::DefIdSet;
|
||||
use rustc_hir::{self as hir, def::Res, QPath};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::{
|
||||
|
|
@ -27,14 +27,14 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
|
|||
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
|
||||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
if let Some(attr) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
||||
} else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
|
||||
check_must_use_candidate(
|
||||
cx,
|
||||
sig.decl,
|
||||
cx.tcx.hir().body(*body_id),
|
||||
item.span,
|
||||
item.owner_id.def_id,
|
||||
item.owner_id,
|
||||
item.span.with_hi(sig.decl.output.span().hi()),
|
||||
"this function could have a `#[must_use]` attribute",
|
||||
);
|
||||
|
|
@ -49,7 +49,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
|
|||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
|
||||
if let Some(attr) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
||||
} else if is_public
|
||||
&& !is_proc_macro(cx.sess(), attrs)
|
||||
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
||||
|
|
@ -59,7 +59,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
|
|||
sig.decl,
|
||||
cx.tcx.hir().body(*body_id),
|
||||
item.span,
|
||||
item.owner_id.def_id,
|
||||
item.owner_id,
|
||||
item.span.with_hi(sig.decl.output.span().hi()),
|
||||
"this method could have a `#[must_use]` attribute",
|
||||
);
|
||||
|
|
@ -75,7 +75,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
|
|||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
|
||||
if let Some(attr) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
|
||||
} else if let hir::TraitFn::Provided(eid) = *eid {
|
||||
let body = cx.tcx.hir().body(eid);
|
||||
if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
|
||||
|
|
@ -84,7 +84,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
|
|||
sig.decl,
|
||||
body,
|
||||
item.span,
|
||||
item.owner_id.def_id,
|
||||
item.owner_id,
|
||||
item.span.with_hi(sig.decl.output.span().hi()),
|
||||
"this method could have a `#[must_use]` attribute",
|
||||
);
|
||||
|
|
@ -96,7 +96,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
|
|||
fn check_needless_must_use(
|
||||
cx: &LateContext<'_>,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
item_id: hir::HirId,
|
||||
item_id: hir::OwnerId,
|
||||
item_span: Span,
|
||||
fn_header_span: Span,
|
||||
attr: &Attribute,
|
||||
|
|
@ -131,7 +131,7 @@ fn check_must_use_candidate<'tcx>(
|
|||
decl: &'tcx hir::FnDecl<'_>,
|
||||
body: &'tcx hir::Body<'_>,
|
||||
item_span: Span,
|
||||
item_id: LocalDefId,
|
||||
item_id: hir::OwnerId,
|
||||
fn_span: Span,
|
||||
msg: &str,
|
||||
) {
|
||||
|
|
@ -139,8 +139,8 @@ fn check_must_use_candidate<'tcx>(
|
|||
|| mutates_static(cx, body)
|
||||
|| in_external_macro(cx.sess(), item_span)
|
||||
|| returns_unit(decl)
|
||||
|| !cx.effective_visibilities.is_exported(item_id)
|
||||
|| is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id)))
|
||||
|| !cx.effective_visibilities.is_exported(item_id.def_id)
|
||||
|| is_must_use_ty(cx, return_ty(cx, item_id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub(super) fn check_fn<'tcx>(
|
|||
kind: intravisit::FnKind<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
hir_id: hir::HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let unsafety = match kind {
|
||||
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety,
|
||||
|
|
@ -25,7 +25,7 @@ pub(super) fn check_fn<'tcx>(
|
|||
intravisit::FnKind::Closure => return,
|
||||
};
|
||||
|
||||
check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
|
||||
check_raw_ptr(cx, unsafety, decl, body, def_id)
|
||||
}
|
||||
|
||||
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
|
|
@ -58,7 +58,7 @@ fn check_raw_ptr<'tcx>(
|
|||
},
|
||||
hir::ExprKind::MethodCall(_, recv, args, _) => {
|
||||
let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap();
|
||||
if cx.tcx.fn_sig(def_id).skip_binder().unsafety == hir::Unsafety::Unsafe {
|
||||
if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().unsafety == hir::Unsafety::Unsafe {
|
||||
check_arg(cx, &raw_ptrs, recv);
|
||||
for arg in args {
|
||||
check_arg(cx, &raw_ptrs, arg);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fn result_err_ty<'tcx>(
|
|||
) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
|
||||
if !in_external_macro(cx.sess(), item_span)
|
||||
&& let hir::FnRetTy::Return(hir_ty) = decl.output
|
||||
&& let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output())
|
||||
&& let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().output())
|
||||
&& is_type_diagnostic_item(cx, ty, sym::Result)
|
||||
&& let ty::Adt(_, substs) = ty.kind()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::return_ty;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl, HirId};
|
||||
use rustc_hir::{Body, FnDecl};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, FulfillmentError};
|
||||
|
|
@ -56,12 +57,12 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
|||
decl: &'tcx FnDecl<'tcx>,
|
||||
_: &'tcx Body<'tcx>,
|
||||
_: Span,
|
||||
hir_id: HirId,
|
||||
fn_def_id: LocalDefId,
|
||||
) {
|
||||
if let FnKind::Closure = kind {
|
||||
return;
|
||||
}
|
||||
let ret_ty = return_ty(cx, hir_id);
|
||||
let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner());
|
||||
if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
|
||||
let preds = cx.tcx.explicit_item_bounds(def_id);
|
||||
let mut is_future = false;
|
||||
|
|
@ -78,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
|||
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
|
||||
let span = decl.output.span();
|
||||
let infcx = cx.tcx.infer_ctxt().build();
|
||||
let cause = traits::ObligationCause::misc(span, hir_id);
|
||||
let cause = traits::ObligationCause::misc(span, fn_def_id);
|
||||
let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait);
|
||||
if !send_errors.is_empty() {
|
||||
span_lint_and_then(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
|
|||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Span, SyntaxContext};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -223,7 +224,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
|
|||
decl: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
span: Span,
|
||||
_: HirId,
|
||||
_: LocalDefId,
|
||||
) {
|
||||
if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
|
||||
|| span.ctxt() != body.value.span.ctxt()
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
|
|||
if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
|
||||
|
||||
// Check if return type is String
|
||||
if is_type_lang_item(cx, return_ty(cx, impl_item.hir_id()), LangItem::String);
|
||||
if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String);
|
||||
|
||||
// Filters instances of to_string which are required by a trait
|
||||
if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
|
||||
|
|
@ -124,7 +124,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
|
|||
.expect("Failed to get trait ID of `Display`!");
|
||||
|
||||
// Get the real type of 'self'
|
||||
let self_type = cx.tcx.fn_sig(item.owner_id).input(0);
|
||||
let self_type = cx.tcx.fn_sig(item.owner_id).skip_binder().input(0);
|
||||
let self_type = self_type.skip_binder().peel_refs();
|
||||
|
||||
// Emit either a warning or an error
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// [`Duration`]: std::time::Duration
|
||||
/// [`Instant::now()`]: std::time::Instant::now;
|
||||
#[clippy::version = "1.65.0"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub UNCHECKED_DURATION_SUBTRACTION,
|
||||
pedantic,
|
||||
"finds unchecked subtraction of a 'Duration' from an 'Instant'"
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
|
|||
|
||||
fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
|
||||
if sig.decl.implicit_self.has_implicit_self() {
|
||||
let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).output());
|
||||
let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output());
|
||||
let ret_ty = cx
|
||||
.tcx
|
||||
.try_normalize_erasing_regions(cx.param_env, ret_ty)
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
|
|||
if let Some(local_id) = ty_id.as_local();
|
||||
let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
|
||||
if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
|
||||
if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder());
|
||||
if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder());
|
||||
then {
|
||||
let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
|
||||
Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
|
||||
|
|
@ -196,7 +196,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
|
|||
fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
|
||||
item.ident.name == name
|
||||
&& if let AssocItemKind::Fn { has_self } = item.kind {
|
||||
has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 }
|
||||
has_self && { cx.tcx.fn_sig(item.id.owner_id).skip_binder().inputs().skip_binder().len() == 1 }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
|
|||
.any(|i| {
|
||||
i.kind == ty::AssocKind::Fn
|
||||
&& i.fn_has_self_parameter
|
||||
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
|
||||
&& cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1
|
||||
});
|
||||
|
||||
if !is_empty_method_found {
|
||||
|
|
@ -342,7 +342,7 @@ fn check_for_is_empty<'tcx>(
|
|||
),
|
||||
Some(is_empty)
|
||||
if !(is_empty.fn_has_self_parameter
|
||||
&& check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
|
||||
&& check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(), self_kind, output)) =>
|
||||
{
|
||||
(
|
||||
format!(
|
||||
|
|
@ -473,7 +473,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
|||
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
|
||||
fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
|
||||
if item.kind == ty::AssocKind::Fn {
|
||||
let sig = cx.tcx.fn_sig(item.def_id);
|
||||
let sig = cx.tcx.fn_sig(item.def_id).skip_binder();
|
||||
let ty = sig.skip_binder();
|
||||
ty.inputs().len() == 1
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ declare_clippy_lint! {
|
|||
/// let _ = foo().await;
|
||||
/// # }
|
||||
/// ```
|
||||
#[clippy::version = "1.66"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub LET_UNDERSCORE_FUTURE,
|
||||
suspicious,
|
||||
"non-binding `let` on a future"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(binary_heap_into_iter_sorted)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_chains)]
|
||||
|
|
@ -198,6 +197,7 @@ mod missing_trait_methods;
|
|||
mod mixed_read_write_in_expression;
|
||||
mod module_style;
|
||||
mod multi_assignments;
|
||||
mod multiple_unsafe_ops_per_block;
|
||||
mod mut_key;
|
||||
mod mut_mut;
|
||||
mod mut_reference;
|
||||
|
|
@ -908,6 +908,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
|
||||
store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
|
||||
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
|
||||
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ use rustc_hir::{
|
|||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter as middle_nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
|
|
@ -154,7 +153,7 @@ fn check_fn_inner<'tcx>(
|
|||
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
|
||||
|
||||
for typ in types {
|
||||
for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
|
||||
for pred in generics.bounds_for_param(typ.def_id) {
|
||||
if pred.origin == PredicateOrigin::WhereClause {
|
||||
// has_where_lifetimes checked that this predicate contains no lifetime.
|
||||
continue;
|
||||
|
|
@ -251,7 +250,7 @@ fn could_use_elision<'tcx>(
|
|||
// level of the current item.
|
||||
|
||||
// check named LTs
|
||||
let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
|
||||
let allowed_lts = allowed_lts_from(named_generics);
|
||||
|
||||
// these will collect all the lifetimes for references in arg/return types
|
||||
let mut input_visitor = RefVisitor::new(cx);
|
||||
|
|
@ -360,11 +359,11 @@ fn could_use_elision<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
|
||||
fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
|
||||
let mut allowed_lts = FxHashSet::default();
|
||||
for par in named_generics.iter() {
|
||||
if let GenericParamKind::Lifetime { .. } = par.kind {
|
||||
allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
|
||||
allowed_lts.insert(RefLt::Named(par.def_id));
|
||||
}
|
||||
}
|
||||
allowed_lts.insert(RefLt::Unnamed);
|
||||
|
|
@ -516,7 +515,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
|
|||
return true;
|
||||
}
|
||||
// if the bounds define new lifetimes, they are fine to occur
|
||||
let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
|
||||
let allowed_lts = allowed_lts_from(pred.bound_generic_params);
|
||||
// now walk the bounds
|
||||
for bound in pred.bounds.iter() {
|
||||
walk_param_bound(&mut visitor, bound);
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
|||
ExprKind::MethodCall(_, receiver, args, _) => {
|
||||
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
||||
for (ty, expr) in iter::zip(
|
||||
self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
|
||||
self.cx.tcx.fn_sig(def_id).subst_identity().inputs().skip_binder(),
|
||||
std::iter::once(receiver).chain(args.iter()),
|
||||
) {
|
||||
self.prefer_mutable = false;
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound,
|
||||
HirId, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
|
||||
ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
|
|||
decl: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
span: Span,
|
||||
_: HirId,
|
||||
_: LocalDefId,
|
||||
) {
|
||||
if_chain! {
|
||||
if let Some(header) = kind.header();
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ declare_clippy_lint! {
|
|||
/// 'A'.is_ascii_uppercase();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub MANUAL_IS_ASCII_CHECK,
|
||||
style,
|
||||
"use dedicated method to check ascii range"
|
||||
|
|
|
|||
|
|
@ -157,11 +157,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
|
|||
&& def.variants.len() > 1
|
||||
{
|
||||
let mut iter = def.variants.iter().filter_map(|v| {
|
||||
let id = cx.tcx.hir().local_def_id(v.hir_id);
|
||||
(matches!(v.data, hir::VariantData::Unit(..))
|
||||
(matches!(v.data, hir::VariantData::Unit(_, _))
|
||||
&& v.ident.as_str().starts_with('_')
|
||||
&& is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
|
||||
.then_some((id, v.span))
|
||||
.then_some((v.def_id, v.span))
|
||||
});
|
||||
if let Some((id, span)) = iter.next()
|
||||
&& iter.next().is_none()
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
|||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
|
||||
if let ty::FnDef(id, _) = *ty.kind() {
|
||||
if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
|
||||
if let Some(fn_type) = cx.tcx.fn_sig(id).subst_identity().no_bound_vars() {
|
||||
return is_unit_type(fn_type.output());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ fn collect_replace_calls<'tcx>(
|
|||
from_args.push_front(from);
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(
|
|||
if let hir::ExprKind::Path(ref p) = fun.kind {
|
||||
match cx.qpath_res(p, fun.hir_id) {
|
||||
hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
|
||||
cx.tcx.fn_sig(def_id).output().skip_binder().kind(),
|
||||
cx.tcx.fn_sig(def_id).subst_identity().output().skip_binder().kind(),
|
||||
ty::Ref(re, ..) if re.is_static(),
|
||||
),
|
||||
_ => false,
|
||||
|
|
@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
|
|||
.type_dependent_def_id(arg.hir_id)
|
||||
.map_or(false, |method_id| {
|
||||
matches!(
|
||||
cx.tcx.fn_sig(method_id).output().skip_binder().kind(),
|
||||
cx.tcx.fn_sig(method_id).subst_identity().output().skip_binder().kind(),
|
||||
ty::Ref(re, ..) if re.is_static()
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3102,7 +3102,7 @@ declare_clippy_lint! {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub SEEK_FROM_CURRENT,
|
||||
complexity,
|
||||
"use dedicated method for seek from current position"
|
||||
|
|
@ -3133,7 +3133,7 @@ declare_clippy_lint! {
|
|||
/// t.rewind();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub SEEK_TO_START_INSTEAD_OF_REWIND,
|
||||
complexity,
|
||||
"jumping to the start of stream using `seek` method"
|
||||
|
|
@ -3352,7 +3352,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
|
||||
let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
|
||||
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
|
||||
let method_sig = cx.tcx.fn_sig(impl_item.owner_id);
|
||||
let method_sig = cx.tcx.fn_sig(impl_item.owner_id).subst_identity();
|
||||
let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
|
||||
let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
|
||||
// if this impl block implements a trait, lint in trait definition instead
|
||||
|
|
@ -3412,7 +3412,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
}
|
||||
|
||||
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
|
||||
let ret_ty = return_ty(cx, impl_item.hir_id());
|
||||
let ret_ty = return_ty(cx, impl_item.owner_id);
|
||||
|
||||
if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
|
||||
return;
|
||||
|
|
@ -3460,7 +3460,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
if_chain! {
|
||||
if item.ident.name == sym::new;
|
||||
if let TraitItemKind::Fn(_, _) = item.kind;
|
||||
let ret_ty = return_ty(cx, item.hir_id());
|
||||
let ret_ty = return_ty(cx, item.owner_id);
|
||||
let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
|
||||
.self_ty()
|
||||
.skip_binder();
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ pub(super) fn check<'tcx>(
|
|||
/// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
|
||||
fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
|
||||
cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
|
||||
let sig = cx.tcx.fn_sig(id).skip_binder();
|
||||
let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
|
||||
sig.inputs().len() == 1 && sig.output().is_bool()
|
||||
})
|
||||
}
|
||||
|
|
@ -165,7 +165,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
|
|||
fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool {
|
||||
let typeck = cx.typeck_results();
|
||||
if let Some(id) = typeck.type_dependent_def_id(call_id)
|
||||
&& let sig = cx.tcx.fn_sig(id)
|
||||
&& let sig = cx.tcx.fn_sig(id).subst_identity()
|
||||
&& sig.skip_binder().output().is_bool()
|
||||
&& let [_, search_ty] = *sig.skip_binder().inputs()
|
||||
&& let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
|
||||
|
|
|
|||
|
|
@ -11,10 +11,8 @@ use super::SUSPICIOUS_MAP;
|
|||
pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
|
||||
if_chain! {
|
||||
if is_trait_method(cx, count_recv, sym::Iterator);
|
||||
let closure = expr_or_init(cx, map_arg);
|
||||
if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id);
|
||||
if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id);
|
||||
let closure_body = cx.tcx.hir().body(body_id);
|
||||
if let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind;
|
||||
let closure_body = cx.tcx.hir().body(closure.body);
|
||||
if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
|
||||
then {
|
||||
if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ fn check_other_call_arg<'tcx>(
|
|||
if_chain! {
|
||||
if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
|
||||
if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
|
||||
if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
|
||||
if let Some(input) = fn_sig.inputs().get(i);
|
||||
let (input, n_refs) = peel_mid_ty_refs(*input);
|
||||
|
|
@ -368,10 +368,9 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
|
|||
Node::Block(..) => continue,
|
||||
Node::Item(item) => {
|
||||
if let ItemKind::Fn(_, _, body_id) = &item.kind
|
||||
&& let output_ty = return_ty(cx, item.hir_id())
|
||||
&& let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
|
||||
&& Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
|
||||
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
|
||||
&& let output_ty = return_ty(cx, item.owner_id)
|
||||
&& Inherited::build(cx.tcx, item.owner_id.def_id).enter(|inherited| {
|
||||
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.owner_id.def_id);
|
||||
fn_ctxt.can_coerce(ty, output_ty)
|
||||
}) {
|
||||
if has_lifetime(output_ty) && has_lifetime(ty) {
|
||||
|
|
@ -386,7 +385,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
|
|||
Node::Expr(parent_expr) => {
|
||||
if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
|
||||
{
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
|
||||
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
|
||||
&& let Some(param_ty) = fn_sig.inputs().get(arg_index)
|
||||
&& let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ use if_chain::if_chain;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
|
||||
Stmt, StmtKind, TyKind,
|
||||
self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, Stmt,
|
||||
StmtKind, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::{ExpnKind, Span};
|
||||
|
||||
|
|
@ -151,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
|
|||
decl: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
span: Span,
|
||||
_: HirId,
|
||||
_: LocalDefId,
|
||||
) {
|
||||
if let FnKind::Closure = k {
|
||||
// Does not apply to closures
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_ma
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
|
||||
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind};
|
||||
use rustc_hir_analysis::hir_ty_to_ty;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -91,14 +92,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
|
|||
_: &FnDecl<'_>,
|
||||
body: &Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
|
||||
return;
|
||||
}
|
||||
|
||||
let def_id = cx.tcx.hir().local_def_id(hir_id);
|
||||
|
||||
if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -132,6 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
|
|||
FnKind::Closure => return,
|
||||
}
|
||||
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
|
||||
// Const fns are not allowed as methods in a trait.
|
||||
{
|
||||
let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
|
|||
"implement the method",
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,185 @@
|
|||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_then,
|
||||
visitors::{for_each_expr_with_closures, Descend, Visitable},
|
||||
};
|
||||
use core::ops::ControlFlow::Continue;
|
||||
use hir::{
|
||||
def::{DefKind, Res},
|
||||
BlockCheckMode, ExprKind, QPath, UnOp, Unsafety,
|
||||
};
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for `unsafe` blocks that contain more than one unsafe operation.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Combined with `undocumented_unsafe_blocks`,
|
||||
/// this lint ensures that each unsafe operation must be independently justified.
|
||||
/// Combined with `unused_unsafe`, this lint also ensures
|
||||
/// elimination of unnecessary unsafe blocks through refactoring.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// /// Reads a `char` from the given pointer.
|
||||
/// ///
|
||||
/// /// # Safety
|
||||
/// ///
|
||||
/// /// `ptr` must point to four consecutive, initialized bytes which
|
||||
/// /// form a valid `char` when interpreted in the native byte order.
|
||||
/// fn read_char(ptr: *const u8) -> char {
|
||||
/// // SAFETY: The caller has guaranteed that the value pointed
|
||||
/// // to by `bytes` is a valid `char`.
|
||||
/// unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// /// Reads a `char` from the given pointer.
|
||||
/// ///
|
||||
/// /// # Safety
|
||||
/// ///
|
||||
/// /// - `ptr` must be 4-byte aligned, point to four consecutive
|
||||
/// /// initialized bytes, and be valid for reads of 4 bytes.
|
||||
/// /// - The bytes pointed to by `ptr` must represent a valid
|
||||
/// /// `char` when interpreted in the native byte order.
|
||||
/// fn read_char(ptr: *const u8) -> char {
|
||||
/// // SAFETY: `ptr` is 4-byte aligned, points to four consecutive
|
||||
/// // initialized bytes, and is valid for reads of 4 bytes.
|
||||
/// let int_value = unsafe { *ptr.cast::<u32>() };
|
||||
///
|
||||
/// // SAFETY: The caller has guaranteed that the four bytes
|
||||
/// // pointed to by `bytes` represent a valid `char`.
|
||||
/// unsafe { char::from_u32_unchecked(int_value) }
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.68.0"]
|
||||
pub MULTIPLE_UNSAFE_OPS_PER_BLOCK,
|
||||
restriction,
|
||||
"more than one unsafe operation per `unsafe` block"
|
||||
}
|
||||
declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
|
||||
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
|
||||
if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
|
||||
return;
|
||||
}
|
||||
let mut unsafe_ops = vec![];
|
||||
collect_unsafe_exprs(cx, block, &mut unsafe_ops);
|
||||
if unsafe_ops.len() > 1 {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MULTIPLE_UNSAFE_OPS_PER_BLOCK,
|
||||
block.span,
|
||||
&format!(
|
||||
"this `unsafe` block contains {} unsafe operations, expected only one",
|
||||
unsafe_ops.len()
|
||||
),
|
||||
|diag| {
|
||||
for (msg, span) in unsafe_ops {
|
||||
diag.span_note(span, msg);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_unsafe_exprs<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
node: impl Visitable<'tcx>,
|
||||
unsafe_ops: &mut Vec<(&'static str, Span)>,
|
||||
) {
|
||||
for_each_expr_with_closures(cx, node, |expr| {
|
||||
match expr.kind {
|
||||
ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)),
|
||||
|
||||
ExprKind::Field(e, _) => {
|
||||
if cx.typeck_results().expr_ty(e).is_union() {
|
||||
unsafe_ops.push(("union field access occurs here", expr.span));
|
||||
}
|
||||
},
|
||||
|
||||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::Def(DefKind::Static(Mutability::Mut), _),
|
||||
..
|
||||
},
|
||||
)) => {
|
||||
unsafe_ops.push(("access of a mutable static occurs here", expr.span));
|
||||
},
|
||||
|
||||
ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_unsafe_ptr() => {
|
||||
unsafe_ops.push(("raw pointer dereference occurs here", expr.span));
|
||||
},
|
||||
|
||||
ExprKind::Call(path_expr, _) => match path_expr.kind {
|
||||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::Def(kind, def_id),
|
||||
..
|
||||
},
|
||||
)) if kind.is_fn_like() => {
|
||||
let sig = cx.tcx.fn_sig(*def_id);
|
||||
if sig.0.unsafety() == Unsafety::Unsafe {
|
||||
unsafe_ops.push(("unsafe function call occurs here", expr.span));
|
||||
}
|
||||
},
|
||||
|
||||
ExprKind::Path(QPath::TypeRelative(..)) => {
|
||||
if let Some(sig) = cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(path_expr.hir_id)
|
||||
.map(|def_id| cx.tcx.fn_sig(def_id))
|
||||
{
|
||||
if sig.0.unsafety() == Unsafety::Unsafe {
|
||||
unsafe_ops.push(("unsafe function call occurs here", expr.span));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_ => {},
|
||||
},
|
||||
|
||||
ExprKind::MethodCall(..) => {
|
||||
if let Some(sig) = cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(expr.hir_id)
|
||||
.map(|def_id| cx.tcx.fn_sig(def_id))
|
||||
{
|
||||
if sig.0.unsafety() == Unsafety::Unsafe {
|
||||
unsafe_ops.push(("unsafe method call occurs here", expr.span));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
|
||||
if matches!(
|
||||
lhs.kind,
|
||||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::Def(DefKind::Static(Mutability::Mut), _),
|
||||
..
|
||||
}
|
||||
))
|
||||
) {
|
||||
unsafe_ops.push(("modification of a mutable static occurs here", expr.span));
|
||||
collect_unsafe_exprs(cx, rhs, unsafe_ops);
|
||||
return Continue(Descend::No);
|
||||
}
|
||||
},
|
||||
|
||||
_ => {},
|
||||
};
|
||||
|
||||
Continue::<(), _>(Descend::Yes)
|
||||
});
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
|
|||
use rustc_middle::ty::TypeVisitable;
|
||||
use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::sym;
|
||||
use std::iter;
|
||||
|
|
@ -102,21 +103,21 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
|
|||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
|
||||
self.check_sig(cx, item.hir_id(), sig.decl);
|
||||
self.check_sig(cx, item.owner_id.def_id, sig.decl);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
|
||||
if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
|
||||
if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
|
||||
self.check_sig(cx, item.hir_id(), sig.decl);
|
||||
self.check_sig(cx, item.owner_id.def_id, sig.decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) {
|
||||
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
|
||||
self.check_sig(cx, item.hir_id(), sig.decl);
|
||||
self.check_sig(cx, item.owner_id.def_id, sig.decl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,9 +137,8 @@ impl MutableKeyType {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_sig(&self, cx: &LateContext<'_>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) {
|
||||
let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id);
|
||||
let fn_sig = cx.tcx.fn_sig(fn_def_id);
|
||||
fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
|
||||
let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
|
||||
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
|
||||
self.check_ty_(cx, hir_ty.span, *ty);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use rustc_lint::{LateContext, LateLintPass};
|
|||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty::{self, TypeVisitable};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
|
@ -82,12 +83,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
|||
decl: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
fn_def_id: LocalDefId,
|
||||
) {
|
||||
if span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
|
||||
|
||||
match kind {
|
||||
FnKind::ItemFn(.., header) => {
|
||||
let attrs = cx.tcx.hir().attrs(hir_id);
|
||||
|
|
@ -119,8 +122,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
|||
|
||||
let sized_trait = need!(cx.tcx.lang_items().sized_trait());
|
||||
|
||||
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
|
||||
|
||||
let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter())
|
||||
.filter(|p| !p.is_global())
|
||||
.filter_map(|obligation| {
|
||||
|
|
@ -147,7 +148,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
|||
ctx
|
||||
};
|
||||
|
||||
let fn_sig = cx.tcx.fn_sig(fn_def_id);
|
||||
let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
|
||||
let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);
|
||||
|
||||
for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||
}
|
||||
if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
|
||||
let name = impl_item.ident.name;
|
||||
let id = impl_item.hir_id();
|
||||
let id = impl_item.owner_id;
|
||||
if sig.header.constness == hir::Constness::Const {
|
||||
// can't be implemented by default
|
||||
return;
|
||||
|
|
@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||
if sig.decl.inputs.is_empty();
|
||||
if name == sym::new;
|
||||
if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
|
||||
let self_def_id = cx.tcx.hir().get_parent_item(id);
|
||||
let self_def_id = cx.tcx.hir().get_parent_item(id.into());
|
||||
let self_ty = cx.tcx.type_of(self_def_id);
|
||||
if self_ty == return_ty(cx, id);
|
||||
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
|
||||
|
|
@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||
span_lint_hir_and_then(
|
||||
cx,
|
||||
NEW_WITHOUT_DEFAULT,
|
||||
id,
|
||||
id.into(),
|
||||
impl_item.span,
|
||||
&format!(
|
||||
"you should consider adding a `Default` implementation for `{self_type_snip}`"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::hir_id::HirIdMap;
|
||||
use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::subst::{EarlyBinder, GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{self, ConstKind};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
|
|
@ -244,7 +244,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
|
|||
})) => {
|
||||
#[allow(trivial_casts)]
|
||||
if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
|
||||
&& let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(|t| t.subst_identity())
|
||||
&& let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::subst_identity)
|
||||
&& let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
|
||||
{
|
||||
(
|
||||
|
|
|
|||
|
|
@ -209,7 +209,8 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
|
|||
|
||||
fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
|
||||
let body_owner = cx.tcx.hir().body_owner(body.id());
|
||||
let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
|
||||
let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
|
||||
|
||||
let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
|
||||
if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
|
||||
let body_span = cx.tcx.hir().span_with_body(body_owner);
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ impl Context {
|
|||
|
||||
pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
|
||||
let body_owner = cx.tcx.hir().body_owner(body.id());
|
||||
let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
|
||||
let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
|
||||
|
||||
match cx.tcx.hir().body_owner_kind(body_owner_def_id) {
|
||||
hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -49,9 +50,13 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
|
|||
_: &'tcx hir::FnDecl<'tcx>,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: hir::HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
|
||||
if matches!(fn_kind, FnKind::Closure) {
|
||||
return;
|
||||
}
|
||||
let owner = cx.tcx.hir().local_def_id_to_hir_id(def_id).expect_owner();
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, owner), sym::Result) {
|
||||
lint_impl_body(cx, span, body);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
|
||||
use rustc_hir::{BindingAnnotation, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::adjustment::{Adjust, PointerCast};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
|
|
@ -143,7 +143,7 @@ impl<'tcx> PassByRefOrValue {
|
|||
return;
|
||||
}
|
||||
|
||||
let fn_sig = cx.tcx.fn_sig(def_id);
|
||||
let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
|
||||
let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));
|
||||
|
||||
// Gather all the lifetimes found in the output type which may affect whether
|
||||
|
|
@ -272,12 +272,13 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
|
|||
decl: &'tcx FnDecl<'_>,
|
||||
_body: &'tcx Body<'_>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
if span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
match kind {
|
||||
FnKind::ItemFn(.., header) => {
|
||||
if header.abi != Abi::Rust {
|
||||
|
|
@ -308,6 +309,6 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
|
|||
}
|
||||
}
|
||||
|
||||
self.check_poly_fn(cx, cx.tcx.hir().local_def_id(hir_id), decl, Some(span));
|
||||
self.check_poly_fn(cx, def_id, decl, Some(span));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_hir::{
|
||||
intravisit, Body, Expr, ExprKind, FnDecl, HirId, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -116,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
|
|||
_: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
_: Span,
|
||||
_: HirId,
|
||||
_: LocalDefId,
|
||||
) {
|
||||
for param in body.params {
|
||||
apply_lint(cx, param.pat, DerefPossible::Impossible);
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
|
|||
check_mut_from_ref(cx, sig, None);
|
||||
for arg in check_fn_args(
|
||||
cx,
|
||||
cx.tcx.fn_sig(item.owner_id).skip_binder().inputs(),
|
||||
cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(),
|
||||
sig.decl.inputs,
|
||||
&[],
|
||||
)
|
||||
|
|
@ -217,7 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
|
|||
|
||||
check_mut_from_ref(cx, sig, Some(body));
|
||||
let decl = sig.decl;
|
||||
let sig = cx.tcx.fn_sig(item_id).skip_binder();
|
||||
let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder();
|
||||
let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
|
||||
.filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
|
||||
.collect();
|
||||
|
|
@ -624,7 +624,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
|
|||
return;
|
||||
};
|
||||
|
||||
match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
|
||||
match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i].peel_refs().kind() {
|
||||
ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
|
||||
set_skip_flag();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
|
|||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{def_id, Body, FnDecl, HirId, LangItem};
|
||||
use rustc_hir::{def_id, Body, FnDecl, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::{BytePos, Span};
|
||||
use rustc_span::sym;
|
||||
|
||||
|
|
@ -69,12 +70,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
|
|||
cx: &LateContext<'tcx>,
|
||||
_: FnKind<'tcx>,
|
||||
_: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
_: &'tcx Body<'_>,
|
||||
_: Span,
|
||||
_: HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let def_id = cx.tcx.hir().body_owner_def_id(body.id());
|
||||
|
||||
// Building MIR for `fn`s with unsatisfiable preds results in ICE.
|
||||
if fn_has_unsatisfiable_preds(cx, def_id.to_def_id()) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use clippy_utils::ty::is_must_use_ty;
|
|||
use clippy_utils::{nth_arg, return_ty};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
|
||||
use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
|
@ -68,7 +68,7 @@ declare_clippy_lint! {
|
|||
|
||||
declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
|
||||
|
||||
fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
|
||||
fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) {
|
||||
if_chain! {
|
||||
// If it comes from an external macro, better ignore it.
|
||||
if !in_external_macro(cx.sess(), span);
|
||||
|
|
@ -76,10 +76,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
|
|||
// We only show this warning for public exported methods.
|
||||
if cx.effective_visibilities.is_exported(fn_def);
|
||||
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
|
||||
if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
|
||||
if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use));
|
||||
if cx.tcx.visibility(fn_def.to_def_id()).is_public();
|
||||
let ret_ty = return_ty(cx, hir_id);
|
||||
let self_arg = nth_arg(cx, hir_id, 0);
|
||||
let ret_ty = return_ty(cx, owner_id.into());
|
||||
let self_arg = nth_arg(cx, owner_id.into(), 0);
|
||||
// If `Self` has the same type as the returned type, then we want to warn.
|
||||
//
|
||||
// For this check, we don't want to remove the reference on the returned type because if
|
||||
|
|
@ -109,26 +109,26 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
|
|||
decl: &'tcx FnDecl<'tcx>,
|
||||
_: &'tcx Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
fn_def: LocalDefId,
|
||||
) {
|
||||
if_chain! {
|
||||
// We are only interested in methods, not in functions or associated functions.
|
||||
if matches!(kind, FnKind::Method(_, _));
|
||||
if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
|
||||
if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
|
||||
// We don't want this method to be te implementation of a trait because the
|
||||
// `#[must_use]` should be put on the trait definition directly.
|
||||
if cx.tcx.trait_id_of_impl(impl_def).is_none();
|
||||
|
||||
then {
|
||||
check_method(cx, decl, fn_def, span, hir_id);
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def);
|
||||
check_method(cx, decl, fn_def, span, hir_id.expect_owner());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
|
||||
if let TraitItemKind::Fn(ref sig, _) = item.kind {
|
||||
check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.hir_id());
|
||||
check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.owner_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_context};
|
||||
use clippy_utils::visitors::{for_each_expr, Descend};
|
||||
use clippy_utils::{fn_def_id, path_to_local_id};
|
||||
use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
|
||||
use core::ops::ControlFlow;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind};
|
||||
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::{BytePos, Pos};
|
||||
|
||||
|
|
@ -151,8 +152,8 @@ impl<'tcx> LateLintPass<'tcx> for Return {
|
|||
kind: FnKind<'tcx>,
|
||||
_: &'tcx FnDecl<'tcx>,
|
||||
body: &'tcx Body<'tcx>,
|
||||
_: Span,
|
||||
_: HirId,
|
||||
sp: Span,
|
||||
_: LocalDefId,
|
||||
) {
|
||||
match kind {
|
||||
FnKind::Closure => {
|
||||
|
|
@ -166,14 +167,14 @@ impl<'tcx> LateLintPass<'tcx> for Return {
|
|||
check_final_expr(cx, body.value, vec![], replacement);
|
||||
},
|
||||
FnKind::ItemFn(..) | FnKind::Method(..) => {
|
||||
check_block_return(cx, &body.value.kind, vec![]);
|
||||
check_block_return(cx, &body.value.kind, sp, vec![]);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if `expr` is a block, check if there are needless returns in it
|
||||
fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, semi_spans: Vec<Span>) {
|
||||
fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
|
||||
if let ExprKind::Block(block, _) = expr_kind {
|
||||
if let Some(block_expr) = block.expr {
|
||||
check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty);
|
||||
|
|
@ -183,12 +184,14 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>,
|
|||
check_final_expr(cx, expr, semi_spans, RetReplacement::Empty);
|
||||
},
|
||||
StmtKind::Semi(semi_expr) => {
|
||||
let mut semi_spans_and_this_one = semi_spans;
|
||||
// we only want the span containing the semicolon so we can remove it later. From `entry.rs:382`
|
||||
if let Some(semicolon_span) = stmt.span.trim_start(semi_expr.span) {
|
||||
semi_spans_and_this_one.push(semicolon_span);
|
||||
check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty);
|
||||
// Remove ending semicolons and any whitespace ' ' in between.
|
||||
// Without `return`, the suggestion might not compile if the semicolon is retained
|
||||
if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
|
||||
let semi_span_to_remove =
|
||||
span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
|
||||
semi_spans.push(semi_span_to_remove);
|
||||
}
|
||||
check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
|
@ -231,9 +234,9 @@ fn check_final_expr<'tcx>(
|
|||
emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
|
||||
},
|
||||
ExprKind::If(_, then, else_clause_opt) => {
|
||||
check_block_return(cx, &then.kind, semi_spans.clone());
|
||||
check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
|
||||
if let Some(else_clause) = else_clause_opt {
|
||||
check_block_return(cx, &else_clause.kind, semi_spans);
|
||||
check_block_return(cx, &else_clause.kind, peeled_drop_expr.span, semi_spans);
|
||||
}
|
||||
},
|
||||
// a match expr, check all arms
|
||||
|
|
@ -246,7 +249,7 @@ fn check_final_expr<'tcx>(
|
|||
}
|
||||
},
|
||||
// if it's a whole block, check it
|
||||
other_expr_kind => check_block_return(cx, other_expr_kind, semi_spans),
|
||||
other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,6 +291,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
|
|||
&& cx
|
||||
.tcx
|
||||
.fn_sig(def_id)
|
||||
.subst_identity()
|
||||
.skip_binder()
|
||||
.output()
|
||||
.walk()
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
|
|||
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
|
||||
let item = cx.tcx.hir().expect_item(parent);
|
||||
let self_ty = cx.tcx.type_of(item.owner_id);
|
||||
let ret_ty = return_ty(cx, impl_item.hir_id());
|
||||
let ret_ty = return_ty(cx, impl_item.owner_id);
|
||||
|
||||
// Do not check trait impls
|
||||
if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ declare_clippy_lint! {
|
|||
/// ### What it does
|
||||
/// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal.
|
||||
/// ### Why is this bad?
|
||||
/// It's most probably a typo and may lead to unexpected behaviours.
|
||||
/// It's most probably a typo and may lead to unexpected behaviours.
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let x = 3_i32 ^ 4_i32;
|
||||
|
|
@ -18,7 +18,7 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let x = 3_i32.pow(4);
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub SUSPICIOUS_XOR_USED_AS_POW,
|
||||
restriction,
|
||||
"XOR (`^`) operator possibly used as exponentiation operator"
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
|
|||
if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
|
||||
|
||||
// Then check if that that array zero-sized
|
||||
let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
|
||||
let length = Const::from_anon_const(cx.tcx, length_ldid);
|
||||
let length = Const::from_anon_const(cx.tcx, length.def_id);
|
||||
let length = length.try_eval_usize(cx.tcx, cx.param_env);
|
||||
if let Some(length) = length;
|
||||
then {
|
||||
|
|
|
|||
|
|
@ -479,7 +479,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
|
|||
// - char conversions (https://github.com/rust-lang/rust/issues/89259)
|
||||
let const_context = in_constant(cx, e.hir_id);
|
||||
|
||||
let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
|
||||
let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
|
||||
[] => (cx.typeck_results().expr_ty(arg), false),
|
||||
[.., a] => (a.target, true),
|
||||
};
|
||||
// Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
|
||||
let to_ty = cx.typeck_results().expr_ty(e);
|
||||
|
||||
|
|
@ -506,7 +509,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
|
|||
);
|
||||
|
||||
if !linted {
|
||||
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
|
||||
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use super::utils::can_be_expressed_as_pointer_cast;
|
||||
use super::utils::check_cast;
|
||||
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::sugg;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::{cast::CastKind, Ty};
|
||||
|
||||
/// Checks for `transmutes_expressible_as_ptr_casts` lint.
|
||||
/// Returns `true` if it's triggered, otherwise returns `false`.
|
||||
|
|
@ -13,24 +13,40 @@ pub(super) fn check<'tcx>(
|
|||
cx: &LateContext<'tcx>,
|
||||
e: &'tcx Expr<'_>,
|
||||
from_ty: Ty<'tcx>,
|
||||
from_ty_adjusted: bool,
|
||||
to_ty: Ty<'tcx>,
|
||||
arg: &'tcx Expr<'_>,
|
||||
) -> bool {
|
||||
if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
|
||||
e.span,
|
||||
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|
||||
|diag| {
|
||||
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
|
||||
let sugg = arg.as_ty(to_ty.to_string()).to_string();
|
||||
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let sugg = match check_cast(cx, e, from_ty, to_ty) {
|
||||
Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
|
||||
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
|
||||
.as_ty(to_ty.to_string())
|
||||
.to_string()
|
||||
},
|
||||
Some(PtrAddrCast) if !from_ty_adjusted => Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
|
||||
.as_ty(to_ty.to_string())
|
||||
.to_string(),
|
||||
|
||||
// The only adjustments here would be ref-to-ptr and unsize coercions. The result of an unsize coercions can't
|
||||
// be transmuted to a usize. For ref-to-ptr coercions, borrows need to be cast to a pointer before being cast to
|
||||
// a usize.
|
||||
Some(PtrAddrCast) => format!(
|
||||
"{} as {to_ty}",
|
||||
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app).as_ty(from_ty)
|
||||
),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
|
||||
e.span,
|
||||
&format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|
||||
"try",
|
||||
sugg,
|
||||
app,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,33 +20,21 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
/// Check if the type conversion can be expressed as a pointer cast, instead of
|
||||
/// a transmute. In certain cases, including some invalid casts from array
|
||||
/// references to pointers, this may cause additional errors to be emitted and/or
|
||||
/// ICE error messages. This function will panic if that occurs.
|
||||
pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
e: &'tcx Expr<'_>,
|
||||
from_ty: Ty<'tcx>,
|
||||
to_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
|
||||
matches!(
|
||||
check_cast(cx, e, from_ty, to_ty),
|
||||
Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
|
||||
)
|
||||
}
|
||||
|
||||
/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
|
||||
/// the cast. In certain cases, including some invalid casts from array references
|
||||
/// to pointers, this may cause additional errors to be emitted and/or ICE error
|
||||
/// messages. This function will panic if that occurs.
|
||||
fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
|
||||
pub(super) fn check_cast<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
e: &'tcx Expr<'_>,
|
||||
from_ty: Ty<'tcx>,
|
||||
to_ty: Ty<'tcx>,
|
||||
) -> Option<CastKind> {
|
||||
let hir_id = e.hir_id;
|
||||
let local_def_id = hir_id.owner.def_id;
|
||||
|
||||
Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
|
||||
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, hir_id);
|
||||
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, local_def_id);
|
||||
|
||||
// If we already have errors, we can't be sure we can pointer cast.
|
||||
assert!(
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ mod vec_box;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
|
||||
Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
|
||||
TraitItemKind, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -311,15 +312,27 @@ pub struct Types {
|
|||
impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Types {
|
||||
fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
|
||||
let is_in_trait_impl =
|
||||
if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id).def_id) {
|
||||
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'_>,
|
||||
_: FnKind<'_>,
|
||||
decl: &FnDecl<'_>,
|
||||
_: &Body<'_>,
|
||||
_: Span,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(
|
||||
cx.tcx
|
||||
.hir()
|
||||
.get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(def_id))
|
||||
.def_id,
|
||||
) {
|
||||
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(id));
|
||||
let is_exported = cx.effective_visibilities.is_exported(def_id);
|
||||
|
||||
self.check_fn_decl(
|
||||
cx,
|
||||
|
|
@ -381,7 +394,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
|||
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
|
||||
let is_exported = cx
|
||||
.effective_visibilities
|
||||
.is_exported(cx.tcx.hir().local_def_id(field.hir_id));
|
||||
.is_exported(field.def_id);
|
||||
|
||||
self.check_ty(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -263,6 +263,18 @@ fn expr_has_unnecessary_safety_comment<'tcx>(
|
|||
expr: &'tcx hir::Expr<'tcx>,
|
||||
comment_pos: BytePos,
|
||||
) -> Option<Span> {
|
||||
if cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, ref node)| {
|
||||
matches!(
|
||||
node,
|
||||
Node::Block(&Block {
|
||||
rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
|
||||
..
|
||||
}),
|
||||
)
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// this should roughly be the reverse of `block_parents_have_safety_comment`
|
||||
if for_each_expr_with_closures(cx, expr, |expr| match expr.kind {
|
||||
hir::ExprKind::Block(
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ fn get_projection_pred<'tcx>(
|
|||
fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
|
||||
let mut args_to_check = Vec::new();
|
||||
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||
let fn_sig = cx.tcx.fn_sig(def_id);
|
||||
let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
|
||||
let generics = cx.tcx.predicates_of(def_id);
|
||||
let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
|
||||
let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ fn needs_inferred_result_ty(
|
|||
},
|
||||
_ => return false,
|
||||
};
|
||||
let sig = cx.tcx.fn_sig(id).skip_binder();
|
||||
let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
|
||||
if let ty::Param(output_ty) = *sig.output().kind() {
|
||||
let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
|
||||
std::iter::once(receiver).chain(args.iter()).collect()
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ use if_chain::if_chain;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::LangItem::{OptionSome, ResultOk};
|
||||
use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
|
||||
use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
@ -77,12 +78,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
|||
fn_decl: &FnDecl<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
// Abort if public function/method or closure.
|
||||
match fn_kind {
|
||||
FnKind::ItemFn(..) | FnKind::Method(..) => {
|
||||
let def_id = cx.tcx.hir().local_def_id(hir_id);
|
||||
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -91,6 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
|||
}
|
||||
|
||||
// Abort if the method is implementing a trait or of it a trait method.
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
|
||||
if matches!(
|
||||
item.kind,
|
||||
|
|
@ -101,17 +102,18 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
|||
}
|
||||
|
||||
// Get the wrapper and inner types, if can't, abort.
|
||||
let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() {
|
||||
if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
|
||||
("Option", OptionSome, subst.type_at(0))
|
||||
} else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
|
||||
("Result", ResultOk, subst.type_at(0))
|
||||
let (return_type_label, lang_item, inner_type) =
|
||||
if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id.expect_owner()).kind() {
|
||||
if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
|
||||
("Option", OptionSome, subst.type_at(0))
|
||||
} else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
|
||||
("Result", ResultOk, subst.type_at(0))
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
||||
// Check if all return expression respect the following condition and collect them.
|
||||
let mut suggs = Vec::new();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, YieldSource};
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -66,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
|
|||
fn_decl: &'tcx FnDecl<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
if !span.from_expansion() && fn_kind.asyncness().is_async() {
|
||||
let mut visitor = AsyncFnVisitor { cx, found_await: false };
|
||||
walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id);
|
||||
walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
|
||||
if !visitor.found_await {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use rustc_middle::hir::nested_filter;
|
|||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::sym;
|
||||
|
||||
|
|
@ -312,7 +313,7 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap {
|
|||
decl: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
span: Span,
|
||||
fn_id: HirId,
|
||||
fn_id: LocalDefId,
|
||||
) {
|
||||
if span.from_expansion() {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
|
|||
// first check if it's a method or function
|
||||
if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind;
|
||||
// checking if its return type is `result` or `option`
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Result)
|
||||
|| is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Option);
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
|
||||
|| is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option);
|
||||
then {
|
||||
lint_impl_body(cx, impl_item.span, impl_item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
|||
.associated_item(impl_item.owner_id)
|
||||
.trait_item_def_id
|
||||
.expect("impl method matches a trait method");
|
||||
let trait_method_sig = cx.tcx.fn_sig(trait_method);
|
||||
let trait_method_sig = cx.tcx.fn_sig(trait_method).subst_identity();
|
||||
let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
|
||||
|
||||
// `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
|
||||
|
|
|
|||
|
|
@ -219,7 +219,8 @@ define_Conf! {
|
|||
///
|
||||
/// #### Noteworthy
|
||||
///
|
||||
/// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
|
||||
/// A type, say `SomeType`, listed in this configuration has the same behavior of
|
||||
/// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
|
||||
(arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
|
||||
/// Lint: ARITHMETIC_SIDE_EFFECTS.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use clippy_utils::diagnostics::span_lint;
|
|||
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
|
||||
use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{
|
||||
|
|
@ -34,8 +35,10 @@ use std::path::Path;
|
|||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
/// This is the output file of the lint collector.
|
||||
const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
|
||||
/// This is the json output file of the lint collector.
|
||||
const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
|
||||
/// This is the markdown output file of the lint collector.
|
||||
const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md";
|
||||
/// These lints are excluded from the export.
|
||||
const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"];
|
||||
/// These groups will be ignored by the lint group matcher. This is useful for collections like
|
||||
|
|
@ -176,6 +179,23 @@ This lint has the following configuration variables:
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn configs_to_markdown(&self, map_fn: fn(&ClippyConfiguration) -> String) -> String {
|
||||
self.config
|
||||
.iter()
|
||||
.filter(|config| config.deprecation_reason.is_none())
|
||||
.filter(|config| !config.lints.is_empty())
|
||||
.map(map_fn)
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
fn get_markdown_docs(&self) -> String {
|
||||
format!(
|
||||
"## Lint Configuration Options\n| <div style=\"width:290px\">Option</div> | Default Value |\n|--|--|\n{}\n\n{}\n",
|
||||
self.configs_to_markdown(ClippyConfiguration::to_markdown_table_entry),
|
||||
self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MetadataCollector {
|
||||
|
|
@ -199,12 +219,37 @@ impl Drop for MetadataCollector {
|
|||
|
||||
collect_renames(&mut lints);
|
||||
|
||||
// Outputting
|
||||
if Path::new(OUTPUT_FILE).exists() {
|
||||
fs::remove_file(OUTPUT_FILE).unwrap();
|
||||
// Outputting json
|
||||
if Path::new(JSON_OUTPUT_FILE).exists() {
|
||||
fs::remove_file(JSON_OUTPUT_FILE).unwrap();
|
||||
}
|
||||
let mut file = OpenOptions::new().write(true).create(true).open(OUTPUT_FILE).unwrap();
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(JSON_OUTPUT_FILE)
|
||||
.unwrap();
|
||||
writeln!(file, "{}", serde_json::to_string_pretty(&lints).unwrap()).unwrap();
|
||||
|
||||
// Outputting markdown
|
||||
if Path::new(MARKDOWN_OUTPUT_FILE).exists() {
|
||||
fs::remove_file(MARKDOWN_OUTPUT_FILE).unwrap();
|
||||
}
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(MARKDOWN_OUTPUT_FILE)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
file,
|
||||
"<!--
|
||||
This file is generated by `cargo collect-metadata`.
|
||||
Please use that command to update the file and do not edit it by hand.
|
||||
-->
|
||||
|
||||
{}",
|
||||
self.get_markdown_docs(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -505,6 +550,28 @@ impl ClippyConfiguration {
|
|||
deprecation_reason,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_markdown_paragraph(&self) -> String {
|
||||
format!(
|
||||
"### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
|
||||
self.name,
|
||||
self.doc
|
||||
.lines()
|
||||
.map(|line| line.strip_prefix(" ").unwrap_or(line))
|
||||
.join("\n"),
|
||||
self.default,
|
||||
self.config_type,
|
||||
self.lints
|
||||
.iter()
|
||||
.map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
|
||||
.map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
|
||||
.join("\n"),
|
||||
)
|
||||
}
|
||||
|
||||
fn to_markdown_table_entry(&self) -> String {
|
||||
format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_configs() -> Vec<ClippyConfiguration> {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
|
|||
&& subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
|
||||
{
|
||||
// Limit the function to either `(self) -> bool` or `(&self) -> bool`
|
||||
match &**cx.tcx.fn_sig(fn_id).skip_binder().inputs_and_output {
|
||||
match &**cx.tcx.fn_sig(fn_id).subst_identity().skip_binder().inputs_and_output {
|
||||
[arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange,
|
||||
_ => Lazy,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#![feature(array_chunks)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(lint_reasons)]
|
||||
#![feature(never_type)]
|
||||
|
|
@ -1119,9 +1118,8 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
|
|||
self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
|
||||
}
|
||||
},
|
||||
ExprKind::Closure { .. } => {
|
||||
let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id);
|
||||
for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) {
|
||||
ExprKind::Closure(closure) => {
|
||||
for capture in self.cx.typeck_results().closure_min_captures_flattened(closure.def_id) {
|
||||
let local_id = match capture.place.base {
|
||||
PlaceBase::Local(id) => id,
|
||||
PlaceBase::Upvar(var) => var.var_path.hir_id,
|
||||
|
|
@ -1379,7 +1377,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
|
|||
.chain(args.iter())
|
||||
.position(|arg| arg.hir_id == id)?;
|
||||
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
|
||||
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
|
||||
let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i];
|
||||
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
|
||||
},
|
||||
_ => None,
|
||||
|
|
@ -1578,16 +1576,14 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
|
|||
}
|
||||
|
||||
/// Convenience function to get the return type of a function.
|
||||
pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
|
||||
let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
|
||||
let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
|
||||
pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> {
|
||||
let ret_ty = cx.tcx.fn_sig(fn_def_id).subst_identity().output();
|
||||
cx.tcx.erase_late_bound_regions(ret_ty)
|
||||
}
|
||||
|
||||
/// Convenience function to get the nth argument type of a function.
|
||||
pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> {
|
||||
let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
|
||||
let arg = cx.tcx.fn_sig(fn_def_id).input(nth);
|
||||
pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> {
|
||||
let arg = cx.tcx.fn_sig(fn_def_id).subst_identity().input(nth);
|
||||
cx.tcx.erase_late_bound_regions(arg)
|
||||
}
|
||||
|
||||
|
|
@ -2491,6 +2487,10 @@ pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
|
|||
comments_buf.join("\n")
|
||||
}
|
||||
|
||||
pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
|
||||
sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
|
||||
}
|
||||
|
||||
macro_rules! op_utils {
|
||||
($($name:ident $assign:ident)*) => {
|
||||
/// Binary operation traits like `LangItem::Add`
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#![allow(clippy::similar_names)] // `expr` and `expn`
|
||||
|
||||
use crate::is_path_diagnostic_item;
|
||||
use crate::source::snippet_opt;
|
||||
use crate::visitors::{for_each_expr, Descend};
|
||||
|
||||
|
|
@ -8,7 +7,7 @@ use arrayvec::ArrayVec;
|
|||
use itertools::{izip, Either, Itertools};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
|
||||
use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind};
|
||||
use rustc_lexer::unescape::unescape_literal;
|
||||
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -328,7 +327,7 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
|
|||
} else {
|
||||
match cx.tcx.item_name(macro_call.def_id) {
|
||||
// `cfg!(debug_assertions)` in `debug_assert!`
|
||||
sym::cfg => ControlFlow::CONTINUE,
|
||||
sym::cfg => ControlFlow::Continue(()),
|
||||
// assert!(other_macro!(..))
|
||||
_ => ControlFlow::Break(true),
|
||||
}
|
||||
|
|
@ -439,8 +438,7 @@ impl<'tcx> FormatArgsValues<'tcx> {
|
|||
// ArgumentV1::from_usize(<val>)
|
||||
if let ExprKind::Call(callee, [val]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
|
||||
&& let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
|
||||
&& path.segments.last().unwrap().ident.name == sym::ArgumentV1
|
||||
&& let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind
|
||||
{
|
||||
let val_idx = if val.span.ctxt() == expr.span.ctxt()
|
||||
&& let ExprKind::Field(_, field) = val.kind
|
||||
|
|
@ -486,20 +484,6 @@ struct ParamPosition {
|
|||
|
||||
impl<'tcx> Visitor<'tcx> for ParamPosition {
|
||||
fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
|
||||
fn parse_count(expr: &Expr<'_>) -> Option<usize> {
|
||||
// ::core::fmt::rt::v1::Count::Param(1usize),
|
||||
if let ExprKind::Call(ctor, [val]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
|
||||
&& path.segments.last()?.ident.name == sym::Param
|
||||
&& let ExprKind::Lit(lit) = &val.kind
|
||||
&& let LitKind::Int(pos, _) = lit.node
|
||||
{
|
||||
Some(pos as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
match field.ident.name {
|
||||
sym::position => {
|
||||
if let ExprKind::Lit(lit) = &field.expr.kind
|
||||
|
|
@ -519,15 +503,41 @@ impl<'tcx> Visitor<'tcx> for ParamPosition {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_count(expr: &Expr<'_>) -> Option<usize> {
|
||||
// <::core::fmt::rt::v1::Count>::Param(1usize),
|
||||
if let ExprKind::Call(ctor, [val]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind
|
||||
&& path.ident.name == sym::Param
|
||||
&& let ExprKind::Lit(lit) = &val.kind
|
||||
&& let LitKind::Int(pos, _) = lit.node
|
||||
{
|
||||
Some(pos as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
|
||||
fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
|
||||
if let ExprKind::AddrOf(.., array) = fmt_arg.kind
|
||||
&& let ExprKind::Array(specs) = array.kind
|
||||
{
|
||||
Some(specs.iter().map(|spec| {
|
||||
let mut position = ParamPosition::default();
|
||||
position.visit_expr(spec);
|
||||
position
|
||||
if let ExprKind::Call(f, args) = spec.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind
|
||||
&& let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind
|
||||
&& f.ident.name == sym::new
|
||||
&& let [position, _fill, _align, _flags, precision, width] = args
|
||||
&& let ExprKind::Lit(position) = &position.kind
|
||||
&& let LitKind::Int(position, _) = position.node {
|
||||
ParamPosition {
|
||||
value: position as usize,
|
||||
width: parse_count(width),
|
||||
precision: parse_count(precision),
|
||||
}
|
||||
} else {
|
||||
ParamPosition::default()
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -701,8 +711,8 @@ pub struct FormatSpec<'tcx> {
|
|||
pub fill: Option<char>,
|
||||
/// Optionally specified alignment.
|
||||
pub align: Alignment,
|
||||
/// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
|
||||
pub flags: u32,
|
||||
/// Whether all flag options are set to default (no flags specified).
|
||||
pub no_flags: bool,
|
||||
/// Represents either the maximum width or the integer precision.
|
||||
pub precision: Count<'tcx>,
|
||||
/// The minimum width, will be padded according to `width`/`align`
|
||||
|
|
@ -718,7 +728,7 @@ impl<'tcx> FormatSpec<'tcx> {
|
|||
Some(Self {
|
||||
fill: spec.fill,
|
||||
align: spec.align,
|
||||
flags: spec.flags,
|
||||
no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(),
|
||||
precision: Count::new(
|
||||
FormatParamUsage::Precision,
|
||||
spec.precision,
|
||||
|
|
@ -763,7 +773,7 @@ impl<'tcx> FormatSpec<'tcx> {
|
|||
self.width.is_implied()
|
||||
&& self.precision.is_implied()
|
||||
&& self.align == Alignment::AlignUnknown
|
||||
&& self.flags == 0
|
||||
&& self.no_flags
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -890,7 +900,7 @@ impl<'tcx> FormatArgsExpn<'tcx> {
|
|||
// ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
|
||||
if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
|
||||
&& is_path_diagnostic_item(cx, ty, sym::Arguments)
|
||||
&& let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind
|
||||
&& matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
|
||||
{
|
||||
let format_string = FormatString::new(cx, pieces)?;
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ impl TypeVisitor<'_> for ContainsRegion {
|
|||
type BreakTy = ();
|
||||
|
||||
fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
|
||||
ControlFlow::BREAK
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
|
|||
// impl trait is gone in MIR, so check the return type manually
|
||||
check_ty(
|
||||
tcx,
|
||||
tcx.fn_sig(def_id).output().skip_binder(),
|
||||
tcx.fn_sig(def_id).subst_identity().output().skip_binder(),
|
||||
body.local_decls.iter().next().unwrap().source_info.span,
|
||||
)?;
|
||||
|
||||
|
|
@ -240,6 +240,7 @@ fn check_statement<'tcx>(
|
|||
| StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => Ok(()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ impl<'a> Sugg<'a> {
|
|||
| ast::ExprKind::Repeat(..)
|
||||
| ast::ExprKind::Ret(..)
|
||||
| ast::ExprKind::Yeet(..)
|
||||
| ast::ExprKind::FormatArgs(..)
|
||||
| ast::ExprKind::Struct(..)
|
||||
| ast::ExprKind::Try(..)
|
||||
| ast::ExprKind::TryBlock(..)
|
||||
|
|
@ -808,7 +809,7 @@ pub struct DerefClosure {
|
|||
///
|
||||
/// note: this only works on single line immutable closures with exactly one input parameter.
|
||||
pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option<DerefClosure> {
|
||||
if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind {
|
||||
if let hir::ExprKind::Closure(&Closure { fn_decl, def_id, body, .. }) = closure.kind {
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
// is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
|
||||
// a type annotation is present if param `kind` is different from `TyKind::Infer`
|
||||
|
|
@ -828,10 +829,8 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti
|
|||
applicability: Applicability::MachineApplicable,
|
||||
};
|
||||
|
||||
let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
|
||||
let infcx = cx.tcx.infer_ctxt().build();
|
||||
ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
|
||||
.consume_body(closure_body);
|
||||
ExprUseVisitor::new(&mut visitor, &infcx, def_id, cx.param_env, cx.typeck_results()).consume_body(closure_body);
|
||||
|
||||
if !visitor.suggestion_start.is_empty() {
|
||||
return Some(DerefClosure {
|
||||
|
|
@ -884,7 +883,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
|
|||
.cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(parent_expr.hir_id)
|
||||
.map(|did| self.cx.tcx.fn_sig(did).skip_binder())
|
||||
.map(|did| self.cx.tcx.fn_sig(did).subst_identity().skip_binder())
|
||||
{
|
||||
std::iter::once(receiver)
|
||||
.chain(call_args.iter())
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ impl<'tcx> ExprFnSig<'tcx> {
|
|||
/// If the expression is function like, get the signature for it.
|
||||
pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
|
||||
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
|
||||
Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id)))
|
||||
Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst_identity(), Some(id)))
|
||||
} else {
|
||||
ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
|
||||
}
|
||||
|
|
@ -646,10 +646,13 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
|
|||
.and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)));
|
||||
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
|
||||
},
|
||||
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), cx.tcx.opt_parent(def_id))
|
||||
},
|
||||
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs), Some(id))),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
|
||||
cx,
|
||||
ty,
|
||||
cx.tcx.item_bounds(def_id).subst(cx.tcx, substs),
|
||||
cx.tcx.opt_parent(def_id),
|
||||
),
|
||||
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
|
||||
ty::Dynamic(bounds, _, _) => {
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
|
|
|
|||
|
|
@ -392,12 +392,12 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
|
|||
.cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(e.hir_id)
|
||||
.map_or(false, |id| self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe) =>
|
||||
.map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe) =>
|
||||
{
|
||||
self.is_unsafe = true;
|
||||
},
|
||||
ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
|
||||
ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
|
||||
ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
|
||||
ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
|
||||
_ => walk_expr(self, e),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2023-01-12"
|
||||
channel = "nightly-2023-01-27"
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ with:
|
|||
-D --deny OPT Set lint denied
|
||||
-F --forbid OPT Set lint forbidden
|
||||
|
||||
You can use tool lints to allow or deny lints from your code, eg.:
|
||||
You can use tool lints to allow or deny lints from your code, e.g.:
|
||||
|
||||
#[allow(clippy::needless_lifetimes)]
|
||||
"#;
|
||||
|
|
|
|||
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