mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-21 20:23:12 +00:00
Merge commit 'f4850f7292efa33759b4f7f9b7621268979e9914' into clippyup
This commit is contained in:
parent
3597ed5a09
commit
46c5a5d234
895 changed files with 8247 additions and 18379 deletions
159
CHANGELOG.md
159
CHANGELOG.md
|
@ -4,13 +4,157 @@ All notable changes to this project will be documented in this file.
|
|||
See [Changelog Update](book/src/development/infrastructure/changelog_update.md) if you want to update this
|
||||
document.
|
||||
|
||||
## Unreleased / In Rust Nightly
|
||||
## Unreleased / Beta / In Rust Nightly
|
||||
|
||||
[3c7e7dbc...master](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...master)
|
||||
[b52fb523...master](https://github.com/rust-lang/rust-clippy/compare/b52fb523...master)
|
||||
|
||||
## Rust 1.65
|
||||
|
||||
Current stable, released 2022-11-03
|
||||
|
||||
[3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523)
|
||||
|
||||
### Important Changes
|
||||
|
||||
* Clippy now has an `--explain <LINT>` command to show the lint description in the console
|
||||
[#8952](https://github.com/rust-lang/rust-clippy/pull/8952)
|
||||
|
||||
### New Lints
|
||||
|
||||
* [`unused_peekable`]
|
||||
[#9258](https://github.com/rust-lang/rust-clippy/pull/9258)
|
||||
* [`collapsible_str_replace`]
|
||||
[#9269](https://github.com/rust-lang/rust-clippy/pull/9269)
|
||||
* [`manual_string_new`]
|
||||
[#9295](https://github.com/rust-lang/rust-clippy/pull/9295)
|
||||
* [`iter_on_empty_collections`]
|
||||
[#9187](https://github.com/rust-lang/rust-clippy/pull/9187)
|
||||
* [`iter_on_single_items`]
|
||||
[#9187](https://github.com/rust-lang/rust-clippy/pull/9187)
|
||||
* [`bool_to_int_with_if`]
|
||||
[#9412](https://github.com/rust-lang/rust-clippy/pull/9412)
|
||||
* [`multi_assignments`]
|
||||
[#9379](https://github.com/rust-lang/rust-clippy/pull/9379)
|
||||
* [`result_large_err`]
|
||||
[#9373](https://github.com/rust-lang/rust-clippy/pull/9373)
|
||||
* [`partialeq_to_none`]
|
||||
[#9288](https://github.com/rust-lang/rust-clippy/pull/9288)
|
||||
* [`suspicious_to_owned`]
|
||||
[#8984](https://github.com/rust-lang/rust-clippy/pull/8984)
|
||||
* [`cast_slice_from_raw_parts`]
|
||||
[#9247](https://github.com/rust-lang/rust-clippy/pull/9247)
|
||||
* [`manual_instant_elapsed`]
|
||||
[#9264](https://github.com/rust-lang/rust-clippy/pull/9264)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Moved [`significant_drop_in_scrutinee`] to `nursery` (now allow-by-default)
|
||||
[#9302](https://github.com/rust-lang/rust-clippy/pull/9302)
|
||||
* Rename `logic_bug` to [`overly_complex_bool_expr`]
|
||||
[#9306](https://github.com/rust-lang/rust-clippy/pull/9306)
|
||||
* Rename `arithmetic` to [`arithmetic_side_effects`]
|
||||
[#9443](https://github.com/rust-lang/rust-clippy/pull/9443)
|
||||
* Moved [`only_used_in_recursion`] to complexity (now warn-by-default)
|
||||
[#8804](https://github.com/rust-lang/rust-clippy/pull/8804)
|
||||
* Moved [`assertions_on_result_states`] to restriction (now allow-by-default)
|
||||
[#9273](https://github.com/rust-lang/rust-clippy/pull/9273)
|
||||
* Renamed `blacklisted_name` to [`disallowed_names`]
|
||||
[#8974](https://github.com/rust-lang/rust-clippy/pull/8974)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`option_if_let_else`]: Now also checks for match expressions
|
||||
[#8696](https://github.com/rust-lang/rust-clippy/pull/8696)
|
||||
* [`explicit_auto_deref`]: Now lints on implicit returns in closures
|
||||
[#9126](https://github.com/rust-lang/rust-clippy/pull/9126)
|
||||
* [`needless_borrow`]: Now considers trait implementations
|
||||
[#9136](https://github.com/rust-lang/rust-clippy/pull/9136)
|
||||
* [`suboptimal_flops`], [`imprecise_flops`]: Now lint on constant expressions
|
||||
[#9404](https://github.com/rust-lang/rust-clippy/pull/9404)
|
||||
* [`if_let_mutex`]: Now detects mutex behind references and warns about deadlocks
|
||||
[#9318](https://github.com/rust-lang/rust-clippy/pull/9318)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`unit_arg`] [`default_trait_access`] [`missing_docs_in_private_items`]: No longer
|
||||
trigger in code generated from proc-macros
|
||||
[#8694](https://github.com/rust-lang/rust-clippy/pull/8694)
|
||||
* [`unwrap_used`]: Now lints uses of `unwrap_err`
|
||||
[#9338](https://github.com/rust-lang/rust-clippy/pull/9338)
|
||||
* [`expect_used`]: Now lints uses of `expect_err`
|
||||
[#9338](https://github.com/rust-lang/rust-clippy/pull/9338)
|
||||
* [`transmute_undefined_repr`]: Now longer lints if the first field is compatible
|
||||
with the other type
|
||||
[#9287](https://github.com/rust-lang/rust-clippy/pull/9287)
|
||||
* [`unnecessary_to_owned`]: No longer lints, if type change cased errors in
|
||||
the caller function
|
||||
[#9424](https://github.com/rust-lang/rust-clippy/pull/9424)
|
||||
* [`match_like_matches_macro`]: No longer lints, if there are comments inside the
|
||||
match expression
|
||||
[#9276](https://github.com/rust-lang/rust-clippy/pull/9276)
|
||||
* [`partialeq_to_none`]: No longer trigger in code generated from macros
|
||||
[#9389](https://github.com/rust-lang/rust-clippy/pull/9389)
|
||||
* [`arithmetic_side_effects`]: No longer lints expressions that only use literals
|
||||
[#9365](https://github.com/rust-lang/rust-clippy/pull/9365)
|
||||
* [`explicit_auto_deref`]: Now ignores references on block expressions when the type
|
||||
is `Sized`, on `dyn Trait` returns and when the suggestion is non-trivial
|
||||
[#9126](https://github.com/rust-lang/rust-clippy/pull/9126)
|
||||
* [`trait_duplication_in_bounds`]: Now better tracks bounds to avoid false positives
|
||||
[#9167](https://github.com/rust-lang/rust-clippy/pull/9167)
|
||||
* [`format_in_format_args`]: Now suggests cases where the result is formatted again
|
||||
[#9349](https://github.com/rust-lang/rust-clippy/pull/9349)
|
||||
* [`only_used_in_recursion`]: No longer lints on function without recursions and
|
||||
takes external functions into account
|
||||
[#8804](https://github.com/rust-lang/rust-clippy/pull/8804)
|
||||
* [`missing_const_for_fn`]: No longer lints in proc-macros
|
||||
[#9308](https://github.com/rust-lang/rust-clippy/pull/9308)
|
||||
* [`non_ascii_literal`]: Allow non-ascii comments in tests and make sure `#[allow]`
|
||||
attributes work in tests
|
||||
[#9327](https://github.com/rust-lang/rust-clippy/pull/9327)
|
||||
* [`question_mark`]: No longer lint `if let`s with subpatterns
|
||||
[#9348](https://github.com/rust-lang/rust-clippy/pull/9348)
|
||||
* [`needless_collect`]: No longer lints in loops
|
||||
[#8992](https://github.com/rust-lang/rust-clippy/pull/8992)
|
||||
* [`mut_mutex_lock`]: No longer lints if the mutex is behind an immutable reference
|
||||
[#9418](https://github.com/rust-lang/rust-clippy/pull/9418)
|
||||
* [`needless_return`]: Now ignores returns with arguments
|
||||
[#9381](https://github.com/rust-lang/rust-clippy/pull/9381)
|
||||
* [`range_plus_one`], [`range_minus_one`]: Now ignores code with macros
|
||||
[#9446](https://github.com/rust-lang/rust-clippy/pull/9446)
|
||||
* [`assertions_on_result_states`]: No longer lints on the unit type
|
||||
[#9273](https://github.com/rust-lang/rust-clippy/pull/9273)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`unwrap_or_else_default`]: Now suggests `unwrap_or_default()` for empty strings
|
||||
[#9421](https://github.com/rust-lang/rust-clippy/pull/9421)
|
||||
* [`if_then_some_else_none`]: Now also suggests `bool::then_some`
|
||||
[#9289](https://github.com/rust-lang/rust-clippy/pull/9289)
|
||||
* [`redundant_closure_call`]: The suggestion now works for async closures
|
||||
[#9053](https://github.com/rust-lang/rust-clippy/pull/9053)
|
||||
* [`suboptimal_flops`]: Now suggests parenthesis when they are required
|
||||
[#9394](https://github.com/rust-lang/rust-clippy/pull/9394)
|
||||
* [`case_sensitive_file_extension_comparisons`]: Now suggests `map_or(..)` instead of `map(..).unwrap_or`
|
||||
[#9341](https://github.com/rust-lang/rust-clippy/pull/9341)
|
||||
* Deprecated configuration values can now be updated automatically
|
||||
[#9252](https://github.com/rust-lang/rust-clippy/pull/9252)
|
||||
* [`or_fun_call`]: Now suggest `Entry::or_default` for `Entry::or_insert(Default::default())`
|
||||
[#9342](https://github.com/rust-lang/rust-clippy/pull/9342)
|
||||
* [`unwrap_used`]: Only suggests `expect` if [`expect_used`] is allowed
|
||||
[#9223](https://github.com/rust-lang/rust-clippy/pull/9223)
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* Fix ICE in [`useless_format`] for literals
|
||||
[#9406](https://github.com/rust-lang/rust-clippy/pull/9406)
|
||||
* Fix infinite loop in [`vec_init_then_push`]
|
||||
[#9441](https://github.com/rust-lang/rust-clippy/pull/9441)
|
||||
* Fix ICE when reading literals with weird proc-macro spans
|
||||
[#9303](https://github.com/rust-lang/rust-clippy/pull/9303)
|
||||
|
||||
## Rust 1.64
|
||||
|
||||
Current stable, released 2022-09-22
|
||||
Released 2022-09-22
|
||||
|
||||
[d7b5cbf0...3c7e7dbc](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...3c7e7dbc)
|
||||
|
||||
|
@ -3903,6 +4047,7 @@ Released 2018-09-13
|
|||
[`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string
|
||||
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
|
||||
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
|
||||
[`from_raw_with_void_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_raw_with_void_ptr
|
||||
[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
|
||||
[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
|
||||
[`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first
|
||||
|
@ -3978,6 +4123,7 @@ Released 2018-09-13
|
|||
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
|
||||
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
|
||||
[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
|
||||
[`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future
|
||||
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
|
||||
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
|
||||
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
|
||||
|
@ -3996,6 +4142,8 @@ Released 2018-09-13
|
|||
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
|
||||
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
|
||||
[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
|
||||
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
|
||||
[`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
|
||||
[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
|
||||
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
|
||||
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
||||
|
@ -4198,6 +4346,8 @@ Released 2018-09-13
|
|||
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
|
||||
[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method
|
||||
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
|
||||
[`seek_from_current`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current
|
||||
[`seek_to_start_instead_of_rewind`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_to_start_instead_of_rewind
|
||||
[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
|
||||
[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
|
||||
[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
|
||||
|
@ -4247,6 +4397,7 @@ Released 2018-09-13
|
|||
[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
|
||||
[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
|
||||
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
|
||||
[`suspicious_xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_xor_used_as_pow
|
||||
[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
|
||||
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
|
||||
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
|
||||
|
@ -4277,6 +4428,7 @@ Released 2018-09-13
|
|||
[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
|
||||
[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
|
||||
[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
|
||||
[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
|
||||
[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
|
||||
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
|
||||
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
|
||||
|
@ -4298,6 +4450,7 @@ Released 2018-09-13
|
|||
[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
|
||||
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
|
||||
[`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
|
||||
[`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc
|
||||
[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
|
||||
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
|
||||
[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
|
||||
|
|
|
@ -1,70 +1,3 @@
|
|||
# The Rust Code of Conduct
|
||||
|
||||
A version of this document [can be found online](https://www.rust-lang.org/conduct.html).
|
||||
|
||||
## Conduct
|
||||
|
||||
**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
|
||||
|
||||
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience,
|
||||
gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||
religion, nationality, or other similar characteristic.
|
||||
* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and
|
||||
welcoming environment for all.
|
||||
* Please be kind and courteous. There's no need to be mean or rude.
|
||||
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and
|
||||
numerous costs. There is seldom a right answer.
|
||||
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and
|
||||
see how it works.
|
||||
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We
|
||||
interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen
|
||||
Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their
|
||||
definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
|
||||
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or
|
||||
made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation
|
||||
team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a
|
||||
safe place for you and we've got your back.
|
||||
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
|
||||
|
||||
## Moderation
|
||||
|
||||
|
||||
These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation,
|
||||
please contact the [Rust moderation team][mod_team].
|
||||
|
||||
1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks,
|
||||
are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
|
||||
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
|
||||
3. Moderators will first respond to such remarks with a warning.
|
||||
4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
|
||||
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
|
||||
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended
|
||||
party a genuine apology.
|
||||
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a
|
||||
different moderator, **in private**. Complaints about bans in-channel are not allowed.
|
||||
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate
|
||||
situation, they should expect less leeway than others.
|
||||
|
||||
In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically
|
||||
unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly
|
||||
if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can
|
||||
drive people away from the community entirely.
|
||||
|
||||
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was
|
||||
they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good
|
||||
there was something you could've communicated better — remember that it's your responsibility to make your fellow
|
||||
Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about
|
||||
cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their
|
||||
trust.
|
||||
|
||||
The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust,
|
||||
#rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo);
|
||||
GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org
|
||||
(users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the
|
||||
maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider
|
||||
explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
|
||||
|
||||
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the
|
||||
[Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
|
||||
|
||||
[mod_team]: https://www.rust-lang.org/team.html#Moderation-team
|
||||
The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html).
|
||||
|
|
|
@ -23,6 +23,7 @@ All contributors are expected to follow the [Rust Code of Conduct].
|
|||
- [Issue and PR triage](#issue-and-pr-triage)
|
||||
- [Bors and Homu](#bors-and-homu)
|
||||
- [Contributions](#contributions)
|
||||
- [License](#license)
|
||||
|
||||
[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
|
||||
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
|
||||
|
@ -245,6 +246,38 @@ Contributions to Clippy should be made in the form of GitHub pull requests. Each
|
|||
be reviewed by a core contributor (someone with permission to land patches) and either landed in the
|
||||
main tree or given feedback for changes that would be required.
|
||||
|
||||
All PRs should include a `changelog` entry with a short comment explaining the change. The rule of thumb is basically,
|
||||
"what do you believe is important from an outsider's perspective?" Often, PRs are only related to a single property of a
|
||||
lint, and then it's good to mention that one. Otherwise, it's better to include too much detail than too little.
|
||||
|
||||
Clippy's [changelog] is created from these comments. Every release, someone gets all commits from bors with a
|
||||
`changelog: XYZ` entry and combines them into the changelog. This is a manual process.
|
||||
|
||||
Examples:
|
||||
- New lint
|
||||
```
|
||||
changelog: new lint: [`missing_trait_methods`]
|
||||
```
|
||||
- False positive fix
|
||||
```
|
||||
changelog: Fix [`unused_peekable`] false positive when peeked in a closure or called as `f(&mut peekable)`
|
||||
```
|
||||
- Purely internal change
|
||||
```
|
||||
changelog: none
|
||||
```
|
||||
|
||||
Note this it is fine for a PR to include multiple `changelog` entries, e.g.:
|
||||
```
|
||||
changelog: Something 1
|
||||
changelog: Something 2
|
||||
changelog: Something 3
|
||||
```
|
||||
|
||||
[changelog]: CHANGELOG.md
|
||||
|
||||
## License
|
||||
|
||||
All code in this repository is under the [Apache-2.0] or the [MIT] license.
|
||||
|
||||
<!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.1.66"
|
||||
version = "0.1.67"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Clippy
|
||||
|
||||
[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
|
||||
[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto)
|
||||
[![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](#license)
|
||||
|
||||
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
|
||||
|
@ -204,12 +204,6 @@ lints can be configured and the meaning of the variables.
|
|||
>
|
||||
> `clippy.toml` or `.clippy.toml` cannot be used to allow/deny lints.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Configuration changes will not apply for code that has already been compiled and cached under `./target/`;
|
||||
> for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure
|
||||
> that any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch.
|
||||
|
||||
To deactivate the “for further information visit *lint-link*” message you can
|
||||
define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ indoc = "1.0"
|
|||
itertools = "0.10.1"
|
||||
opener = "0.5"
|
||||
shell-escape = "0.1"
|
||||
tempfile = "3.2"
|
||||
walkdir = "2.3"
|
||||
|
||||
[features]
|
||||
|
|
|
@ -36,20 +36,12 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
|
|||
} else {
|
||||
exit_if_err(Command::new("cargo").arg("build").status());
|
||||
|
||||
// Run in a tempdir as changes to clippy do not retrigger linting
|
||||
let target = tempfile::Builder::new()
|
||||
.prefix("clippy")
|
||||
.tempdir()
|
||||
.expect("failed to create tempdir");
|
||||
|
||||
let status = Command::new(cargo_clippy_path())
|
||||
.arg("clippy")
|
||||
.args(args)
|
||||
.current_dir(path)
|
||||
.env("CARGO_TARGET_DIR", target.as_ref())
|
||||
.status();
|
||||
|
||||
target.close().expect("failed to remove tempdir");
|
||||
exit_if_err(status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use aho_corasick::AhoCorasickBuilder;
|
|||
use indoc::writedoc;
|
||||
use itertools::Itertools;
|
||||
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt::Write;
|
||||
use std::fs::{self, OpenOptions};
|
||||
|
@ -36,6 +36,60 @@ pub enum UpdateMode {
|
|||
pub fn update(update_mode: UpdateMode) {
|
||||
let (lints, deprecated_lints, renamed_lints) = gather_all();
|
||||
generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints);
|
||||
remove_old_files(update_mode);
|
||||
}
|
||||
|
||||
/// Remove files no longer needed after <https://github.com/rust-lang/rust-clippy/pull/9541>
|
||||
/// that may be reintroduced unintentionally
|
||||
///
|
||||
/// FIXME: This is a temporary measure that should be removed when there are no more PRs that
|
||||
/// include the stray files
|
||||
fn remove_old_files(update_mode: UpdateMode) {
|
||||
let mut failed = false;
|
||||
let mut remove_file = |path: &Path| match update_mode {
|
||||
UpdateMode::Check => {
|
||||
if path.exists() {
|
||||
failed = true;
|
||||
println!("unexpected file: {}", path.display());
|
||||
}
|
||||
},
|
||||
UpdateMode::Change => {
|
||||
if fs::remove_file(path).is_ok() {
|
||||
println!("removed file: {}", path.display());
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let files = [
|
||||
"clippy_lints/src/lib.register_all.rs",
|
||||
"clippy_lints/src/lib.register_cargo.rs",
|
||||
"clippy_lints/src/lib.register_complexity.rs",
|
||||
"clippy_lints/src/lib.register_correctness.rs",
|
||||
"clippy_lints/src/lib.register_internal.rs",
|
||||
"clippy_lints/src/lib.register_lints.rs",
|
||||
"clippy_lints/src/lib.register_nursery.rs",
|
||||
"clippy_lints/src/lib.register_pedantic.rs",
|
||||
"clippy_lints/src/lib.register_perf.rs",
|
||||
"clippy_lints/src/lib.register_restriction.rs",
|
||||
"clippy_lints/src/lib.register_style.rs",
|
||||
"clippy_lints/src/lib.register_suspicious.rs",
|
||||
"src/docs.rs",
|
||||
];
|
||||
|
||||
for file in files {
|
||||
remove_file(Path::new(file));
|
||||
}
|
||||
|
||||
if let Ok(docs_dir) = fs::read_dir("src/docs") {
|
||||
for doc_file in docs_dir {
|
||||
let path = doc_file.unwrap().path();
|
||||
remove_file(&path);
|
||||
}
|
||||
}
|
||||
|
||||
if failed {
|
||||
exit_with_failure();
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_lint_files(
|
||||
|
@ -104,9 +158,9 @@ fn generate_lint_files(
|
|||
);
|
||||
|
||||
process_file(
|
||||
"clippy_lints/src/lib.register_lints.rs",
|
||||
"clippy_lints/src/declared_lints.rs",
|
||||
update_mode,
|
||||
&gen_register_lint_list(internal_lints.iter(), usable_lints.iter()),
|
||||
&gen_declared_lints(internal_lints.iter(), usable_lints.iter()),
|
||||
);
|
||||
process_file(
|
||||
"clippy_lints/src/lib.deprecated.rs",
|
||||
|
@ -114,26 +168,6 @@ fn generate_lint_files(
|
|||
&gen_deprecated(deprecated_lints),
|
||||
);
|
||||
|
||||
let all_group_lints = usable_lints.iter().filter(|l| {
|
||||
matches!(
|
||||
&*l.group,
|
||||
"correctness" | "suspicious" | "style" | "complexity" | "perf"
|
||||
)
|
||||
});
|
||||
let content = gen_lint_group_list("all", all_group_lints);
|
||||
process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content);
|
||||
|
||||
update_docs(update_mode, &usable_lints);
|
||||
|
||||
for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
|
||||
let content = gen_lint_group_list(&lint_group, lints.iter());
|
||||
process_file(
|
||||
format!("clippy_lints/src/lib.register_{lint_group}.rs"),
|
||||
update_mode,
|
||||
&content,
|
||||
);
|
||||
}
|
||||
|
||||
let content = gen_deprecated_lints_test(deprecated_lints);
|
||||
process_file("tests/ui/deprecated.rs", update_mode, &content);
|
||||
|
||||
|
@ -141,62 +175,6 @@ fn generate_lint_files(
|
|||
process_file("tests/ui/rename.rs", update_mode, &content);
|
||||
}
|
||||
|
||||
fn update_docs(update_mode: UpdateMode, usable_lints: &[Lint]) {
|
||||
replace_region_in_file(update_mode, Path::new("src/docs.rs"), "docs! {\n", "\n}\n", |res| {
|
||||
for name in usable_lints.iter().map(|lint| lint.name.clone()).sorted() {
|
||||
writeln!(res, r#" "{name}","#).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
if update_mode == UpdateMode::Check {
|
||||
let mut extra = BTreeSet::new();
|
||||
let mut lint_names = usable_lints
|
||||
.iter()
|
||||
.map(|lint| lint.name.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
for file in std::fs::read_dir("src/docs").unwrap() {
|
||||
let filename = file.unwrap().file_name().into_string().unwrap();
|
||||
if let Some(name) = filename.strip_suffix(".txt") {
|
||||
if !lint_names.remove(name) {
|
||||
extra.insert(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let failed = print_lint_names("extra lint docs:", &extra) | print_lint_names("missing lint docs:", &lint_names);
|
||||
|
||||
if failed {
|
||||
exit_with_failure();
|
||||
}
|
||||
} else {
|
||||
if std::fs::remove_dir_all("src/docs").is_err() {
|
||||
eprintln!("could not remove src/docs directory");
|
||||
}
|
||||
if std::fs::create_dir("src/docs").is_err() {
|
||||
eprintln!("could not recreate src/docs directory");
|
||||
}
|
||||
}
|
||||
for lint in usable_lints {
|
||||
process_file(
|
||||
Path::new("src/docs").join(lint.name.clone() + ".txt"),
|
||||
update_mode,
|
||||
&lint.documentation,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_lint_names(header: &str, lints: &BTreeSet<String>) -> bool {
|
||||
if lints.is_empty() {
|
||||
return false;
|
||||
}
|
||||
println!("{header}");
|
||||
for lint in lints.iter().sorted() {
|
||||
println!(" {lint}");
|
||||
}
|
||||
println!();
|
||||
true
|
||||
}
|
||||
|
||||
pub fn print_lints() {
|
||||
let (lint_list, _, _) = gather_all();
|
||||
let usable_lints = Lint::usable_lints(&lint_list);
|
||||
|
@ -641,26 +619,17 @@ struct Lint {
|
|||
desc: String,
|
||||
module: String,
|
||||
declaration_range: Range<usize>,
|
||||
documentation: String,
|
||||
}
|
||||
|
||||
impl Lint {
|
||||
#[must_use]
|
||||
fn new(
|
||||
name: &str,
|
||||
group: &str,
|
||||
desc: &str,
|
||||
module: &str,
|
||||
declaration_range: Range<usize>,
|
||||
documentation: String,
|
||||
) -> Self {
|
||||
fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range<usize>) -> Self {
|
||||
Self {
|
||||
name: name.to_lowercase(),
|
||||
group: group.into(),
|
||||
desc: remove_line_splices(desc),
|
||||
module: module.into(),
|
||||
declaration_range,
|
||||
documentation,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,25 +685,6 @@ impl RenamedLint {
|
|||
}
|
||||
}
|
||||
|
||||
/// Generates the code for registering a group
|
||||
fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator<Item = &'a Lint>) -> String {
|
||||
let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect();
|
||||
details.sort_unstable();
|
||||
|
||||
let mut output = GENERATED_FILE_COMMENT.to_string();
|
||||
|
||||
let _ = writeln!(
|
||||
output,
|
||||
"store.register_group(true, \"clippy::{group_name}\", Some(\"clippy_{group_name}\"), vec![",
|
||||
);
|
||||
for (module, name) in details {
|
||||
let _ = writeln!(output, " LintId::of({module}::{name}),");
|
||||
}
|
||||
output.push_str("])\n");
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Generates the `register_removed` code
|
||||
#[must_use]
|
||||
fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
|
||||
|
@ -759,7 +709,7 @@ fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
|
|||
|
||||
/// Generates the code for registering lints
|
||||
#[must_use]
|
||||
fn gen_register_lint_list<'a>(
|
||||
fn gen_declared_lints<'a>(
|
||||
internal_lints: impl Iterator<Item = &'a Lint>,
|
||||
usable_lints: impl Iterator<Item = &'a Lint>,
|
||||
) -> String {
|
||||
|
@ -770,15 +720,15 @@ fn gen_register_lint_list<'a>(
|
|||
details.sort_unstable();
|
||||
|
||||
let mut output = GENERATED_FILE_COMMENT.to_string();
|
||||
output.push_str("store.register_lints(&[\n");
|
||||
output.push_str("pub(crate) static LINTS: &[&crate::LintInfo] = &[\n");
|
||||
|
||||
for (is_public, module_name, lint_name) in details {
|
||||
if !is_public {
|
||||
output.push_str(" #[cfg(feature = \"internal\")]\n");
|
||||
}
|
||||
let _ = writeln!(output, " {module_name}::{lint_name},");
|
||||
let _ = writeln!(output, " crate::{module_name}::{lint_name}_INFO,");
|
||||
}
|
||||
output.push_str("])\n");
|
||||
output.push_str("];\n");
|
||||
|
||||
output
|
||||
}
|
||||
|
@ -910,35 +860,26 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
|
|||
}| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint",
|
||||
) {
|
||||
let start = range.start;
|
||||
let mut docs = String::with_capacity(128);
|
||||
let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace));
|
||||
let mut iter = iter
|
||||
.by_ref()
|
||||
.filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
|
||||
// matches `!{`
|
||||
match_tokens!(iter, Bang OpenBrace);
|
||||
let mut in_code = false;
|
||||
while let Some(t) = iter.next() {
|
||||
match t.token_kind {
|
||||
TokenKind::LineComment { .. } => {
|
||||
if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) {
|
||||
if line.starts_with("```") {
|
||||
docs += "```\n";
|
||||
in_code = !in_code;
|
||||
} else if !(in_code && line.starts_with("# ")) {
|
||||
docs += line;
|
||||
docs.push('\n');
|
||||
}
|
||||
}
|
||||
},
|
||||
TokenKind::Pound => {
|
||||
match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
|
||||
break;
|
||||
},
|
||||
TokenKind::Ident => {
|
||||
break;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
match iter.next() {
|
||||
// #[clippy::version = "version"] pub
|
||||
Some(LintDeclSearchResult {
|
||||
token_kind: TokenKind::Pound,
|
||||
..
|
||||
}) => {
|
||||
match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
|
||||
},
|
||||
// pub
|
||||
Some(LintDeclSearchResult {
|
||||
token_kind: TokenKind::Ident,
|
||||
..
|
||||
}) => (),
|
||||
_ => continue,
|
||||
}
|
||||
docs.pop(); // remove final newline
|
||||
|
||||
let (name, group, desc) = match_tokens!(
|
||||
iter,
|
||||
|
@ -956,7 +897,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
|
|||
..
|
||||
}) = iter.next()
|
||||
{
|
||||
lints.push(Lint::new(name, group, desc, module, start..range.end, docs));
|
||||
lints.push(Lint::new(name, group, desc, module, start..range.end));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1186,7 +1127,6 @@ mod tests {
|
|||
"\"really long text\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"doc_markdown",
|
||||
|
@ -1194,7 +1134,6 @@ mod tests {
|
|||
"\"single line\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
];
|
||||
assert_eq!(expected, result);
|
||||
|
@ -1234,7 +1173,6 @@ mod tests {
|
|||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"should_assert_eq2",
|
||||
|
@ -1242,7 +1180,6 @@ mod tests {
|
|||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"should_assert_eq2",
|
||||
|
@ -1250,7 +1187,6 @@ mod tests {
|
|||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
];
|
||||
let expected = vec![Lint::new(
|
||||
|
@ -1259,7 +1195,6 @@ mod tests {
|
|||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
)];
|
||||
assert_eq!(expected, Lint::usable_lints(&lints));
|
||||
}
|
||||
|
@ -1267,51 +1202,22 @@ mod tests {
|
|||
#[test]
|
||||
fn test_by_lint_group() {
|
||||
let lints = vec![
|
||||
Lint::new(
|
||||
"should_assert_eq",
|
||||
"group1",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new(
|
||||
"should_assert_eq2",
|
||||
"group2",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"incorrect_match",
|
||||
"group1",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
];
|
||||
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
|
||||
expected.insert(
|
||||
"group1".to_string(),
|
||||
vec![
|
||||
Lint::new(
|
||||
"should_assert_eq",
|
||||
"group1",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"incorrect_match",
|
||||
"group1",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
],
|
||||
);
|
||||
expected.insert(
|
||||
|
@ -1322,7 +1228,6 @@ mod tests {
|
|||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
)],
|
||||
);
|
||||
assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
|
||||
|
@ -1357,48 +1262,4 @@ mod tests {
|
|||
|
||||
assert_eq!(expected, gen_deprecated(&lints));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gen_lint_group_list() {
|
||||
let lints = vec![
|
||||
Lint::new(
|
||||
"abc",
|
||||
"group1",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"should_assert_eq",
|
||||
"group1",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
Lint::new(
|
||||
"internal",
|
||||
"internal_style",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
String::new(),
|
||||
),
|
||||
];
|
||||
let expected = GENERATED_FILE_COMMENT.to_string()
|
||||
+ &[
|
||||
"store.register_group(true, \"clippy::group1\", Some(\"clippy_group1\"), vec![",
|
||||
" LintId::of(module_name::ABC),",
|
||||
" LintId::of(module_name::INTERNAL),",
|
||||
" LintId::of(module_name::SHOULD_ASSERT_EQ),",
|
||||
"])",
|
||||
]
|
||||
.join("\n")
|
||||
+ "\n";
|
||||
|
||||
let result = gen_lint_group_list("group1", lints.iter());
|
||||
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.66"
|
||||
version = "0.1.67"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
@ -11,6 +11,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
cargo_metadata = "0.14"
|
||||
clippy_utils = { path = "../clippy_utils" }
|
||||
declare_clippy_lint = { path = "../declare_clippy_lint" }
|
||||
if_chain = "1.0"
|
||||
itertools = "0.10.1"
|
||||
pulldown-cmark = { version = "0.9", default-features = false }
|
||||
|
|
|
@ -11,14 +11,14 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::{
|
||||
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
|
||||
};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{sym, DUMMY_SP};
|
||||
use semver::Version;
|
||||
|
||||
static UNIX_SYSTEMS: &[&str] = &[
|
||||
|
@ -303,6 +303,26 @@ declare_lint_pass!(Attributes => [
|
|||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Attributes {
|
||||
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
||||
for (name, level) in &cx.sess().opts.lint_opts {
|
||||
if name == "clippy::restriction" && *level > Level::Allow {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
BLANKET_CLIPPY_RESTRICTION_LINTS,
|
||||
DUMMY_SP,
|
||||
"`clippy::restriction` is not meant to be enabled as a group",
|
||||
|diag| {
|
||||
diag.note(format!(
|
||||
"because of the command line `--{} clippy::restriction`",
|
||||
level.as_str()
|
||||
));
|
||||
diag.help("enable the restriction lints you need individually");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
|
||||
if let Some(items) = &attr.meta_item_list() {
|
||||
if let Some(ident) = attr.ident() {
|
||||
|
@ -358,7 +378,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
|
|||
| "enum_glob_use"
|
||||
| "redundant_pub_crate"
|
||||
| "macro_use_imports"
|
||||
| "unsafe_removed_from_name",
|
||||
| "unsafe_removed_from_name"
|
||||
| "module_name_repetitions"
|
||||
| "single_component_path_imports"
|
||||
)
|
||||
})
|
||||
{
|
||||
|
@ -441,9 +463,9 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe
|
|||
cx,
|
||||
BLANKET_CLIPPY_RESTRICTION_LINTS,
|
||||
lint.span(),
|
||||
"restriction lints are not meant to be all enabled",
|
||||
"`clippy::restriction` is not meant to be enabled as a group",
|
||||
None,
|
||||
"try enabling only the lints you really need",
|
||||
"enable the restriction lints you need individually",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -464,6 +486,11 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
|
|||
return;
|
||||
}
|
||||
|
||||
// Check if the attribute is in an external macro and therefore out of the developer's control
|
||||
if in_external_macro(cx.sess(), attr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
ALLOW_ATTRIBUTES_WITHOUT_REASON,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -189,7 +188,7 @@ impl LateLintPass<'_> for AwaitHolding {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for conf in &self.conf_invalid_types {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.def_ids.insert(id, conf.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_utils::higher::If;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_hir::{Block, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, is_integer_literal, sugg::Sugg};
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, in_constant, is_else_clause, is_integer_literal, sugg::Sugg};
|
||||
use rustc_errors::Applicability;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -12,7 +13,7 @@ declare_clippy_lint! {
|
|||
/// this lint suggests using a `from()` function or an `as` coercion.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Coercion or `from()` is idiomatic way to convert bool to a number.
|
||||
/// Coercion or `from()` is another way to convert bool to a number.
|
||||
/// Both methods are guaranteed to return 1 for true, and 0 for false.
|
||||
///
|
||||
/// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
|
||||
|
@ -38,23 +39,23 @@ declare_clippy_lint! {
|
|||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub BOOL_TO_INT_WITH_IF,
|
||||
style,
|
||||
pedantic,
|
||||
"using if to convert bool to int"
|
||||
}
|
||||
declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
|
||||
fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
|
||||
if !expr.span.from_expansion() {
|
||||
check_if_else(ctx, expr);
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
|
||||
if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
|
||||
check_if_else(cx, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
|
||||
if let ExprKind::If(check, then, Some(else_)) = expr.kind
|
||||
fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
|
||||
if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr)
|
||||
&& let Some(then_lit) = int_literal(then)
|
||||
&& let Some(else_lit) = int_literal(else_)
|
||||
&& let Some(else_lit) = int_literal(r#else)
|
||||
{
|
||||
let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
|
||||
false
|
||||
|
@ -66,17 +67,17 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
|
|||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snippet = {
|
||||
let mut sugg = Sugg::hir_with_applicability(ctx, check, "..", &mut applicability);
|
||||
let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
|
||||
if inverted {
|
||||
sugg = !sugg;
|
||||
}
|
||||
sugg
|
||||
};
|
||||
|
||||
let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
|
||||
let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
|
||||
|
||||
let suggestion = {
|
||||
let wrap_in_curly = is_else_clause(ctx.tcx, expr);
|
||||
let wrap_in_curly = is_else_clause(cx.tcx, expr);
|
||||
let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
|
||||
if wrap_in_curly {
|
||||
s = s.blockify();
|
||||
|
@ -87,7 +88,7 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
|
|||
let into_snippet = snippet.clone().maybe_par();
|
||||
let as_snippet = snippet.as_ty(ty);
|
||||
|
||||
span_lint_and_then(ctx,
|
||||
span_lint_and_then(cx,
|
||||
BOOL_TO_INT_WITH_IF,
|
||||
expr.span,
|
||||
"boolean to int conversion using if",
|
||||
|
|
|
@ -481,7 +481,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
|
||||
fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
cx.tcx
|
||||
.get_diagnostic_item(sym::Ord)
|
||||
|
|
|
@ -593,7 +593,7 @@ declare_clippy_lint! {
|
|||
/// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
|
||||
/// ```
|
||||
/// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
|
||||
#[clippy::version = "1.64.0"]
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub CAST_SLICE_FROM_RAW_PARTS,
|
||||
suspicious,
|
||||
"casting a slice created from a pointer and length to a slice pointer"
|
||||
|
|
|
@ -4,11 +4,11 @@ use clippy_utils::diagnostics::span_lint_and_help;
|
|||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::for_each_expr;
|
||||
use clippy_utils::LimitStack;
|
||||
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, ExprKind, FnDecl, HirId};
|
||||
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Span;
|
||||
|
@ -56,15 +56,13 @@ impl CognitiveComplexity {
|
|||
cx: &LateContext<'tcx>,
|
||||
kind: FnKind<'tcx>,
|
||||
decl: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
body_span: Span,
|
||||
) {
|
||||
if body_span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
let expr = body.value;
|
||||
|
||||
let mut cc = 1u64;
|
||||
let mut returns = 0u64;
|
||||
let _: Option<!> = for_each_expr(expr, |e| {
|
||||
|
@ -146,7 +144,18 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
|
|||
) {
|
||||
let def_id = cx.tcx.hir().local_def_id(hir_id);
|
||||
if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
|
||||
self.check(cx, kind, decl, body, span);
|
||||
let expr = if is_async_fn(kind) {
|
||||
match get_async_fn_body(cx.tcx, body) {
|
||||
Some(b) => b,
|
||||
None => {
|
||||
return;
|
||||
},
|
||||
}
|
||||
} else {
|
||||
body.value
|
||||
};
|
||||
|
||||
self.check(cx, kind, decl, expr, span);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
628
clippy_lints/src/declared_lints.rs
Normal file
628
clippy_lints/src/declared_lints.rs
Normal file
|
@ -0,0 +1,628 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::if_chain_style::IF_CHAIN_STYLE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
|
||||
crate::almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE_INFO,
|
||||
crate::approx_const::APPROX_CONSTANT_INFO,
|
||||
crate::as_conversions::AS_CONVERSIONS_INFO,
|
||||
crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
|
||||
crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO,
|
||||
crate::assertions_on_constants::ASSERTIONS_ON_CONSTANTS_INFO,
|
||||
crate::assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES_INFO,
|
||||
crate::async_yields_async::ASYNC_YIELDS_ASYNC_INFO,
|
||||
crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO,
|
||||
crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO,
|
||||
crate::attrs::DEPRECATED_CFG_ATTR_INFO,
|
||||
crate::attrs::DEPRECATED_SEMVER_INFO,
|
||||
crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
|
||||
crate::attrs::INLINE_ALWAYS_INFO,
|
||||
crate::attrs::MISMATCHED_TARGET_OS_INFO,
|
||||
crate::attrs::USELESS_ATTRIBUTE_INFO,
|
||||
crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
|
||||
crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,
|
||||
crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO,
|
||||
crate::blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS_INFO,
|
||||
crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO,
|
||||
crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
|
||||
crate::booleans::NONMINIMAL_BOOL_INFO,
|
||||
crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
|
||||
crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
|
||||
crate::box_default::BOX_DEFAULT_INFO,
|
||||
crate::cargo::CARGO_COMMON_METADATA_INFO,
|
||||
crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
|
||||
crate::cargo::NEGATIVE_FEATURE_NAMES_INFO,
|
||||
crate::cargo::REDUNDANT_FEATURE_NAMES_INFO,
|
||||
crate::cargo::WILDCARD_DEPENDENCIES_INFO,
|
||||
crate::casts::AS_PTR_CAST_MUT_INFO,
|
||||
crate::casts::AS_UNDERSCORE_INFO,
|
||||
crate::casts::BORROW_AS_PTR_INFO,
|
||||
crate::casts::CAST_ABS_TO_UNSIGNED_INFO,
|
||||
crate::casts::CAST_ENUM_CONSTRUCTOR_INFO,
|
||||
crate::casts::CAST_ENUM_TRUNCATION_INFO,
|
||||
crate::casts::CAST_LOSSLESS_INFO,
|
||||
crate::casts::CAST_NAN_TO_INT_INFO,
|
||||
crate::casts::CAST_POSSIBLE_TRUNCATION_INFO,
|
||||
crate::casts::CAST_POSSIBLE_WRAP_INFO,
|
||||
crate::casts::CAST_PRECISION_LOSS_INFO,
|
||||
crate::casts::CAST_PTR_ALIGNMENT_INFO,
|
||||
crate::casts::CAST_REF_TO_MUT_INFO,
|
||||
crate::casts::CAST_SIGN_LOSS_INFO,
|
||||
crate::casts::CAST_SLICE_DIFFERENT_SIZES_INFO,
|
||||
crate::casts::CAST_SLICE_FROM_RAW_PARTS_INFO,
|
||||
crate::casts::CHAR_LIT_AS_U8_INFO,
|
||||
crate::casts::FN_TO_NUMERIC_CAST_INFO,
|
||||
crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
|
||||
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
|
||||
crate::casts::PTR_AS_PTR_INFO,
|
||||
crate::casts::UNNECESSARY_CAST_INFO,
|
||||
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
|
||||
crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
|
||||
crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
|
||||
crate::collapsible_if::COLLAPSIBLE_IF_INFO,
|
||||
crate::comparison_chain::COMPARISON_CHAIN_INFO,
|
||||
crate::copies::BRANCHES_SHARING_CODE_INFO,
|
||||
crate::copies::IFS_SAME_COND_INFO,
|
||||
crate::copies::IF_SAME_THEN_ELSE_INFO,
|
||||
crate::copies::SAME_FUNCTIONS_IN_IF_CONDITION_INFO,
|
||||
crate::copy_iterator::COPY_ITERATOR_INFO,
|
||||
crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
|
||||
crate::create_dir::CREATE_DIR_INFO,
|
||||
crate::dbg_macro::DBG_MACRO_INFO,
|
||||
crate::default::DEFAULT_TRAIT_ACCESS_INFO,
|
||||
crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
|
||||
crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
|
||||
crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
|
||||
crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
|
||||
crate::dereference::EXPLICIT_AUTO_DEREF_INFO,
|
||||
crate::dereference::EXPLICIT_DEREF_METHODS_INFO,
|
||||
crate::dereference::NEEDLESS_BORROW_INFO,
|
||||
crate::dereference::REF_BINDING_TO_REFERENCE_INFO,
|
||||
crate::derivable_impls::DERIVABLE_IMPLS_INFO,
|
||||
crate::derive::DERIVE_HASH_XOR_EQ_INFO,
|
||||
crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO,
|
||||
crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO,
|
||||
crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO,
|
||||
crate::derive::UNSAFE_DERIVE_DESERIALIZE_INFO,
|
||||
crate::disallowed_macros::DISALLOWED_MACROS_INFO,
|
||||
crate::disallowed_methods::DISALLOWED_METHODS_INFO,
|
||||
crate::disallowed_names::DISALLOWED_NAMES_INFO,
|
||||
crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
|
||||
crate::disallowed_types::DISALLOWED_TYPES_INFO,
|
||||
crate::doc::DOC_LINK_WITH_QUOTES_INFO,
|
||||
crate::doc::DOC_MARKDOWN_INFO,
|
||||
crate::doc::MISSING_ERRORS_DOC_INFO,
|
||||
crate::doc::MISSING_PANICS_DOC_INFO,
|
||||
crate::doc::MISSING_SAFETY_DOC_INFO,
|
||||
crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,
|
||||
crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
|
||||
crate::double_parens::DOUBLE_PARENS_INFO,
|
||||
crate::drop_forget_ref::DROP_COPY_INFO,
|
||||
crate::drop_forget_ref::DROP_NON_DROP_INFO,
|
||||
crate::drop_forget_ref::DROP_REF_INFO,
|
||||
crate::drop_forget_ref::FORGET_COPY_INFO,
|
||||
crate::drop_forget_ref::FORGET_NON_DROP_INFO,
|
||||
crate::drop_forget_ref::FORGET_REF_INFO,
|
||||
crate::drop_forget_ref::UNDROPPED_MANUALLY_DROPS_INFO,
|
||||
crate::duplicate_mod::DUPLICATE_MOD_INFO,
|
||||
crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
|
||||
crate::empty_drop::EMPTY_DROP_INFO,
|
||||
crate::empty_enum::EMPTY_ENUM_INFO,
|
||||
crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
|
||||
crate::entry::MAP_ENTRY_INFO,
|
||||
crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
|
||||
crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
|
||||
crate::enum_variants::MODULE_INCEPTION_INFO,
|
||||
crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
|
||||
crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
|
||||
crate::escape::BOXED_LOCAL_INFO,
|
||||
crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
|
||||
crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
|
||||
crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO,
|
||||
crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO,
|
||||
crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
|
||||
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
|
||||
crate::exit::EXIT_INFO,
|
||||
crate::explicit_write::EXPLICIT_WRITE_INFO,
|
||||
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
|
||||
crate::float_literal::EXCESSIVE_PRECISION_INFO,
|
||||
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
|
||||
crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
|
||||
crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
|
||||
crate::format::USELESS_FORMAT_INFO,
|
||||
crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
|
||||
crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
|
||||
crate::format_args::UNINLINED_FORMAT_ARGS_INFO,
|
||||
crate::format_args::UNUSED_FORMAT_SPECS_INFO,
|
||||
crate::format_impl::PRINT_IN_FORMAT_IMPL_INFO,
|
||||
crate::format_impl::RECURSIVE_FORMAT_IMPL_INFO,
|
||||
crate::format_push_string::FORMAT_PUSH_STRING_INFO,
|
||||
crate::formatting::POSSIBLE_MISSING_COMMA_INFO,
|
||||
crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
|
||||
crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
|
||||
crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
|
||||
crate::from_over_into::FROM_OVER_INTO_INFO,
|
||||
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
|
||||
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
|
||||
crate::functions::DOUBLE_MUST_USE_INFO,
|
||||
crate::functions::MUST_USE_CANDIDATE_INFO,
|
||||
crate::functions::MUST_USE_UNIT_INFO,
|
||||
crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
|
||||
crate::functions::RESULT_LARGE_ERR_INFO,
|
||||
crate::functions::RESULT_UNIT_ERR_INFO,
|
||||
crate::functions::TOO_MANY_ARGUMENTS_INFO,
|
||||
crate::functions::TOO_MANY_LINES_INFO,
|
||||
crate::future_not_send::FUTURE_NOT_SEND_INFO,
|
||||
crate::if_let_mutex::IF_LET_MUTEX_INFO,
|
||||
crate::if_not_else::IF_NOT_ELSE_INFO,
|
||||
crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
|
||||
crate::implicit_hasher::IMPLICIT_HASHER_INFO,
|
||||
crate::implicit_return::IMPLICIT_RETURN_INFO,
|
||||
crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
|
||||
crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
|
||||
crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
|
||||
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
|
||||
crate::indexing_slicing::INDEXING_SLICING_INFO,
|
||||
crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
|
||||
crate::infinite_iter::INFINITE_ITER_INFO,
|
||||
crate::infinite_iter::MAYBE_INFINITE_ITER_INFO,
|
||||
crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
|
||||
crate::inherent_to_string::INHERENT_TO_STRING_INFO,
|
||||
crate::inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY_INFO,
|
||||
crate::init_numbered_fields::INIT_NUMBERED_FIELDS_INFO,
|
||||
crate::inline_fn_without_body::INLINE_FN_WITHOUT_BODY_INFO,
|
||||
crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO,
|
||||
crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
|
||||
crate::int_plus_one::INT_PLUS_ONE_INFO,
|
||||
crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
|
||||
crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_INFO,
|
||||
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
|
||||
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
|
||||
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
|
||||
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
|
||||
crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
|
||||
crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
|
||||
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
|
||||
crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
|
||||
crate::len_zero::LEN_ZERO_INFO,
|
||||
crate::let_if_seq::USELESS_LET_IF_SEQ_INFO,
|
||||
crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
|
||||
crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
|
||||
crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
|
||||
crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
|
||||
crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
|
||||
crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
|
||||
crate::literal_representation::INCONSISTENT_DIGIT_GROUPING_INFO,
|
||||
crate::literal_representation::LARGE_DIGIT_GROUPS_INFO,
|
||||
crate::literal_representation::MISTYPED_LITERAL_SUFFIXES_INFO,
|
||||
crate::literal_representation::UNREADABLE_LITERAL_INFO,
|
||||
crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO,
|
||||
crate::loops::EMPTY_LOOP_INFO,
|
||||
crate::loops::EXPLICIT_COUNTER_LOOP_INFO,
|
||||
crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
|
||||
crate::loops::EXPLICIT_ITER_LOOP_INFO,
|
||||
crate::loops::FOR_KV_MAP_INFO,
|
||||
crate::loops::ITER_NEXT_LOOP_INFO,
|
||||
crate::loops::MANUAL_FIND_INFO,
|
||||
crate::loops::MANUAL_FLATTEN_INFO,
|
||||
crate::loops::MANUAL_MEMCPY_INFO,
|
||||
crate::loops::MISSING_SPIN_LOOP_INFO,
|
||||
crate::loops::MUT_RANGE_BOUND_INFO,
|
||||
crate::loops::NEEDLESS_RANGE_LOOP_INFO,
|
||||
crate::loops::NEVER_LOOP_INFO,
|
||||
crate::loops::SAME_ITEM_PUSH_INFO,
|
||||
crate::loops::SINGLE_ELEMENT_LOOP_INFO,
|
||||
crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
|
||||
crate::loops::WHILE_LET_LOOP_INFO,
|
||||
crate::loops::WHILE_LET_ON_ITERATOR_INFO,
|
||||
crate::macro_use::MACRO_USE_IMPORTS_INFO,
|
||||
crate::main_recursion::MAIN_RECURSION_INFO,
|
||||
crate::manual_assert::MANUAL_ASSERT_INFO,
|
||||
crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
|
||||
crate::manual_bits::MANUAL_BITS_INFO,
|
||||
crate::manual_clamp::MANUAL_CLAMP_INFO,
|
||||
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
|
||||
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
|
||||
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
|
||||
crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
|
||||
crate::manual_retain::MANUAL_RETAIN_INFO,
|
||||
crate::manual_string_new::MANUAL_STRING_NEW_INFO,
|
||||
crate::manual_strip::MANUAL_STRIP_INFO,
|
||||
crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO,
|
||||
crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO,
|
||||
crate::match_result_ok::MATCH_RESULT_OK_INFO,
|
||||
crate::matches::COLLAPSIBLE_MATCH_INFO,
|
||||
crate::matches::INFALLIBLE_DESTRUCTURING_MATCH_INFO,
|
||||
crate::matches::MANUAL_FILTER_INFO,
|
||||
crate::matches::MANUAL_MAP_INFO,
|
||||
crate::matches::MANUAL_UNWRAP_OR_INFO,
|
||||
crate::matches::MATCH_AS_REF_INFO,
|
||||
crate::matches::MATCH_BOOL_INFO,
|
||||
crate::matches::MATCH_LIKE_MATCHES_MACRO_INFO,
|
||||
crate::matches::MATCH_ON_VEC_ITEMS_INFO,
|
||||
crate::matches::MATCH_OVERLAPPING_ARM_INFO,
|
||||
crate::matches::MATCH_REF_PATS_INFO,
|
||||
crate::matches::MATCH_SAME_ARMS_INFO,
|
||||
crate::matches::MATCH_SINGLE_BINDING_INFO,
|
||||
crate::matches::MATCH_STR_CASE_MISMATCH_INFO,
|
||||
crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
|
||||
crate::matches::MATCH_WILD_ERR_ARM_INFO,
|
||||
crate::matches::NEEDLESS_MATCH_INFO,
|
||||
crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
|
||||
crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
|
||||
crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
|
||||
crate::matches::SINGLE_MATCH_INFO,
|
||||
crate::matches::SINGLE_MATCH_ELSE_INFO,
|
||||
crate::matches::TRY_ERR_INFO,
|
||||
crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO,
|
||||
crate::matches::WILDCARD_IN_OR_PATTERNS_INFO,
|
||||
crate::mem_forget::MEM_FORGET_INFO,
|
||||
crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO,
|
||||
crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO,
|
||||
crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO,
|
||||
crate::methods::BIND_INSTEAD_OF_MAP_INFO,
|
||||
crate::methods::BYTES_COUNT_TO_LEN_INFO,
|
||||
crate::methods::BYTES_NTH_INFO,
|
||||
crate::methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS_INFO,
|
||||
crate::methods::CHARS_LAST_CMP_INFO,
|
||||
crate::methods::CHARS_NEXT_CMP_INFO,
|
||||
crate::methods::CLONED_INSTEAD_OF_COPIED_INFO,
|
||||
crate::methods::CLONE_DOUBLE_REF_INFO,
|
||||
crate::methods::CLONE_ON_COPY_INFO,
|
||||
crate::methods::CLONE_ON_REF_PTR_INFO,
|
||||
crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
|
||||
crate::methods::ERR_EXPECT_INFO,
|
||||
crate::methods::EXPECT_FUN_CALL_INFO,
|
||||
crate::methods::EXPECT_USED_INFO,
|
||||
crate::methods::EXTEND_WITH_DRAIN_INFO,
|
||||
crate::methods::FILETYPE_IS_FILE_INFO,
|
||||
crate::methods::FILTER_MAP_IDENTITY_INFO,
|
||||
crate::methods::FILTER_MAP_NEXT_INFO,
|
||||
crate::methods::FILTER_NEXT_INFO,
|
||||
crate::methods::FLAT_MAP_IDENTITY_INFO,
|
||||
crate::methods::FLAT_MAP_OPTION_INFO,
|
||||
crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO,
|
||||
crate::methods::GET_FIRST_INFO,
|
||||
crate::methods::GET_LAST_WITH_LEN_INFO,
|
||||
crate::methods::GET_UNWRAP_INFO,
|
||||
crate::methods::IMPLICIT_CLONE_INFO,
|
||||
crate::methods::INEFFICIENT_TO_STRING_INFO,
|
||||
crate::methods::INSPECT_FOR_EACH_INFO,
|
||||
crate::methods::INTO_ITER_ON_REF_INFO,
|
||||
crate::methods::IS_DIGIT_ASCII_RADIX_INFO,
|
||||
crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
|
||||
crate::methods::ITER_CLONED_COLLECT_INFO,
|
||||
crate::methods::ITER_COUNT_INFO,
|
||||
crate::methods::ITER_KV_MAP_INFO,
|
||||
crate::methods::ITER_NEXT_SLICE_INFO,
|
||||
crate::methods::ITER_NTH_INFO,
|
||||
crate::methods::ITER_NTH_ZERO_INFO,
|
||||
crate::methods::ITER_ON_EMPTY_COLLECTIONS_INFO,
|
||||
crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
|
||||
crate::methods::ITER_OVEREAGER_CLONED_INFO,
|
||||
crate::methods::ITER_SKIP_NEXT_INFO,
|
||||
crate::methods::ITER_WITH_DRAIN_INFO,
|
||||
crate::methods::MANUAL_FILTER_MAP_INFO,
|
||||
crate::methods::MANUAL_FIND_MAP_INFO,
|
||||
crate::methods::MANUAL_OK_OR_INFO,
|
||||
crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
|
||||
crate::methods::MANUAL_SPLIT_ONCE_INFO,
|
||||
crate::methods::MANUAL_STR_REPEAT_INFO,
|
||||
crate::methods::MAP_CLONE_INFO,
|
||||
crate::methods::MAP_COLLECT_RESULT_UNIT_INFO,
|
||||
crate::methods::MAP_ERR_IGNORE_INFO,
|
||||
crate::methods::MAP_FLATTEN_INFO,
|
||||
crate::methods::MAP_IDENTITY_INFO,
|
||||
crate::methods::MAP_UNWRAP_OR_INFO,
|
||||
crate::methods::MUT_MUTEX_LOCK_INFO,
|
||||
crate::methods::NAIVE_BYTECOUNT_INFO,
|
||||
crate::methods::NEEDLESS_COLLECT_INFO,
|
||||
crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO,
|
||||
crate::methods::NEEDLESS_OPTION_TAKE_INFO,
|
||||
crate::methods::NEEDLESS_SPLITN_INFO,
|
||||
crate::methods::NEW_RET_NO_SELF_INFO,
|
||||
crate::methods::NONSENSICAL_OPEN_OPTIONS_INFO,
|
||||
crate::methods::NO_EFFECT_REPLACE_INFO,
|
||||
crate::methods::OBFUSCATED_IF_ELSE_INFO,
|
||||
crate::methods::OK_EXPECT_INFO,
|
||||
crate::methods::OPTION_AS_REF_DEREF_INFO,
|
||||
crate::methods::OPTION_FILTER_MAP_INFO,
|
||||
crate::methods::OPTION_MAP_OR_NONE_INFO,
|
||||
crate::methods::OR_FUN_CALL_INFO,
|
||||
crate::methods::OR_THEN_UNWRAP_INFO,
|
||||
crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
|
||||
crate::methods::RANGE_ZIP_WITH_LEN_INFO,
|
||||
crate::methods::REPEAT_ONCE_INFO,
|
||||
crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
|
||||
crate::methods::SEARCH_IS_SOME_INFO,
|
||||
crate::methods::SEEK_FROM_CURRENT_INFO,
|
||||
crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO,
|
||||
crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO,
|
||||
crate::methods::SINGLE_CHAR_ADD_STR_INFO,
|
||||
crate::methods::SINGLE_CHAR_PATTERN_INFO,
|
||||
crate::methods::SKIP_WHILE_NEXT_INFO,
|
||||
crate::methods::STABLE_SORT_PRIMITIVE_INFO,
|
||||
crate::methods::STRING_EXTEND_CHARS_INFO,
|
||||
crate::methods::SUSPICIOUS_MAP_INFO,
|
||||
crate::methods::SUSPICIOUS_SPLITN_INFO,
|
||||
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
|
||||
crate::methods::UNINIT_ASSUMED_INIT_INFO,
|
||||
crate::methods::UNIT_HASH_INFO,
|
||||
crate::methods::UNNECESSARY_FILTER_MAP_INFO,
|
||||
crate::methods::UNNECESSARY_FIND_MAP_INFO,
|
||||
crate::methods::UNNECESSARY_FOLD_INFO,
|
||||
crate::methods::UNNECESSARY_JOIN_INFO,
|
||||
crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
|
||||
crate::methods::UNNECESSARY_SORT_BY_INFO,
|
||||
crate::methods::UNNECESSARY_TO_OWNED_INFO,
|
||||
crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
|
||||
crate::methods::UNWRAP_USED_INFO,
|
||||
crate::methods::USELESS_ASREF_INFO,
|
||||
crate::methods::VEC_RESIZE_TO_ZERO_INFO,
|
||||
crate::methods::VERBOSE_FILE_READS_INFO,
|
||||
crate::methods::WRONG_SELF_CONVENTION_INFO,
|
||||
crate::methods::ZST_OFFSET_INFO,
|
||||
crate::minmax::MIN_MAX_INFO,
|
||||
crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
|
||||
crate::misc::TOPLEVEL_REF_ARG_INFO,
|
||||
crate::misc::USED_UNDERSCORE_BINDING_INFO,
|
||||
crate::misc::ZERO_PTR_INFO,
|
||||
crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
|
||||
crate::misc_early::DOUBLE_NEG_INFO,
|
||||
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
|
||||
crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
|
||||
crate::misc_early::REDUNDANT_PATTERN_INFO,
|
||||
crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO,
|
||||
crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
|
||||
crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
|
||||
crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
|
||||
crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
|
||||
crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
|
||||
crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
|
||||
crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
|
||||
crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
|
||||
crate::missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS_INFO,
|
||||
crate::missing_trait_methods::MISSING_TRAIT_METHODS_INFO,
|
||||
crate::mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION_INFO,
|
||||
crate::mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION_INFO,
|
||||
crate::module_style::MOD_MODULE_FILES_INFO,
|
||||
crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
|
||||
crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
|
||||
crate::mut_key::MUTABLE_KEY_TYPE_INFO,
|
||||
crate::mut_mut::MUT_MUT_INFO,
|
||||
crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,
|
||||
crate::mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL_INFO,
|
||||
crate::mutex_atomic::MUTEX_ATOMIC_INFO,
|
||||
crate::mutex_atomic::MUTEX_INTEGER_INFO,
|
||||
crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
|
||||
crate::needless_bool::BOOL_COMPARISON_INFO,
|
||||
crate::needless_bool::NEEDLESS_BOOL_INFO,
|
||||
crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
|
||||
crate::needless_continue::NEEDLESS_CONTINUE_INFO,
|
||||
crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
|
||||
crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
|
||||
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
|
||||
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
|
||||
crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
|
||||
crate::needless_update::NEEDLESS_UPDATE_INFO,
|
||||
crate::neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD_INFO,
|
||||
crate::neg_multiply::NEG_MULTIPLY_INFO,
|
||||
crate::new_without_default::NEW_WITHOUT_DEFAULT_INFO,
|
||||
crate::no_effect::NO_EFFECT_INFO,
|
||||
crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
|
||||
crate::no_effect::UNNECESSARY_OPERATION_INFO,
|
||||
crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
|
||||
crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
|
||||
crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
|
||||
crate::non_expressive_names::MANY_SINGLE_CHAR_NAMES_INFO,
|
||||
crate::non_expressive_names::SIMILAR_NAMES_INFO,
|
||||
crate::non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS_INFO,
|
||||
crate::non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY_INFO,
|
||||
crate::nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES_INFO,
|
||||
crate::octal_escapes::OCTAL_ESCAPES_INFO,
|
||||
crate::only_used_in_recursion::ONLY_USED_IN_RECURSION_INFO,
|
||||
crate::operators::ABSURD_EXTREME_COMPARISONS_INFO,
|
||||
crate::operators::ARITHMETIC_SIDE_EFFECTS_INFO,
|
||||
crate::operators::ASSIGN_OP_PATTERN_INFO,
|
||||
crate::operators::BAD_BIT_MASK_INFO,
|
||||
crate::operators::CMP_NAN_INFO,
|
||||
crate::operators::CMP_OWNED_INFO,
|
||||
crate::operators::DOUBLE_COMPARISONS_INFO,
|
||||
crate::operators::DURATION_SUBSEC_INFO,
|
||||
crate::operators::EQ_OP_INFO,
|
||||
crate::operators::ERASING_OP_INFO,
|
||||
crate::operators::FLOAT_ARITHMETIC_INFO,
|
||||
crate::operators::FLOAT_CMP_INFO,
|
||||
crate::operators::FLOAT_CMP_CONST_INFO,
|
||||
crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
|
||||
crate::operators::IDENTITY_OP_INFO,
|
||||
crate::operators::INEFFECTIVE_BIT_MASK_INFO,
|
||||
crate::operators::INTEGER_ARITHMETIC_INFO,
|
||||
crate::operators::INTEGER_DIVISION_INFO,
|
||||
crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
|
||||
crate::operators::MODULO_ARITHMETIC_INFO,
|
||||
crate::operators::MODULO_ONE_INFO,
|
||||
crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
|
||||
crate::operators::OP_REF_INFO,
|
||||
crate::operators::PTR_EQ_INFO,
|
||||
crate::operators::SELF_ASSIGNMENT_INFO,
|
||||
crate::operators::VERBOSE_BIT_MASK_INFO,
|
||||
crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
|
||||
crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO,
|
||||
crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO,
|
||||
crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO,
|
||||
crate::panic_unimplemented::PANIC_INFO,
|
||||
crate::panic_unimplemented::TODO_INFO,
|
||||
crate::panic_unimplemented::UNIMPLEMENTED_INFO,
|
||||
crate::panic_unimplemented::UNREACHABLE_INFO,
|
||||
crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO,
|
||||
crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO,
|
||||
crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
|
||||
crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
|
||||
crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
|
||||
crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
|
||||
crate::precedence::PRECEDENCE_INFO,
|
||||
crate::ptr::CMP_NULL_INFO,
|
||||
crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
|
||||
crate::ptr::MUT_FROM_REF_INFO,
|
||||
crate::ptr::PTR_ARG_INFO,
|
||||
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
|
||||
crate::pub_use::PUB_USE_INFO,
|
||||
crate::question_mark::QUESTION_MARK_INFO,
|
||||
crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
|
||||
crate::ranges::RANGE_MINUS_ONE_INFO,
|
||||
crate::ranges::RANGE_PLUS_ONE_INFO,
|
||||
crate::ranges::REVERSED_EMPTY_RANGES_INFO,
|
||||
crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
|
||||
crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
|
||||
crate::redundant_clone::REDUNDANT_CLONE_INFO,
|
||||
crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
|
||||
crate::redundant_else::REDUNDANT_ELSE_INFO,
|
||||
crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
|
||||
crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
|
||||
crate::redundant_slicing::DEREF_BY_SLICING_INFO,
|
||||
crate::redundant_slicing::REDUNDANT_SLICING_INFO,
|
||||
crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
|
||||
crate::ref_option_ref::REF_OPTION_REF_INFO,
|
||||
crate::reference::DEREF_ADDROF_INFO,
|
||||
crate::regex::INVALID_REGEX_INFO,
|
||||
crate::regex::TRIVIAL_REGEX_INFO,
|
||||
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
|
||||
crate::returns::LET_AND_RETURN_INFO,
|
||||
crate::returns::NEEDLESS_RETURN_INFO,
|
||||
crate::same_name_method::SAME_NAME_METHOD_INFO,
|
||||
crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
|
||||
crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
|
||||
crate::serde_api::SERDE_API_MISUSE_INFO,
|
||||
crate::shadow::SHADOW_REUSE_INFO,
|
||||
crate::shadow::SHADOW_SAME_INFO,
|
||||
crate::shadow::SHADOW_UNRELATED_INFO,
|
||||
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
|
||||
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
|
||||
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
|
||||
crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
|
||||
crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
|
||||
crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
|
||||
crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO,
|
||||
crate::strings::STRING_ADD_INFO,
|
||||
crate::strings::STRING_ADD_ASSIGN_INFO,
|
||||
crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO,
|
||||
crate::strings::STRING_LIT_AS_BYTES_INFO,
|
||||
crate::strings::STRING_SLICE_INFO,
|
||||
crate::strings::STRING_TO_STRING_INFO,
|
||||
crate::strings::STR_TO_STRING_INFO,
|
||||
crate::strings::TRIM_SPLIT_WHITESPACE_INFO,
|
||||
crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO,
|
||||
crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
|
||||
crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
|
||||
crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
|
||||
crate::suspicious_xor_used_as_pow::SUSPICIOUS_XOR_USED_AS_POW_INFO,
|
||||
crate::swap::ALMOST_SWAPPED_INFO,
|
||||
crate::swap::MANUAL_SWAP_INFO,
|
||||
crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO,
|
||||
crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
|
||||
crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
|
||||
crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
|
||||
crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
|
||||
crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
|
||||
crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
|
||||
crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
|
||||
crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
|
||||
crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
|
||||
crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
|
||||
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
|
||||
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
|
||||
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
|
||||
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
|
||||
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
|
||||
crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
|
||||
crate::transmute::TRANSMUTE_UNDEFINED_REPR_INFO,
|
||||
crate::transmute::TRANSMUTING_NULL_INFO,
|
||||
crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO,
|
||||
crate::transmute::USELESS_TRANSMUTE_INFO,
|
||||
crate::transmute::WRONG_TRANSMUTE_INFO,
|
||||
crate::types::BORROWED_BOX_INFO,
|
||||
crate::types::BOX_COLLECTION_INFO,
|
||||
crate::types::LINKEDLIST_INFO,
|
||||
crate::types::OPTION_OPTION_INFO,
|
||||
crate::types::RC_BUFFER_INFO,
|
||||
crate::types::RC_MUTEX_INFO,
|
||||
crate::types::REDUNDANT_ALLOCATION_INFO,
|
||||
crate::types::TYPE_COMPLEXITY_INFO,
|
||||
crate::types::VEC_BOX_INFO,
|
||||
crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
|
||||
crate::unicode::INVISIBLE_CHARACTERS_INFO,
|
||||
crate::unicode::NON_ASCII_LITERAL_INFO,
|
||||
crate::unicode::UNICODE_NOT_NFC_INFO,
|
||||
crate::uninit_vec::UNINIT_VEC_INFO,
|
||||
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
|
||||
crate::unit_types::LET_UNIT_VALUE_INFO,
|
||||
crate::unit_types::UNIT_ARG_INFO,
|
||||
crate::unit_types::UNIT_CMP_INFO,
|
||||
crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
|
||||
crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
|
||||
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
|
||||
crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
|
||||
crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
|
||||
crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO,
|
||||
crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO,
|
||||
crate::unused_async::UNUSED_ASYNC_INFO,
|
||||
crate::unused_io_amount::UNUSED_IO_AMOUNT_INFO,
|
||||
crate::unused_peekable::UNUSED_PEEKABLE_INFO,
|
||||
crate::unused_rounding::UNUSED_ROUNDING_INFO,
|
||||
crate::unused_self::UNUSED_SELF_INFO,
|
||||
crate::unused_unit::UNUSED_UNIT_INFO,
|
||||
crate::unwrap::PANICKING_UNWRAP_INFO,
|
||||
crate::unwrap::UNNECESSARY_UNWRAP_INFO,
|
||||
crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO,
|
||||
crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO,
|
||||
crate::use_self::USE_SELF_INFO,
|
||||
crate::useless_conversion::USELESS_CONVERSION_INFO,
|
||||
crate::vec::USELESS_VEC_INFO,
|
||||
crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
|
||||
crate::wildcard_imports::ENUM_GLOB_USE_INFO,
|
||||
crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
|
||||
crate::write::PRINTLN_EMPTY_STRING_INFO,
|
||||
crate::write::PRINT_LITERAL_INFO,
|
||||
crate::write::PRINT_STDERR_INFO,
|
||||
crate::write::PRINT_STDOUT_INFO,
|
||||
crate::write::PRINT_WITH_NEWLINE_INFO,
|
||||
crate::write::USE_DEBUG_INFO,
|
||||
crate::write::WRITELN_EMPTY_STRING_INFO,
|
||||
crate::write::WRITE_LITERAL_INFO,
|
||||
crate::write::WRITE_WITH_NEWLINE_INFO,
|
||||
crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO,
|
||||
crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO,
|
||||
];
|
|
@ -9,6 +9,7 @@ use clippy_utils::{
|
|||
};
|
||||
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_ty, Visitor};
|
||||
use rustc_hir::{
|
||||
|
@ -274,9 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
}
|
||||
|
||||
let typeck = cx.typeck_results();
|
||||
let (kind, sub_expr) = if let Some(x) = try_parse_ref_op(cx.tcx, typeck, expr) {
|
||||
x
|
||||
} else {
|
||||
let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
|
||||
// The whole chain of reference operations has been seen
|
||||
if let Some((state, data)) = self.state.take() {
|
||||
report(cx, expr, state, data);
|
||||
|
@ -806,30 +805,39 @@ fn walk_parents<'tcx>(
|
|||
.position(|arg| arg.hir_id == child_id)
|
||||
.zip(expr_sig(cx, func))
|
||||
.and_then(|(i, sig)| {
|
||||
sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty {
|
||||
// Type inference for closures can depend on how they're called. Only go by the explicit
|
||||
// types here.
|
||||
Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
|
||||
None => {
|
||||
if let ty::Param(param_ty) = ty.skip_binder().kind() {
|
||||
needless_borrow_impl_arg_position(
|
||||
cx,
|
||||
possible_borrowers,
|
||||
parent,
|
||||
i,
|
||||
*param_ty,
|
||||
e,
|
||||
precedence,
|
||||
msrv,
|
||||
)
|
||||
} else {
|
||||
ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
|
||||
.position_for_arg()
|
||||
}
|
||||
},
|
||||
sig.input_with_hir(i).map(|(hir_ty, ty)| {
|
||||
match hir_ty {
|
||||
// Type inference for closures can depend on how they're called. Only go by the explicit
|
||||
// types here.
|
||||
Some(hir_ty) => {
|
||||
binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
|
||||
},
|
||||
None => {
|
||||
// `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
|
||||
// `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
|
||||
if e.hir_id == child_id
|
||||
&& !call_is_qualified(func)
|
||||
&& let ty::Param(param_ty) = ty.skip_binder().kind()
|
||||
{
|
||||
needless_borrow_impl_arg_position(
|
||||
cx,
|
||||
possible_borrowers,
|
||||
parent,
|
||||
i,
|
||||
*param_ty,
|
||||
e,
|
||||
precedence,
|
||||
msrv,
|
||||
)
|
||||
} else {
|
||||
ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
|
||||
.position_for_arg()
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
}),
|
||||
ExprKind::MethodCall(_, receiver, args, _) => {
|
||||
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
||||
if receiver.hir_id == child_id {
|
||||
// Check for calls to trait methods where the trait is implemented on a reference.
|
||||
|
@ -867,7 +875,9 @@ fn walk_parents<'tcx>(
|
|||
}
|
||||
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
|
||||
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
|
||||
if let ty::Param(param_ty) = ty.kind() {
|
||||
// `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() {
|
||||
needless_borrow_impl_arg_position(
|
||||
cx,
|
||||
possible_borrowers,
|
||||
|
@ -1045,13 +1055,25 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
|
|||
v.0
|
||||
}
|
||||
|
||||
fn call_is_qualified(expr: &Expr<'_>) -> bool {
|
||||
if let ExprKind::Path(path) = &expr.kind {
|
||||
match path {
|
||||
QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
|
||||
QPath::TypeRelative(_, segment) => segment.args.is_some(),
|
||||
QPath::LangItem(..) => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Checks whether:
|
||||
// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
|
||||
// * `e`'s type implements `Trait` and is copyable
|
||||
// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
|
||||
// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
|
||||
// be moved, but it cannot be.
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
|
||||
fn needless_borrow_impl_arg_position<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
|
||||
|
@ -1113,6 +1135,16 @@ fn needless_borrow_impl_arg_position<'tcx>(
|
|||
return Position::Other(precedence);
|
||||
}
|
||||
|
||||
// See:
|
||||
// - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1289294201
|
||||
// - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
|
||||
if projection_predicates
|
||||
.iter()
|
||||
.any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
|
||||
{
|
||||
return Position::Other(precedence);
|
||||
}
|
||||
|
||||
// `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
|
||||
// elements are modified each time `check_referent` is called.
|
||||
let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
|
||||
|
@ -1192,6 +1224,37 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
|
|||
})
|
||||
}
|
||||
|
||||
fn is_mixed_projection_predicate<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
callee_def_id: DefId,
|
||||
projection_predicate: &ProjectionPredicate<'tcx>,
|
||||
) -> bool {
|
||||
let generics = cx.tcx.generics_of(callee_def_id);
|
||||
// The predicate requires the projected type to equal a type parameter from the parent context.
|
||||
if let Some(term_ty) = projection_predicate.term.ty()
|
||||
&& let ty::Param(term_param_ty) = term_ty.kind()
|
||||
&& (term_param_ty.index as usize) < generics.parent_count
|
||||
{
|
||||
// The inner-most self type is a type parameter from the current function.
|
||||
let mut projection_ty = projection_predicate.projection_ty;
|
||||
loop {
|
||||
match projection_ty.self_ty().kind() {
|
||||
ty::Projection(inner_projection_ty) => {
|
||||
projection_ty = *inner_projection_ty;
|
||||
}
|
||||
ty::Param(param_ty) => {
|
||||
return (param_ty.index as usize) >= generics.parent_count;
|
||||
}
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn referent_used_exactly_once<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
|
||||
|
@ -1203,6 +1266,8 @@ fn referent_used_exactly_once<'tcx>(
|
|||
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
|
||||
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
|
||||
&& !place.has_deref()
|
||||
// Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
|
||||
&& TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
|
||||
{
|
||||
let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
|
||||
if possible_borrowers
|
||||
|
@ -1320,6 +1385,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
|
|||
continue;
|
||||
},
|
||||
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||
ty::Projection(_) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||
ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
|
||||
Position::ReborrowStable(precedence).into()
|
||||
},
|
||||
|
@ -1346,11 +1412,9 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
|
|||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Projection(_) => Position::DerefStable(
|
||||
precedence,
|
||||
ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
|
||||
)
|
||||
.into(),
|
||||
| ty::Projection(_) => {
|
||||
Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -89,7 +88,7 @@ impl DisallowedMacros {
|
|||
&format!("use of a disallowed macro `{}`", conf.path()),
|
||||
|diag| {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(&format!("{reason} (from clippy.toml)"));
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -104,7 +103,7 @@ impl LateLintPass<'_> for DisallowedMacros {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::MacroNS)) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
|
||||
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
|||
let msg = format!("use of a disallowed method `{}`", conf.path());
|
||||
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(&format!("{reason} (from clippy.toml)"));
|
||||
diag.note(reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -53,8 +53,8 @@ declare_clippy_lint! {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedTypes {
|
||||
conf_disallowed: Vec<conf::DisallowedPath>,
|
||||
def_ids: FxHashMap<DefId, Option<String>>,
|
||||
prim_tys: FxHashMap<PrimTy, Option<String>>,
|
||||
def_ids: FxHashMap<DefId, usize>,
|
||||
prim_tys: FxHashMap<PrimTy, usize>,
|
||||
}
|
||||
|
||||
impl DisallowedTypes {
|
||||
|
@ -69,13 +69,13 @@ impl DisallowedTypes {
|
|||
fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
|
||||
match res {
|
||||
Res::Def(_, did) => {
|
||||
if let Some(reason) = self.def_ids.get(did) {
|
||||
emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
|
||||
if let Some(&index) = self.def_ids.get(did) {
|
||||
emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
|
||||
}
|
||||
},
|
||||
Res::PrimTy(prim) => {
|
||||
if let Some(reason) = self.prim_tys.get(prim) {
|
||||
emit(cx, prim.name_str(), span, reason.as_deref());
|
||||
if let Some(&index) = self.prim_tys.get(prim) {
|
||||
emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
|
@ -87,17 +87,19 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for conf in &self.conf_disallowed {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
let reason = conf.reason().map(|reason| format!("{reason} (from clippy.toml)"));
|
||||
match clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
|
||||
Res::Def(_, id) => {
|
||||
self.def_ids.insert(id, reason);
|
||||
},
|
||||
Res::PrimTy(ty) => {
|
||||
self.prim_tys.insert(ty, reason);
|
||||
},
|
||||
_ => {},
|
||||
|
||||
for res in clippy_utils::def_path_res(cx, &segs) {
|
||||
match res {
|
||||
Res::Def(_, id) => {
|
||||
self.def_ids.insert(id, index);
|
||||
},
|
||||
Res::PrimTy(ty) => {
|
||||
self.prim_tys.insert(ty, index);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,14 +121,14 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
|
||||
fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DISALLOWED_TYPES,
|
||||
span,
|
||||
&format!("`{name}` is not allowed according to config"),
|
||||
|diag| {
|
||||
if let Some(reason) = reason {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_ast::token::CommentKind;
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::emitter::EmitterWriter;
|
||||
use rustc_errors::{Applicability, Handler, MultiSpan, SuggestionStyle};
|
||||
use rustc_errors::{Applicability, Handler, SuggestionStyle};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{AnonConst, Expr};
|
||||
|
@ -221,6 +221,42 @@ declare_clippy_lint! {
|
|||
"possible typo for an intra-doc link"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for the doc comments of publicly visible
|
||||
/// safe functions and traits and warns if there is a `# Safety` section.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Safe functions and traits are safe to implement and therefore do not
|
||||
/// need to describe safety preconditions that users are required to uphold.
|
||||
///
|
||||
/// ### Examples
|
||||
/// ```rust
|
||||
///# type Universe = ();
|
||||
/// /// # Safety
|
||||
/// ///
|
||||
/// /// This function should not be called before the horsemen are ready.
|
||||
/// pub fn start_apocalypse_but_safely(u: &mut Universe) {
|
||||
/// unimplemented!();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The function is safe, so there shouldn't be any preconditions
|
||||
/// that have to be explained for safety reasons.
|
||||
///
|
||||
/// ```rust
|
||||
///# type Universe = ();
|
||||
/// /// This function should really be documented
|
||||
/// pub fn start_apocalypse(u: &mut Universe) {
|
||||
/// unimplemented!();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub UNNECESSARY_SAFETY_DOC,
|
||||
style,
|
||||
"`pub fn` or `pub trait` with `# Safety` docs"
|
||||
}
|
||||
|
||||
#[expect(clippy::module_name_repetitions)]
|
||||
#[derive(Clone)]
|
||||
pub struct DocMarkdown {
|
||||
|
@ -243,7 +279,8 @@ impl_lint_pass!(DocMarkdown => [
|
|||
MISSING_SAFETY_DOC,
|
||||
MISSING_ERRORS_DOC,
|
||||
MISSING_PANICS_DOC,
|
||||
NEEDLESS_DOCTEST_MAIN
|
||||
NEEDLESS_DOCTEST_MAIN,
|
||||
UNNECESSARY_SAFETY_DOC,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||
|
@ -254,7 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let headers = check_attrs(cx, &self.valid_idents, attrs);
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
|
||||
match item.kind {
|
||||
hir::ItemKind::Fn(ref sig, _, body_id) => {
|
||||
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
|
||||
|
@ -265,29 +302,26 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(body.value);
|
||||
lint_for_missing_headers(
|
||||
cx,
|
||||
item.owner_id.def_id,
|
||||
item.span,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
fpu.panic_span,
|
||||
);
|
||||
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
},
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
self.in_trait_impl = impl_.of_trait.is_some();
|
||||
},
|
||||
hir::ItemKind::Trait(_, unsafety, ..) => {
|
||||
if !headers.safety && unsafety == hir::Unsafety::Unsafe {
|
||||
span_lint(
|
||||
cx,
|
||||
MISSING_SAFETY_DOC,
|
||||
item.span,
|
||||
"docs for unsafe trait missing `# Safety` section",
|
||||
);
|
||||
}
|
||||
hir::ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
|
||||
(false, hir::Unsafety::Unsafe) => span_lint(
|
||||
cx,
|
||||
MISSING_SAFETY_DOC,
|
||||
cx.tcx.def_span(item.owner_id),
|
||||
"docs for unsafe trait missing `# Safety` section",
|
||||
),
|
||||
(true, hir::Unsafety::Normal) => span_lint(
|
||||
cx,
|
||||
UNNECESSARY_SAFETY_DOC,
|
||||
cx.tcx.def_span(item.owner_id),
|
||||
"docs for safe trait have unnecessary `# Safety` section",
|
||||
),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
@ -301,17 +335,17 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let headers = check_attrs(cx, &self.valid_idents, attrs);
|
||||
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, item.span, sig, headers, None, None);
|
||||
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
let headers = check_attrs(cx, &self.valid_idents, attrs);
|
||||
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
|
||||
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
|
@ -323,23 +357,14 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(body.value);
|
||||
lint_for_missing_headers(
|
||||
cx,
|
||||
item.owner_id.def_id,
|
||||
item.span,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
fpu.panic_span,
|
||||
);
|
||||
lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_for_missing_headers<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
fn lint_for_missing_headers(
|
||||
cx: &LateContext<'_>,
|
||||
def_id: LocalDefId,
|
||||
span: impl Into<MultiSpan> + Copy,
|
||||
sig: &hir::FnSig<'_>,
|
||||
headers: DocHeaders,
|
||||
body_id: Option<hir::BodyId>,
|
||||
|
@ -359,13 +384,21 @@ fn lint_for_missing_headers<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
|
||||
span_lint(
|
||||
let span = cx.tcx.def_span(def_id);
|
||||
match (headers.safety, sig.header.unsafety) {
|
||||
(false, hir::Unsafety::Unsafe) => span_lint(
|
||||
cx,
|
||||
MISSING_SAFETY_DOC,
|
||||
span,
|
||||
"unsafe function's docs miss `# Safety` section",
|
||||
);
|
||||
),
|
||||
(true, hir::Unsafety::Normal) => span_lint(
|
||||
cx,
|
||||
UNNECESSARY_SAFETY_DOC,
|
||||
span,
|
||||
"safe function's docs have unnecessary `# Safety` section",
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
if !headers.panics && panic_span.is_some() {
|
||||
span_lint_and_note(
|
||||
|
@ -467,7 +500,7 @@ struct DocHeaders {
|
|||
panics: bool,
|
||||
}
|
||||
|
||||
fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders {
|
||||
fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
|
||||
use pulldown_cmark::{BrokenLink, CowStr, Options};
|
||||
/// We don't want the parser to choke on intra doc links. Since we don't
|
||||
/// actually care about rendering them, just pretend that all broken links are
|
||||
|
@ -488,11 +521,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
|
|||
} else if attr.has_name(sym::doc) {
|
||||
// ignore mix of sugared and non-sugared doc
|
||||
// don't trigger the safety or errors check
|
||||
return DocHeaders {
|
||||
safety: true,
|
||||
errors: true,
|
||||
panics: true,
|
||||
};
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -504,7 +533,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
|
|||
}
|
||||
|
||||
if doc.is_empty() {
|
||||
return DocHeaders::default();
|
||||
return Some(DocHeaders::default());
|
||||
}
|
||||
|
||||
let mut cb = fake_broken_link_callback;
|
||||
|
@ -527,7 +556,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
|
|||
(previous, current) => Err(((previous, previous_range), (current, current_range))),
|
||||
}
|
||||
});
|
||||
check_doc(cx, valid_idents, events, &spans)
|
||||
Some(check_doc(cx, valid_idents, events, &spans))
|
||||
}
|
||||
|
||||
const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
|
||||
|
|
|
@ -250,7 +250,7 @@ impl LateLintPass<'_> for EnumVariantNames {
|
|||
let item_name = item.ident.name.as_str();
|
||||
let item_camel = to_camel_case(item_name);
|
||||
if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
|
||||
if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
|
||||
if let Some((mod_name, mod_camel)) = self.modules.last() {
|
||||
// constants don't have surrounding modules
|
||||
if !mod_camel.is_empty() {
|
||||
if mod_name == &item.ident.name {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Pat, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
@ -67,16 +66,14 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if_chain! {
|
||||
if !in_external_macro(cx.sess(), expr.span);
|
||||
if let ExprKind::Let(let_expr) = expr.kind;
|
||||
if unary_pattern(let_expr.pat);
|
||||
if !in_external_macro(cx.sess(), expr.span)
|
||||
&& let ExprKind::Let(let_expr) = expr.kind
|
||||
&& unary_pattern(let_expr.pat) {
|
||||
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
|
||||
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
|
||||
if is_structural_partial_eq(cx, exp_ty, pat_ty);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
if is_structural_partial_eq(cx, exp_ty, pat_ty) {
|
||||
let pat_str = match let_expr.pat.kind {
|
||||
PatKind::Struct(..) => format!(
|
||||
"({})",
|
||||
|
@ -96,6 +93,20 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
|
|||
),
|
||||
applicability,
|
||||
);
|
||||
} else {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
EQUATABLE_IF_LET,
|
||||
expr.span,
|
||||
"this pattern matching can be expressed using `matches!`",
|
||||
"try",
|
||||
format!(
|
||||
"matches!({}, {})",
|
||||
snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
|
||||
snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,13 +176,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fake_read(
|
||||
&mut self,
|
||||
_: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
|
||||
_: FakeReadCause,
|
||||
_: HirId,
|
||||
) {
|
||||
}
|
||||
fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{AssocItemKind, Extern, Fn, FnSig, Impl, Item, ItemKind, Trait, Ty, TyKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
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_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -83,6 +86,12 @@ pub struct ExcessiveBools {
|
|||
max_fn_params_bools: u64,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||
enum Kind {
|
||||
Struct,
|
||||
Fn,
|
||||
}
|
||||
|
||||
impl ExcessiveBools {
|
||||
#[must_use]
|
||||
pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self {
|
||||
|
@ -92,21 +101,20 @@ impl ExcessiveBools {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) {
|
||||
match fn_sig.header.ext {
|
||||
Extern::Implicit(_) | Extern::Explicit(_, _) => return,
|
||||
Extern::None => (),
|
||||
fn too_many_bools<'tcx>(&self, tys: impl Iterator<Item = &'tcx Ty<'tcx>>, kind: Kind) -> bool {
|
||||
if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() {
|
||||
(if Kind::Fn == kind {
|
||||
self.max_fn_params_bools
|
||||
} else {
|
||||
self.max_struct_bools
|
||||
}) < bools
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
let fn_sig_bools = fn_sig
|
||||
.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.filter(|param| is_bool_ty(¶m.ty))
|
||||
.count()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
if self.max_fn_params_bools < fn_sig_bools {
|
||||
fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) {
|
||||
if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
FN_PARAMS_EXCESSIVE_BOOLS,
|
||||
|
@ -121,56 +129,55 @@ impl ExcessiveBools {
|
|||
|
||||
impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
|
||||
|
||||
fn is_bool_ty(ty: &Ty) -> bool {
|
||||
if let TyKind::Path(None, path) = &ty.kind {
|
||||
if let [name] = path.segments.as_slice() {
|
||||
return name.ident.name == sym::bool;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
impl EarlyLintPass for ExcessiveBools {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if item.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
match &item.kind {
|
||||
ItemKind::Struct(variant_data, _) => {
|
||||
if item.attrs.iter().any(|attr| attr.has_name(sym::repr)) {
|
||||
return;
|
||||
}
|
||||
if let ItemKind::Struct(variant_data, _) = &item.kind {
|
||||
if has_repr_attr(cx, item.hir_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let struct_bools = variant_data
|
||||
.fields()
|
||||
.iter()
|
||||
.filter(|field| is_bool_ty(&field.ty))
|
||||
.count()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
if self.max_struct_bools < struct_bools {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
STRUCT_EXCESSIVE_BOOLS,
|
||||
item.span,
|
||||
&format!("more than {} bools in a struct", self.max_struct_bools),
|
||||
None,
|
||||
"consider using a state machine or refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
},
|
||||
ItemKind::Impl(box Impl {
|
||||
of_trait: None, items, ..
|
||||
})
|
||||
| ItemKind::Trait(box Trait { items, .. }) => {
|
||||
for item in items {
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_fn_sig(cx, sig, item.span);
|
||||
}
|
||||
}
|
||||
},
|
||||
ItemKind::Fn(box Fn { sig, .. }) => self.check_fn_sig(cx, sig, item.span),
|
||||
_ => (),
|
||||
if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
STRUCT_EXCESSIVE_BOOLS,
|
||||
item.span,
|
||||
&format!("more than {} bools in a struct", self.max_struct_bools),
|
||||
None,
|
||||
"consider using a state machine or refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'tcx>) {
|
||||
// functions with a body are already checked by `check_fn`
|
||||
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
|
||||
&& fn_sig.header.abi == Abi::Rust
|
||||
{
|
||||
self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
fn_kind: FnKind<'tcx>,
|
||||
fn_decl: &'tcx FnDecl<'tcx>,
|
||||
_: &'tcx Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
if let Some(fn_header) = fn_kind.header()
|
||||
&& fn_header.abi == Abi::Rust
|
||||
&& get_parent_as_impl(cx.tcx, hir_id)
|
||||
.map_or(true,
|
||||
|impl_item| impl_item.of_trait.is_none()
|
||||
)
|
||||
{
|
||||
self.check_fn_sig(cx, fn_decl, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
|
|||
}
|
||||
}
|
||||
|
||||
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
|
||||
fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Expr, ImplItemKind};
|
||||
|
||||
|
|
77
clippy_lints/src/from_raw_with_void_ptr.rs
Normal file
77
clippy_lints/src/from_raw_with_void_ptr.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_c_void;
|
||||
use clippy_utils::{match_def_path, path_def_id, paths};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::RawPtr;
|
||||
use rustc_middle::ty::TypeAndMut;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks if we're passing a `c_void` raw pointer to `{Box,Rc,Arc,Weak}::from_raw(_)`
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// When dealing with `c_void` raw pointers in FFI, it is easy to run into the pitfall of calling `from_raw` with the `c_void` pointer.
|
||||
/// The type signature of `Box::from_raw` is `fn from_raw(raw: *mut T) -> Box<T>`, so if you pass a `*mut c_void` you will get a `Box<c_void>` (and similarly for `Rc`, `Arc` and `Weak`).
|
||||
/// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::ffi::c_void;
|
||||
/// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
|
||||
/// let _ = unsafe { Box::from_raw(ptr) };
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::ffi::c_void;
|
||||
/// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
|
||||
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
|
||||
/// ```
|
||||
///
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub FROM_RAW_WITH_VOID_PTR,
|
||||
suspicious,
|
||||
"creating a `Box` from a void raw pointer"
|
||||
}
|
||||
declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]);
|
||||
|
||||
impl LateLintPass<'_> for FromRawWithVoidPtr {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
|
||||
&& seg.ident.name == sym!(from_raw)
|
||||
&& let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
|
||||
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
|
||||
&& let RawPtr(TypeAndMut { ty, .. }) = arg_kind
|
||||
&& is_c_void(cx, *ty) {
|
||||
let msg = format!("creating a `{type_str}` from a void raw pointer");
|
||||
span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether a `DefId` matches `Box`, `Rc`, `Arc`, or one of the `Weak` types.
|
||||
/// Returns a static string slice with the name of the type, if one was found.
|
||||
fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> {
|
||||
// Box
|
||||
if Some(def_id) == cx.tcx.lang_items().owned_box() {
|
||||
return Some("Box");
|
||||
}
|
||||
|
||||
if let Some(symbol) = cx.tcx.get_diagnostic_name(def_id) {
|
||||
if symbol == sym::Arc {
|
||||
return Some("Arc");
|
||||
} else if symbol == sym::Rc {
|
||||
return Some("Rc");
|
||||
}
|
||||
}
|
||||
|
||||
if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) {
|
||||
Some("Weak")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
|
@ -254,7 +254,7 @@ declare_clippy_lint! {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.64.0"]
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub RESULT_LARGE_ERR,
|
||||
perf,
|
||||
"function returning `Result` with large `Err` type"
|
||||
|
|
|
@ -50,7 +50,9 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
|
|||
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);
|
||||
} else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
||||
} else if is_public
|
||||
&& !is_proc_macro(cx.sess(), attrs)
|
||||
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
|
||||
{
|
||||
check_must_use_candidate(
|
||||
cx,
|
||||
|
@ -175,7 +177,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
|
|||
return false; // ignore `_` patterns
|
||||
}
|
||||
if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) {
|
||||
is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), pat.span, tys)
|
||||
is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), tys)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -183,7 +185,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
|
|||
|
||||
static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc];
|
||||
|
||||
fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool {
|
||||
fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) -> bool {
|
||||
match *ty.kind() {
|
||||
// primitive types are never mutable
|
||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
|
||||
|
@ -192,12 +194,12 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
|
|||
|| KNOWN_WRAPPER_TYS
|
||||
.iter()
|
||||
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
|
||||
&& substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
|
||||
&& substs.types().any(|ty| is_mutable_ty(cx, ty, tys))
|
||||
},
|
||||
ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)),
|
||||
ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, span, tys),
|
||||
ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
|
||||
ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
|
||||
ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
|
||||
mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, span, tys)
|
||||
mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
|
||||
},
|
||||
// calling something constitutes a side effect, so return true on all callables
|
||||
// also never calls need not be used, so return true for them, too
|
||||
|
@ -225,12 +227,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
|
|||
let mut tys = DefIdSet::default();
|
||||
for arg in args {
|
||||
if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
|
||||
&& is_mutable_ty(
|
||||
cx,
|
||||
cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
|
||||
arg.span,
|
||||
&mut tys,
|
||||
)
|
||||
&& is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys)
|
||||
&& is_mutated_static(arg)
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
|
@ -243,12 +240,7 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
|
|||
let mut tys = DefIdSet::default();
|
||||
for arg in std::iter::once(receiver).chain(args.iter()) {
|
||||
if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
|
||||
&& is_mutable_ty(
|
||||
cx,
|
||||
cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
|
||||
arg.span,
|
||||
&mut tys,
|
||||
)
|
||||
&& is_mutable_ty(cx, cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg), &mut tys)
|
||||
&& is_mutated_static(arg)
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
|
|
|
@ -2,12 +2,12 @@ use rustc_errors::Diagnostic;
|
|||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Adt, Ty};
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
|
||||
use clippy_utils::trait_ref_of_method;
|
||||
use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item, AdtVariantInfo};
|
||||
|
||||
use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
|
||||
|
||||
|
@ -84,17 +84,57 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S
|
|||
}
|
||||
|
||||
fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
|
||||
let ty_size = approx_ty_size(cx, err_ty);
|
||||
if ty_size >= large_err_threshold {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
RESULT_LARGE_ERR,
|
||||
hir_ty_span,
|
||||
"the `Err`-variant returned from this function is very large",
|
||||
|diag: &mut Diagnostic| {
|
||||
diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
|
||||
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
|
||||
},
|
||||
);
|
||||
if_chain! {
|
||||
if let Adt(adt, subst) = err_ty.kind();
|
||||
if let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local();
|
||||
if let Some(hir::Node::Item(item)) = cx
|
||||
.tcx
|
||||
.hir()
|
||||
.find_by_def_id(local_def_id);
|
||||
if let hir::ItemKind::Enum(ref def, _) = item.kind;
|
||||
then {
|
||||
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
|
||||
if variants_size[0].size >= large_err_threshold {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
RESULT_LARGE_ERR,
|
||||
hir_ty_span,
|
||||
"the `Err`-variant returned from this function is very large",
|
||||
|diag| {
|
||||
diag.span_label(
|
||||
def.variants[variants_size[0].ind].span,
|
||||
format!("the largest variant contains at least {} bytes", variants_size[0].size),
|
||||
);
|
||||
|
||||
for variant in &variants_size[1..] {
|
||||
if variant.size >= large_err_threshold {
|
||||
let variant_def = &def.variants[variant.ind];
|
||||
diag.span_label(
|
||||
variant_def.span,
|
||||
format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
let ty_size = approx_ty_size(cx, err_ty);
|
||||
if ty_size >= large_err_threshold {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
RESULT_LARGE_ERR,
|
||||
hir_ty_span,
|
||||
"the `Err`-variant returned from this function is very large",
|
||||
|diag: &mut Diagnostic| {
|
||||
diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
|
||||
diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,8 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
|||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
use rustc_span::BytePos;
|
||||
|
||||
fn suggestion<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
fn suggestion(
|
||||
cx: &LateContext<'_>,
|
||||
diag: &mut Diagnostic,
|
||||
generics_span: Span,
|
||||
generics_suggestion_span: Span,
|
||||
|
|
|
@ -207,8 +207,8 @@ impl SliceLintInformation {
|
|||
}
|
||||
}
|
||||
|
||||
fn filter_lintable_slices<'a, 'tcx>(
|
||||
cx: &'a LateContext<'tcx>,
|
||||
fn filter_lintable_slices<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
slice_lint_info: FxIndexMap<hir::HirId, SliceLintInformation>,
|
||||
max_suggested_slice: u64,
|
||||
scope: &'tcx hir::Expr<'tcx>,
|
||||
|
|
|
@ -171,11 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
|||
|
||||
/// Returns a tuple of options with the start and end (exclusive) values of
|
||||
/// the range. If the start or end is not constant, None is returned.
|
||||
fn to_const_range<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
range: higher::Range<'_>,
|
||||
array_size: u128,
|
||||
) -> (Option<u128>, Option<u128>) {
|
||||
fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) {
|
||||
let s = range
|
||||
.start
|
||||
.map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
|
||||
|
|
184
clippy_lints/src/instant_subtraction.rs
Normal file
184
clippy_lints/src/instant_subtraction.rs
Normal file
|
@ -0,0 +1,184 @@
|
|||
use clippy_utils::{
|
||||
diagnostics::{self, span_lint_and_sugg},
|
||||
meets_msrv, msrvs, source,
|
||||
sugg::Sugg,
|
||||
ty,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{source_map::Spanned, sym};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Lints subtraction between `Instant::now()` and another `Instant`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
|
||||
/// as `Instant` subtraction saturates.
|
||||
///
|
||||
/// `prev_instant.elapsed()` also more clearly signals intention.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// use std::time::Instant;
|
||||
/// let prev_instant = Instant::now();
|
||||
/// let duration = Instant::now() - prev_instant;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// use std::time::Instant;
|
||||
/// let prev_instant = Instant::now();
|
||||
/// let duration = prev_instant.elapsed();
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub MANUAL_INSTANT_ELAPSED,
|
||||
pedantic,
|
||||
"subtraction between `Instant::now()` and previous `Instant`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Lints subtraction between an [`Instant`] and a [`Duration`].
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Unchecked subtraction could cause underflow on certain platforms, leading to
|
||||
/// unintentional panics.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::time::{Instant, Duration};
|
||||
/// let time_passed = Instant::now() - Duration::from_secs(5);
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::time::{Instant, Duration};
|
||||
/// let time_passed = Instant::now().checked_sub(Duration::from_secs(5));
|
||||
/// ```
|
||||
///
|
||||
/// [`Duration`]: std::time::Duration
|
||||
/// [`Instant::now()`]: std::time::Instant::now;
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub UNCHECKED_DURATION_SUBTRACTION,
|
||||
suspicious,
|
||||
"finds unchecked subtraction of a 'Duration' from an 'Instant'"
|
||||
}
|
||||
|
||||
pub struct InstantSubtraction {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
|
||||
impl InstantSubtraction {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(InstantSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_DURATION_SUBTRACTION]);
|
||||
|
||||
impl LateLintPass<'_> for InstantSubtraction {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
|
||||
if let ExprKind::Binary(
|
||||
Spanned {
|
||||
node: BinOpKind::Sub, ..
|
||||
},
|
||||
lhs,
|
||||
rhs,
|
||||
) = expr.kind
|
||||
{
|
||||
if_chain! {
|
||||
if is_instant_now_call(cx, lhs);
|
||||
|
||||
if is_an_instant(cx, rhs);
|
||||
if let Some(sugg) = Sugg::hir_opt(cx, rhs);
|
||||
|
||||
then {
|
||||
print_manual_instant_elapsed_sugg(cx, expr, sugg)
|
||||
} else {
|
||||
if_chain! {
|
||||
if !expr.span.from_expansion();
|
||||
if meets_msrv(self.msrv, msrvs::TRY_FROM);
|
||||
|
||||
if is_an_instant(cx, lhs);
|
||||
if is_a_duration(cx, rhs);
|
||||
|
||||
then {
|
||||
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
|
||||
if let ExprKind::Call(fn_expr, []) = expr_block.kind
|
||||
&& let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
|
||||
&& clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let expr_ty = cx.typeck_results().expr_ty(expr);
|
||||
|
||||
match expr_ty.kind() {
|
||||
rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let expr_ty = cx.typeck_results().expr_ty(expr);
|
||||
ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration)
|
||||
}
|
||||
|
||||
fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_INSTANT_ELAPSED,
|
||||
expr.span,
|
||||
"manual implementation of `Instant::elapsed`",
|
||||
"try",
|
||||
format!("{}.elapsed()", sugg.maybe_par()),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
fn print_unchecked_duration_subtraction_sugg(
|
||||
cx: &LateContext<'_>,
|
||||
left_expr: &Expr<'_>,
|
||||
right_expr: &Expr<'_>,
|
||||
expr: &Expr<'_>,
|
||||
) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let left_expr =
|
||||
source::snippet_with_applicability(cx, left_expr.span, "std::time::Instant::now()", &mut applicability);
|
||||
let right_expr = source::snippet_with_applicability(
|
||||
cx,
|
||||
right_expr.span,
|
||||
"std::time::Duration::from_secs(1)",
|
||||
&mut applicability,
|
||||
);
|
||||
|
||||
diagnostics::span_lint_and_sugg(
|
||||
cx,
|
||||
UNCHECKED_DURATION_SUBTRACTION,
|
||||
expr.span,
|
||||
"unchecked subtraction of a 'Duration' from an 'Instant'",
|
||||
"try",
|
||||
format!("{left_expr}.checked_sub({right_expr}).unwrap()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
|
@ -63,58 +63,54 @@ impl IntPlusOne {
|
|||
fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
|
||||
match (binop, &lhs.kind, &rhs.kind) {
|
||||
// case where `x - 1 >= ...` or `-1 + x >= ...`
|
||||
(BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
|
||||
(BinOpKind::Ge, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) => {
|
||||
match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
|
||||
// `-1 + x`
|
||||
(BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
|
||||
(BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => {
|
||||
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
|
||||
},
|
||||
// `x - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
|
||||
(BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
// case where `... >= y + 1` or `... >= 1 + y`
|
||||
(BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs))
|
||||
if rhskind.node == BinOpKind::Add =>
|
||||
{
|
||||
(BinOpKind::Ge, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) if rhskind.node == BinOpKind::Add => {
|
||||
match (&rhslhs.kind, &rhsrhs.kind) {
|
||||
// `y + 1` and `1 + y`
|
||||
(&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
|
||||
(ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
|
||||
},
|
||||
(_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
|
||||
(_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
// case where `x + 1 <= ...` or `1 + x <= ...`
|
||||
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
|
||||
if lhskind.node == BinOpKind::Add =>
|
||||
{
|
||||
(BinOpKind::Le, ExprKind::Binary(lhskind, lhslhs, lhsrhs), _) if lhskind.node == BinOpKind::Add => {
|
||||
match (&lhslhs.kind, &lhsrhs.kind) {
|
||||
// `1 + x` and `x + 1`
|
||||
(&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
|
||||
(ExprKind::Lit(lit), _) if Self::check_lit(*lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
|
||||
},
|
||||
(_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
|
||||
(_, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
// case where `... >= y - 1` or `... >= -1 + y`
|
||||
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
|
||||
(BinOpKind::Le, _, ExprKind::Binary(rhskind, rhslhs, rhsrhs)) => {
|
||||
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
|
||||
// `-1 + y`
|
||||
(BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
|
||||
(BinOpKind::Add, ExprKind::Lit(lit), _) if Self::check_lit(*lit, -1) => {
|
||||
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
|
||||
},
|
||||
// `y - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
|
||||
(BinOpKind::Sub, _, ExprKind::Lit(lit)) if Self::check_lit(*lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
|
||||
},
|
||||
_ => None,
|
||||
|
|
|
@ -38,7 +38,7 @@ declare_clippy_lint! {
|
|||
|
||||
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
|
||||
|
||||
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
|
||||
fn numeric_cast_precast_bounds(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(FullInt, FullInt)> {
|
||||
if let ExprKind::Cast(cast_exp, _) = expr.kind {
|
||||
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
|
||||
let cast_ty = cx.typeck_results().expr_ty(expr);
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
//! lint when there is a large size difference between variants on an enum
|
||||
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_then,
|
||||
ty::{approx_ty_size, is_copy, AdtVariantInfo},
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
|
||||
use rustc_middle::ty::{Adt, Ty};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
|
@ -72,49 +75,6 @@ impl LargeEnumVariant {
|
|||
}
|
||||
}
|
||||
|
||||
struct FieldInfo {
|
||||
ind: usize,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
struct VariantInfo {
|
||||
ind: usize,
|
||||
size: u64,
|
||||
fields_size: Vec<FieldInfo>,
|
||||
}
|
||||
|
||||
fn variants_size<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
adt: AdtDef<'tcx>,
|
||||
subst: &'tcx List<GenericArg<'tcx>>,
|
||||
) -> Vec<VariantInfo> {
|
||||
let mut variants_size = adt
|
||||
.variants()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, variant)| {
|
||||
let mut fields_size = variant
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, f)| FieldInfo {
|
||||
ind: i,
|
||||
size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
|
||||
|
||||
VariantInfo {
|
||||
ind: i,
|
||||
size: fields_size.iter().map(|info| info.size).sum(),
|
||||
fields_size,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
|
||||
variants_size
|
||||
}
|
||||
|
||||
impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
|
||||
|
@ -130,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
|
|||
if adt.variants().len() <= 1 {
|
||||
return;
|
||||
}
|
||||
let variants_size = variants_size(cx, *adt, subst);
|
||||
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
|
||||
|
||||
let mut difference = variants_size[0].size - variants_size[1].size;
|
||||
if difference > self.maximum_size_difference_allowed {
|
||||
|
@ -173,16 +133,16 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
|
|||
.fields_size
|
||||
.iter()
|
||||
.rev()
|
||||
.map_while(|val| {
|
||||
.map_while(|&(ind, size)| {
|
||||
if difference > self.maximum_size_difference_allowed {
|
||||
difference = difference.saturating_sub(val.size);
|
||||
difference = difference.saturating_sub(size);
|
||||
Some((
|
||||
fields[val.ind].ty.span,
|
||||
fields[ind].ty.span,
|
||||
format!(
|
||||
"Box<{}>",
|
||||
snippet_with_applicability(
|
||||
cx,
|
||||
fields[val.ind].ty.span,
|
||||
fields[ind].ty.span,
|
||||
"..",
|
||||
&mut applicability
|
||||
)
|
||||
|
|
|
@ -366,8 +366,7 @@ fn check_for_is_empty<'tcx>(
|
|||
}
|
||||
|
||||
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
|
||||
if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
|
||||
{
|
||||
if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
|
||||
// check if we are in an is_empty() method
|
||||
if let Some(name) = get_item_name(cx, method) {
|
||||
if name.as_str() == "is_empty" {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, match_type};
|
||||
use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
|
||||
use clippy_utils::{is_must_use_func_call, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Local, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
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::{sym, Symbol};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -30,13 +28,14 @@ declare_clippy_lint! {
|
|||
#[clippy::version = "1.42.0"]
|
||||
pub LET_UNDERSCORE_MUST_USE,
|
||||
restriction,
|
||||
"non-binding let on a `#[must_use]` expression"
|
||||
"non-binding `let` on a `#[must_use]` expression"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for `let _ = sync_lock`.
|
||||
/// This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`.
|
||||
/// Checks for `let _ = sync_lock`. This supports `mutex` and `rwlock` in
|
||||
/// `parking_lot`. For `std` locks see the `rustc` lint
|
||||
/// [`let_underscore_lock`](https://doc.rust-lang.org/nightly/rustc/lints/listing/deny-by-default.html#let-underscore-lock)
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This statement immediately drops the lock instead of
|
||||
|
@ -57,50 +56,41 @@ declare_clippy_lint! {
|
|||
#[clippy::version = "1.43.0"]
|
||||
pub LET_UNDERSCORE_LOCK,
|
||||
correctness,
|
||||
"non-binding let on a synchronization lock"
|
||||
"non-binding `let` on a synchronization lock"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for `let _ = <expr>`
|
||||
/// where expr has a type that implements `Drop`
|
||||
/// Checks for `let _ = <expr>` where the resulting type of expr implements `Future`
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This statement immediately drops the initializer
|
||||
/// expression instead of extending its lifetime to the end of the scope, which
|
||||
/// is often not intended. To extend the expression's lifetime to the end of the
|
||||
/// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
|
||||
/// explicitly drop the expression, `std::mem::drop` conveys your intention
|
||||
/// better and is less error-prone.
|
||||
/// Futures must be polled for work to be done. The original intention was most likely to await the future
|
||||
/// and ignore the resulting value.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # struct DroppableItem;
|
||||
/// {
|
||||
/// let _ = DroppableItem;
|
||||
/// // ^ dropped here
|
||||
/// /* more code */
|
||||
/// async fn foo() -> Result<(), ()> {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// let _ = foo();
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # struct DroppableItem;
|
||||
/// {
|
||||
/// let _droppable = DroppableItem;
|
||||
/// /* more code */
|
||||
/// // dropped at end of scope
|
||||
/// # async fn context() {
|
||||
/// async fn foo() -> Result<(), ()> {
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// let _ = foo().await;
|
||||
/// # }
|
||||
/// ```
|
||||
#[clippy::version = "1.50.0"]
|
||||
pub LET_UNDERSCORE_DROP,
|
||||
pedantic,
|
||||
"non-binding let on a type that implements `Drop`"
|
||||
#[clippy::version = "1.66"]
|
||||
pub LET_UNDERSCORE_FUTURE,
|
||||
suspicious,
|
||||
"non-binding `let` on a future"
|
||||
}
|
||||
|
||||
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
|
||||
|
||||
const SYNC_GUARD_SYMS: [Symbol; 3] = [sym::MutexGuard, sym::RwLockReadGuard, sym::RwLockWriteGuard];
|
||||
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
|
||||
|
||||
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
|
||||
&paths::PARKING_LOT_MUTEX_GUARD,
|
||||
|
@ -110,64 +100,53 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
||||
fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
|
||||
if in_external_macro(cx.tcx.sess, local.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let PatKind::Wild = local.pat.kind;
|
||||
if let Some(init) = local.init;
|
||||
then {
|
||||
let init_ty = cx.typeck_results().expr_ty(init);
|
||||
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
|
||||
GenericArgKind::Type(inner_ty) => {
|
||||
SYNC_GUARD_SYMS
|
||||
.iter()
|
||||
.any(|&sym| is_type_diagnostic_item(cx, inner_ty, sym))
|
||||
|| SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
|
||||
},
|
||||
|
||||
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
|
||||
});
|
||||
if contains_sync_guard {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_LOCK,
|
||||
local.span,
|
||||
"non-binding let on a synchronization lock",
|
||||
None,
|
||||
"consider using an underscore-prefixed named \
|
||||
if !in_external_macro(cx.tcx.sess, local.span)
|
||||
&& let PatKind::Wild = local.pat.kind
|
||||
&& let Some(init) = local.init
|
||||
{
|
||||
let init_ty = cx.typeck_results().expr_ty(init);
|
||||
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
|
||||
GenericArgKind::Type(inner_ty) => SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path)),
|
||||
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
|
||||
});
|
||||
if contains_sync_guard {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_LOCK,
|
||||
local.span,
|
||||
"non-binding `let` on a synchronization lock",
|
||||
None,
|
||||
"consider using an underscore-prefixed named \
|
||||
binding or dropping explicitly with `std::mem::drop`",
|
||||
);
|
||||
} else if init_ty.needs_drop(cx.tcx, cx.param_env) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_DROP,
|
||||
local.span,
|
||||
"non-binding `let` on a type that implements `Drop`",
|
||||
None,
|
||||
"consider using an underscore-prefixed named \
|
||||
binding or dropping explicitly with `std::mem::drop`",
|
||||
);
|
||||
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_MUST_USE,
|
||||
local.span,
|
||||
"non-binding let on an expression with `#[must_use]` type",
|
||||
None,
|
||||
"consider explicitly using expression value",
|
||||
);
|
||||
} else if is_must_use_func_call(cx, init) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_MUST_USE,
|
||||
local.span,
|
||||
"non-binding let on a result of a `#[must_use]` function",
|
||||
None,
|
||||
"consider explicitly using function result",
|
||||
);
|
||||
}
|
||||
);
|
||||
} else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
|
||||
&& implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_FUTURE,
|
||||
local.span,
|
||||
"non-binding `let` on a future",
|
||||
None,
|
||||
"consider awaiting the future or dropping explicitly with `std::mem::drop`"
|
||||
);
|
||||
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_MUST_USE,
|
||||
local.span,
|
||||
"non-binding `let` on an expression with `#[must_use]` type",
|
||||
None,
|
||||
"consider explicitly using expression value",
|
||||
);
|
||||
} else if is_must_use_func_call(cx, init) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_MUST_USE,
|
||||
local.span,
|
||||
"non-binding `let` on a result of a `#[must_use]` function",
|
||||
None,
|
||||
"consider explicitly using function result",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,368 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||
LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
|
||||
LintId::of(approx_const::APPROX_CONSTANT),
|
||||
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
|
||||
LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
|
||||
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
|
||||
LintId::of(attrs::DEPRECATED_CFG_ATTR),
|
||||
LintId::of(attrs::DEPRECATED_SEMVER),
|
||||
LintId::of(attrs::MISMATCHED_TARGET_OS),
|
||||
LintId::of(attrs::USELESS_ATTRIBUTE),
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||
LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
|
||||
LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
|
||||
LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
|
||||
LintId::of(booleans::NONMINIMAL_BOOL),
|
||||
LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
|
||||
LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
|
||||
LintId::of(box_default::BOX_DEFAULT),
|
||||
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
|
||||
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
|
||||
LintId::of(casts::CAST_ENUM_TRUNCATION),
|
||||
LintId::of(casts::CAST_NAN_TO_INT),
|
||||
LintId::of(casts::CAST_REF_TO_MUT),
|
||||
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
|
||||
LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
|
||||
LintId::of(casts::CHAR_LIT_AS_U8),
|
||||
LintId::of(casts::FN_TO_NUMERIC_CAST),
|
||||
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
||||
LintId::of(casts::UNNECESSARY_CAST),
|
||||
LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
|
||||
LintId::of(collapsible_if::COLLAPSIBLE_IF),
|
||||
LintId::of(comparison_chain::COMPARISON_CHAIN),
|
||||
LintId::of(copies::IFS_SAME_COND),
|
||||
LintId::of(copies::IF_SAME_THEN_ELSE),
|
||||
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
|
||||
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
|
||||
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
|
||||
LintId::of(dereference::EXPLICIT_AUTO_DEREF),
|
||||
LintId::of(dereference::NEEDLESS_BORROW),
|
||||
LintId::of(derivable_impls::DERIVABLE_IMPLS),
|
||||
LintId::of(derive::DERIVE_HASH_XOR_EQ),
|
||||
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
|
||||
LintId::of(disallowed_macros::DISALLOWED_MACROS),
|
||||
LintId::of(disallowed_methods::DISALLOWED_METHODS),
|
||||
LintId::of(disallowed_names::DISALLOWED_NAMES),
|
||||
LintId::of(disallowed_types::DISALLOWED_TYPES),
|
||||
LintId::of(doc::MISSING_SAFETY_DOC),
|
||||
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
|
||||
LintId::of(double_parens::DOUBLE_PARENS),
|
||||
LintId::of(drop_forget_ref::DROP_COPY),
|
||||
LintId::of(drop_forget_ref::DROP_NON_DROP),
|
||||
LintId::of(drop_forget_ref::DROP_REF),
|
||||
LintId::of(drop_forget_ref::FORGET_COPY),
|
||||
LintId::of(drop_forget_ref::FORGET_NON_DROP),
|
||||
LintId::of(drop_forget_ref::FORGET_REF),
|
||||
LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
|
||||
LintId::of(duplicate_mod::DUPLICATE_MOD),
|
||||
LintId::of(entry::MAP_ENTRY),
|
||||
LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
|
||||
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
|
||||
LintId::of(enum_variants::MODULE_INCEPTION),
|
||||
LintId::of(escape::BOXED_LOCAL),
|
||||
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
|
||||
LintId::of(explicit_write::EXPLICIT_WRITE),
|
||||
LintId::of(float_literal::EXCESSIVE_PRECISION),
|
||||
LintId::of(format::USELESS_FORMAT),
|
||||
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
|
||||
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
|
||||
LintId::of(format_args::UNUSED_FORMAT_SPECS),
|
||||
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
|
||||
LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
|
||||
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
|
||||
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
|
||||
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
||||
LintId::of(from_over_into::FROM_OVER_INTO),
|
||||
LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
|
||||
LintId::of(functions::DOUBLE_MUST_USE),
|
||||
LintId::of(functions::MUST_USE_UNIT),
|
||||
LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
|
||||
LintId::of(functions::RESULT_LARGE_ERR),
|
||||
LintId::of(functions::RESULT_UNIT_ERR),
|
||||
LintId::of(functions::TOO_MANY_ARGUMENTS),
|
||||
LintId::of(if_let_mutex::IF_LET_MUTEX),
|
||||
LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
|
||||
LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
|
||||
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
|
||||
LintId::of(infinite_iter::INFINITE_ITER),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
|
||||
LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
|
||||
LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
|
||||
LintId::of(int_plus_one::INT_PLUS_ONE),
|
||||
LintId::of(invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED),
|
||||
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
|
||||
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
|
||||
LintId::of(len_zero::COMPARISON_TO_EMPTY),
|
||||
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
|
||||
LintId::of(len_zero::LEN_ZERO),
|
||||
LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
|
||||
LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
|
||||
LintId::of(lifetimes::NEEDLESS_LIFETIMES),
|
||||
LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
|
||||
LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
|
||||
LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
|
||||
LintId::of(loops::EMPTY_LOOP),
|
||||
LintId::of(loops::EXPLICIT_COUNTER_LOOP),
|
||||
LintId::of(loops::FOR_KV_MAP),
|
||||
LintId::of(loops::ITER_NEXT_LOOP),
|
||||
LintId::of(loops::MANUAL_FIND),
|
||||
LintId::of(loops::MANUAL_FLATTEN),
|
||||
LintId::of(loops::MANUAL_MEMCPY),
|
||||
LintId::of(loops::MISSING_SPIN_LOOP),
|
||||
LintId::of(loops::MUT_RANGE_BOUND),
|
||||
LintId::of(loops::NEEDLESS_COLLECT),
|
||||
LintId::of(loops::NEEDLESS_RANGE_LOOP),
|
||||
LintId::of(loops::NEVER_LOOP),
|
||||
LintId::of(loops::SAME_ITEM_PUSH),
|
||||
LintId::of(loops::SINGLE_ELEMENT_LOOP),
|
||||
LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
|
||||
LintId::of(loops::WHILE_LET_LOOP),
|
||||
LintId::of(loops::WHILE_LET_ON_ITERATOR),
|
||||
LintId::of(main_recursion::MAIN_RECURSION),
|
||||
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
|
||||
LintId::of(manual_bits::MANUAL_BITS),
|
||||
LintId::of(manual_clamp::MANUAL_CLAMP),
|
||||
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||
LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
|
||||
LintId::of(manual_retain::MANUAL_RETAIN),
|
||||
LintId::of(manual_strip::MANUAL_STRIP),
|
||||
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
|
||||
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
|
||||
LintId::of(match_result_ok::MATCH_RESULT_OK),
|
||||
LintId::of(matches::COLLAPSIBLE_MATCH),
|
||||
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||
LintId::of(matches::MANUAL_FILTER),
|
||||
LintId::of(matches::MANUAL_MAP),
|
||||
LintId::of(matches::MANUAL_UNWRAP_OR),
|
||||
LintId::of(matches::MATCH_AS_REF),
|
||||
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
|
||||
LintId::of(matches::MATCH_OVERLAPPING_ARM),
|
||||
LintId::of(matches::MATCH_REF_PATS),
|
||||
LintId::of(matches::MATCH_SINGLE_BINDING),
|
||||
LintId::of(matches::MATCH_STR_CASE_MISMATCH),
|
||||
LintId::of(matches::NEEDLESS_MATCH),
|
||||
LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
|
||||
LintId::of(matches::SINGLE_MATCH),
|
||||
LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
|
||||
LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
|
||||
LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
|
||||
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
|
||||
LintId::of(methods::BIND_INSTEAD_OF_MAP),
|
||||
LintId::of(methods::BYTES_COUNT_TO_LEN),
|
||||
LintId::of(methods::BYTES_NTH),
|
||||
LintId::of(methods::CHARS_LAST_CMP),
|
||||
LintId::of(methods::CHARS_NEXT_CMP),
|
||||
LintId::of(methods::CLONE_DOUBLE_REF),
|
||||
LintId::of(methods::CLONE_ON_COPY),
|
||||
LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
|
||||
LintId::of(methods::ERR_EXPECT),
|
||||
LintId::of(methods::EXPECT_FUN_CALL),
|
||||
LintId::of(methods::EXTEND_WITH_DRAIN),
|
||||
LintId::of(methods::FILTER_MAP_IDENTITY),
|
||||
LintId::of(methods::FILTER_NEXT),
|
||||
LintId::of(methods::FLAT_MAP_IDENTITY),
|
||||
LintId::of(methods::GET_FIRST),
|
||||
LintId::of(methods::GET_LAST_WITH_LEN),
|
||||
LintId::of(methods::INSPECT_FOR_EACH),
|
||||
LintId::of(methods::INTO_ITER_ON_REF),
|
||||
LintId::of(methods::IS_DIGIT_ASCII_RADIX),
|
||||
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
|
||||
LintId::of(methods::ITER_CLONED_COLLECT),
|
||||
LintId::of(methods::ITER_COUNT),
|
||||
LintId::of(methods::ITER_KV_MAP),
|
||||
LintId::of(methods::ITER_NEXT_SLICE),
|
||||
LintId::of(methods::ITER_NTH),
|
||||
LintId::of(methods::ITER_NTH_ZERO),
|
||||
LintId::of(methods::ITER_OVEREAGER_CLONED),
|
||||
LintId::of(methods::ITER_SKIP_NEXT),
|
||||
LintId::of(methods::MANUAL_FILTER_MAP),
|
||||
LintId::of(methods::MANUAL_FIND_MAP),
|
||||
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
|
||||
LintId::of(methods::MANUAL_SPLIT_ONCE),
|
||||
LintId::of(methods::MANUAL_STR_REPEAT),
|
||||
LintId::of(methods::MAP_CLONE),
|
||||
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
|
||||
LintId::of(methods::MAP_FLATTEN),
|
||||
LintId::of(methods::MAP_IDENTITY),
|
||||
LintId::of(methods::MUT_MUTEX_LOCK),
|
||||
LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
|
||||
LintId::of(methods::NEEDLESS_OPTION_TAKE),
|
||||
LintId::of(methods::NEEDLESS_SPLITN),
|
||||
LintId::of(methods::NEW_RET_NO_SELF),
|
||||
LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
|
||||
LintId::of(methods::NO_EFFECT_REPLACE),
|
||||
LintId::of(methods::OBFUSCATED_IF_ELSE),
|
||||
LintId::of(methods::OK_EXPECT),
|
||||
LintId::of(methods::OPTION_AS_REF_DEREF),
|
||||
LintId::of(methods::OPTION_FILTER_MAP),
|
||||
LintId::of(methods::OPTION_MAP_OR_NONE),
|
||||
LintId::of(methods::OR_FUN_CALL),
|
||||
LintId::of(methods::OR_THEN_UNWRAP),
|
||||
LintId::of(methods::RANGE_ZIP_WITH_LEN),
|
||||
LintId::of(methods::REPEAT_ONCE),
|
||||
LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
|
||||
LintId::of(methods::SEARCH_IS_SOME),
|
||||
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
|
||||
LintId::of(methods::SINGLE_CHAR_ADD_STR),
|
||||
LintId::of(methods::SINGLE_CHAR_PATTERN),
|
||||
LintId::of(methods::SKIP_WHILE_NEXT),
|
||||
LintId::of(methods::STRING_EXTEND_CHARS),
|
||||
LintId::of(methods::SUSPICIOUS_MAP),
|
||||
LintId::of(methods::SUSPICIOUS_SPLITN),
|
||||
LintId::of(methods::SUSPICIOUS_TO_OWNED),
|
||||
LintId::of(methods::UNINIT_ASSUMED_INIT),
|
||||
LintId::of(methods::UNIT_HASH),
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FIND_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNNECESSARY_SORT_BY),
|
||||
LintId::of(methods::UNNECESSARY_TO_OWNED),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::USELESS_ASREF),
|
||||
LintId::of(methods::VEC_RESIZE_TO_ZERO),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(methods::ZST_OFFSET),
|
||||
LintId::of(minmax::MIN_MAX),
|
||||
LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
|
||||
LintId::of(misc::TOPLEVEL_REF_ARG),
|
||||
LintId::of(misc::ZERO_PTR),
|
||||
LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
|
||||
LintId::of(misc_early::DOUBLE_NEG),
|
||||
LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
|
||||
LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
|
||||
LintId::of(misc_early::REDUNDANT_PATTERN),
|
||||
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
|
||||
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
|
||||
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
|
||||
LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
|
||||
LintId::of(mut_key::MUTABLE_KEY_TYPE),
|
||||
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
|
||||
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
|
||||
LintId::of(needless_bool::BOOL_COMPARISON),
|
||||
LintId::of(needless_bool::NEEDLESS_BOOL),
|
||||
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
|
||||
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
|
||||
LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
|
||||
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
|
||||
LintId::of(needless_update::NEEDLESS_UPDATE),
|
||||
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
|
||||
LintId::of(neg_multiply::NEG_MULTIPLY),
|
||||
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
|
||||
LintId::of(no_effect::NO_EFFECT),
|
||||
LintId::of(no_effect::UNNECESSARY_OPERATION),
|
||||
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
|
||||
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
|
||||
LintId::of(octal_escapes::OCTAL_ESCAPES),
|
||||
LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
|
||||
LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
|
||||
LintId::of(operators::ASSIGN_OP_PATTERN),
|
||||
LintId::of(operators::BAD_BIT_MASK),
|
||||
LintId::of(operators::CMP_NAN),
|
||||
LintId::of(operators::CMP_OWNED),
|
||||
LintId::of(operators::DOUBLE_COMPARISONS),
|
||||
LintId::of(operators::DURATION_SUBSEC),
|
||||
LintId::of(operators::EQ_OP),
|
||||
LintId::of(operators::ERASING_OP),
|
||||
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
|
||||
LintId::of(operators::IDENTITY_OP),
|
||||
LintId::of(operators::INEFFECTIVE_BIT_MASK),
|
||||
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
|
||||
LintId::of(operators::MODULO_ONE),
|
||||
LintId::of(operators::OP_REF),
|
||||
LintId::of(operators::PTR_EQ),
|
||||
LintId::of(operators::SELF_ASSIGNMENT),
|
||||
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
|
||||
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
|
||||
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
|
||||
LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
|
||||
LintId::of(precedence::PRECEDENCE),
|
||||
LintId::of(ptr::CMP_NULL),
|
||||
LintId::of(ptr::INVALID_NULL_PTR_USAGE),
|
||||
LintId::of(ptr::MUT_FROM_REF),
|
||||
LintId::of(ptr::PTR_ARG),
|
||||
LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
|
||||
LintId::of(question_mark::QUESTION_MARK),
|
||||
LintId::of(ranges::MANUAL_RANGE_CONTAINS),
|
||||
LintId::of(ranges::REVERSED_EMPTY_RANGES),
|
||||
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
|
||||
LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
|
||||
LintId::of(redundant_clone::REDUNDANT_CLONE),
|
||||
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
|
||||
LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
|
||||
LintId::of(redundant_slicing::REDUNDANT_SLICING),
|
||||
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
||||
LintId::of(reference::DEREF_ADDROF),
|
||||
LintId::of(regex::INVALID_REGEX),
|
||||
LintId::of(returns::LET_AND_RETURN),
|
||||
LintId::of(returns::NEEDLESS_RETURN),
|
||||
LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
|
||||
LintId::of(serde_api::SERDE_API_MISUSE),
|
||||
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
|
||||
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
|
||||
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
|
||||
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
|
||||
LintId::of(strings::TRIM_SPLIT_WHITESPACE),
|
||||
LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
|
||||
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
|
||||
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
|
||||
LintId::of(swap::ALMOST_SWAPPED),
|
||||
LintId::of(swap::MANUAL_SWAP),
|
||||
LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
|
||||
LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
|
||||
LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
|
||||
LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
|
||||
LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
|
||||
LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
|
||||
LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
|
||||
LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
|
||||
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
|
||||
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
|
||||
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
|
||||
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
|
||||
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
|
||||
LintId::of(transmute::TRANSMUTING_NULL),
|
||||
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
|
||||
LintId::of(transmute::USELESS_TRANSMUTE),
|
||||
LintId::of(transmute::WRONG_TRANSMUTE),
|
||||
LintId::of(types::BORROWED_BOX),
|
||||
LintId::of(types::BOX_COLLECTION),
|
||||
LintId::of(types::REDUNDANT_ALLOCATION),
|
||||
LintId::of(types::TYPE_COMPLEXITY),
|
||||
LintId::of(types::VEC_BOX),
|
||||
LintId::of(unicode::INVISIBLE_CHARACTERS),
|
||||
LintId::of(uninit_vec::UNINIT_VEC),
|
||||
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
|
||||
LintId::of(unit_types::LET_UNIT_VALUE),
|
||||
LintId::of(unit_types::UNIT_ARG),
|
||||
LintId::of(unit_types::UNIT_CMP),
|
||||
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||
LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
|
||||
LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
|
||||
LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
||||
LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
|
||||
LintId::of(unused_unit::UNUSED_UNIT),
|
||||
LintId::of(unwrap::PANICKING_UNWRAP),
|
||||
LintId::of(unwrap::UNNECESSARY_UNWRAP),
|
||||
LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
|
||||
LintId::of(useless_conversion::USELESS_CONVERSION),
|
||||
LintId::of(vec::USELESS_VEC),
|
||||
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
|
||||
LintId::of(write::PRINTLN_EMPTY_STRING),
|
||||
LintId::of(write::PRINT_LITERAL),
|
||||
LintId::of(write::PRINT_WITH_NEWLINE),
|
||||
LintId::of(write::WRITELN_EMPTY_STRING),
|
||||
LintId::of(write::WRITE_LITERAL),
|
||||
LintId::of(write::WRITE_WITH_NEWLINE),
|
||||
LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
|
||||
])
|
|
@ -1,11 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
|
||||
LintId::of(cargo::CARGO_COMMON_METADATA),
|
||||
LintId::of(cargo::MULTIPLE_CRATE_VERSIONS),
|
||||
LintId::of(cargo::NEGATIVE_FEATURE_NAMES),
|
||||
LintId::of(cargo::REDUNDANT_FEATURE_NAMES),
|
||||
LintId::of(cargo::WILDCARD_DEPENDENCIES),
|
||||
])
|
|
@ -1,111 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
|
||||
LintId::of(attrs::DEPRECATED_CFG_ATTR),
|
||||
LintId::of(booleans::NONMINIMAL_BOOL),
|
||||
LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
|
||||
LintId::of(casts::CHAR_LIT_AS_U8),
|
||||
LintId::of(casts::UNNECESSARY_CAST),
|
||||
LintId::of(dereference::EXPLICIT_AUTO_DEREF),
|
||||
LintId::of(derivable_impls::DERIVABLE_IMPLS),
|
||||
LintId::of(double_parens::DOUBLE_PARENS),
|
||||
LintId::of(explicit_write::EXPLICIT_WRITE),
|
||||
LintId::of(format::USELESS_FORMAT),
|
||||
LintId::of(format_args::UNUSED_FORMAT_SPECS),
|
||||
LintId::of(functions::TOO_MANY_ARGUMENTS),
|
||||
LintId::of(int_plus_one::INT_PLUS_ONE),
|
||||
LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
|
||||
LintId::of(lifetimes::NEEDLESS_LIFETIMES),
|
||||
LintId::of(loops::EXPLICIT_COUNTER_LOOP),
|
||||
LintId::of(loops::MANUAL_FIND),
|
||||
LintId::of(loops::MANUAL_FLATTEN),
|
||||
LintId::of(loops::SINGLE_ELEMENT_LOOP),
|
||||
LintId::of(loops::WHILE_LET_LOOP),
|
||||
LintId::of(manual_clamp::MANUAL_CLAMP),
|
||||
LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
|
||||
LintId::of(manual_strip::MANUAL_STRIP),
|
||||
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
|
||||
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
|
||||
LintId::of(matches::MANUAL_FILTER),
|
||||
LintId::of(matches::MANUAL_UNWRAP_OR),
|
||||
LintId::of(matches::MATCH_AS_REF),
|
||||
LintId::of(matches::MATCH_SINGLE_BINDING),
|
||||
LintId::of(matches::NEEDLESS_MATCH),
|
||||
LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
|
||||
LintId::of(methods::BIND_INSTEAD_OF_MAP),
|
||||
LintId::of(methods::BYTES_COUNT_TO_LEN),
|
||||
LintId::of(methods::CLONE_ON_COPY),
|
||||
LintId::of(methods::FILTER_MAP_IDENTITY),
|
||||
LintId::of(methods::FILTER_NEXT),
|
||||
LintId::of(methods::FLAT_MAP_IDENTITY),
|
||||
LintId::of(methods::GET_LAST_WITH_LEN),
|
||||
LintId::of(methods::INSPECT_FOR_EACH),
|
||||
LintId::of(methods::ITER_COUNT),
|
||||
LintId::of(methods::ITER_KV_MAP),
|
||||
LintId::of(methods::MANUAL_FILTER_MAP),
|
||||
LintId::of(methods::MANUAL_FIND_MAP),
|
||||
LintId::of(methods::MANUAL_SPLIT_ONCE),
|
||||
LintId::of(methods::MAP_FLATTEN),
|
||||
LintId::of(methods::MAP_IDENTITY),
|
||||
LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
|
||||
LintId::of(methods::NEEDLESS_OPTION_TAKE),
|
||||
LintId::of(methods::NEEDLESS_SPLITN),
|
||||
LintId::of(methods::OPTION_AS_REF_DEREF),
|
||||
LintId::of(methods::OPTION_FILTER_MAP),
|
||||
LintId::of(methods::OR_THEN_UNWRAP),
|
||||
LintId::of(methods::RANGE_ZIP_WITH_LEN),
|
||||
LintId::of(methods::REPEAT_ONCE),
|
||||
LintId::of(methods::SEARCH_IS_SOME),
|
||||
LintId::of(methods::SKIP_WHILE_NEXT),
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FIND_MAP),
|
||||
LintId::of(methods::UNNECESSARY_SORT_BY),
|
||||
LintId::of(methods::USELESS_ASREF),
|
||||
LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
|
||||
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
|
||||
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
|
||||
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
|
||||
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
|
||||
LintId::of(needless_bool::BOOL_COMPARISON),
|
||||
LintId::of(needless_bool::NEEDLESS_BOOL),
|
||||
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
|
||||
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
|
||||
LintId::of(needless_update::NEEDLESS_UPDATE),
|
||||
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
|
||||
LintId::of(no_effect::NO_EFFECT),
|
||||
LintId::of(no_effect::UNNECESSARY_OPERATION),
|
||||
LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
|
||||
LintId::of(operators::DOUBLE_COMPARISONS),
|
||||
LintId::of(operators::DURATION_SUBSEC),
|
||||
LintId::of(operators::IDENTITY_OP),
|
||||
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
|
||||
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
|
||||
LintId::of(precedence::PRECEDENCE),
|
||||
LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
|
||||
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
|
||||
LintId::of(redundant_slicing::REDUNDANT_SLICING),
|
||||
LintId::of(reference::DEREF_ADDROF),
|
||||
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
|
||||
LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
|
||||
LintId::of(swap::MANUAL_SWAP),
|
||||
LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
|
||||
LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
|
||||
LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
|
||||
LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
|
||||
LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
|
||||
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
|
||||
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
|
||||
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
|
||||
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
|
||||
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
|
||||
LintId::of(transmute::USELESS_TRANSMUTE),
|
||||
LintId::of(types::BORROWED_BOX),
|
||||
LintId::of(types::TYPE_COMPLEXITY),
|
||||
LintId::of(types::VEC_BOX),
|
||||
LintId::of(unit_types::UNIT_ARG),
|
||||
LintId::of(unwrap::UNNECESSARY_UNWRAP),
|
||||
LintId::of(useless_conversion::USELESS_CONVERSION),
|
||||
LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
|
||||
])
|
|
@ -1,78 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
|
||||
LintId::of(approx_const::APPROX_CONSTANT),
|
||||
LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
|
||||
LintId::of(attrs::DEPRECATED_SEMVER),
|
||||
LintId::of(attrs::MISMATCHED_TARGET_OS),
|
||||
LintId::of(attrs::USELESS_ATTRIBUTE),
|
||||
LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
|
||||
LintId::of(casts::CAST_REF_TO_MUT),
|
||||
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
|
||||
LintId::of(copies::IFS_SAME_COND),
|
||||
LintId::of(copies::IF_SAME_THEN_ELSE),
|
||||
LintId::of(derive::DERIVE_HASH_XOR_EQ),
|
||||
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
|
||||
LintId::of(drop_forget_ref::DROP_COPY),
|
||||
LintId::of(drop_forget_ref::DROP_REF),
|
||||
LintId::of(drop_forget_ref::FORGET_COPY),
|
||||
LintId::of(drop_forget_ref::FORGET_REF),
|
||||
LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
|
||||
LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
|
||||
LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
|
||||
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
|
||||
LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
|
||||
LintId::of(if_let_mutex::IF_LET_MUTEX),
|
||||
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
|
||||
LintId::of(infinite_iter::INFINITE_ITER),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
|
||||
LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
|
||||
LintId::of(invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED),
|
||||
LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
|
||||
LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
|
||||
LintId::of(loops::ITER_NEXT_LOOP),
|
||||
LintId::of(loops::NEVER_LOOP),
|
||||
LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
|
||||
LintId::of(matches::MATCH_STR_CASE_MISMATCH),
|
||||
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
|
||||
LintId::of(methods::CLONE_DOUBLE_REF),
|
||||
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
|
||||
LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
|
||||
LintId::of(methods::SUSPICIOUS_SPLITN),
|
||||
LintId::of(methods::UNINIT_ASSUMED_INIT),
|
||||
LintId::of(methods::UNIT_HASH),
|
||||
LintId::of(methods::VEC_RESIZE_TO_ZERO),
|
||||
LintId::of(methods::ZST_OFFSET),
|
||||
LintId::of(minmax::MIN_MAX),
|
||||
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
|
||||
LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
|
||||
LintId::of(operators::BAD_BIT_MASK),
|
||||
LintId::of(operators::CMP_NAN),
|
||||
LintId::of(operators::EQ_OP),
|
||||
LintId::of(operators::ERASING_OP),
|
||||
LintId::of(operators::INEFFECTIVE_BIT_MASK),
|
||||
LintId::of(operators::MODULO_ONE),
|
||||
LintId::of(operators::SELF_ASSIGNMENT),
|
||||
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
|
||||
LintId::of(ptr::INVALID_NULL_PTR_USAGE),
|
||||
LintId::of(ptr::MUT_FROM_REF),
|
||||
LintId::of(ranges::REVERSED_EMPTY_RANGES),
|
||||
LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
|
||||
LintId::of(regex::INVALID_REGEX),
|
||||
LintId::of(serde_api::SERDE_API_MISUSE),
|
||||
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
|
||||
LintId::of(swap::ALMOST_SWAPPED),
|
||||
LintId::of(transmute::TRANSMUTING_NULL),
|
||||
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
|
||||
LintId::of(transmute::WRONG_TRANSMUTE),
|
||||
LintId::of(unicode::INVISIBLE_CHARACTERS),
|
||||
LintId::of(uninit_vec::UNINIT_VEC),
|
||||
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
|
||||
LintId::of(unit_types::UNIT_CMP),
|
||||
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||
LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
|
||||
LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
|
||||
LintId::of(unwrap::PANICKING_UNWRAP),
|
||||
])
|
|
@ -1,22 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
|
||||
LintId::of(utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL),
|
||||
LintId::of(utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS),
|
||||
LintId::of(utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS),
|
||||
LintId::of(utils::internal_lints::if_chain_style::IF_CHAIN_STYLE),
|
||||
LintId::of(utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL),
|
||||
LintId::of(utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR),
|
||||
LintId::of(utils::internal_lints::invalid_paths::INVALID_PATHS),
|
||||
LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON),
|
||||
LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT),
|
||||
LintId::of(utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE),
|
||||
LintId::of(utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS),
|
||||
LintId::of(utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE),
|
||||
LintId::of(utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL),
|
||||
LintId::of(utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA),
|
||||
LintId::of(utils::internal_lints::produce_ice::PRODUCE_ICE),
|
||||
LintId::of(utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH),
|
||||
])
|
|
@ -1,620 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_lints(&[
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::if_chain_style::IF_CHAIN_STYLE,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::invalid_paths::INVALID_PATHS,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::produce_ice::PRODUCE_ICE,
|
||||
#[cfg(feature = "internal")]
|
||||
utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH,
|
||||
almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
|
||||
approx_const::APPROX_CONSTANT,
|
||||
as_conversions::AS_CONVERSIONS,
|
||||
asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
|
||||
asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
|
||||
assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
|
||||
assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES,
|
||||
async_yields_async::ASYNC_YIELDS_ASYNC,
|
||||
attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON,
|
||||
attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
|
||||
attrs::DEPRECATED_CFG_ATTR,
|
||||
attrs::DEPRECATED_SEMVER,
|
||||
attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
attrs::INLINE_ALWAYS,
|
||||
attrs::MISMATCHED_TARGET_OS,
|
||||
attrs::USELESS_ATTRIBUTE,
|
||||
await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
|
||||
await_holding_invalid::AWAIT_HOLDING_LOCK,
|
||||
await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
|
||||
blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
|
||||
bool_assert_comparison::BOOL_ASSERT_COMPARISON,
|
||||
bool_to_int_with_if::BOOL_TO_INT_WITH_IF,
|
||||
booleans::NONMINIMAL_BOOL,
|
||||
booleans::OVERLY_COMPLEX_BOOL_EXPR,
|
||||
borrow_deref_ref::BORROW_DEREF_REF,
|
||||
box_default::BOX_DEFAULT,
|
||||
cargo::CARGO_COMMON_METADATA,
|
||||
cargo::MULTIPLE_CRATE_VERSIONS,
|
||||
cargo::NEGATIVE_FEATURE_NAMES,
|
||||
cargo::REDUNDANT_FEATURE_NAMES,
|
||||
cargo::WILDCARD_DEPENDENCIES,
|
||||
casts::AS_PTR_CAST_MUT,
|
||||
casts::AS_UNDERSCORE,
|
||||
casts::BORROW_AS_PTR,
|
||||
casts::CAST_ABS_TO_UNSIGNED,
|
||||
casts::CAST_ENUM_CONSTRUCTOR,
|
||||
casts::CAST_ENUM_TRUNCATION,
|
||||
casts::CAST_LOSSLESS,
|
||||
casts::CAST_NAN_TO_INT,
|
||||
casts::CAST_POSSIBLE_TRUNCATION,
|
||||
casts::CAST_POSSIBLE_WRAP,
|
||||
casts::CAST_PRECISION_LOSS,
|
||||
casts::CAST_PTR_ALIGNMENT,
|
||||
casts::CAST_REF_TO_MUT,
|
||||
casts::CAST_SIGN_LOSS,
|
||||
casts::CAST_SLICE_DIFFERENT_SIZES,
|
||||
casts::CAST_SLICE_FROM_RAW_PARTS,
|
||||
casts::CHAR_LIT_AS_U8,
|
||||
casts::FN_TO_NUMERIC_CAST,
|
||||
casts::FN_TO_NUMERIC_CAST_ANY,
|
||||
casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
|
||||
casts::PTR_AS_PTR,
|
||||
casts::UNNECESSARY_CAST,
|
||||
checked_conversions::CHECKED_CONVERSIONS,
|
||||
cognitive_complexity::COGNITIVE_COMPLEXITY,
|
||||
collapsible_if::COLLAPSIBLE_ELSE_IF,
|
||||
collapsible_if::COLLAPSIBLE_IF,
|
||||
comparison_chain::COMPARISON_CHAIN,
|
||||
copies::BRANCHES_SHARING_CODE,
|
||||
copies::IFS_SAME_COND,
|
||||
copies::IF_SAME_THEN_ELSE,
|
||||
copies::SAME_FUNCTIONS_IN_IF_CONDITION,
|
||||
copy_iterator::COPY_ITERATOR,
|
||||
crate_in_macro_def::CRATE_IN_MACRO_DEF,
|
||||
create_dir::CREATE_DIR,
|
||||
dbg_macro::DBG_MACRO,
|
||||
default::DEFAULT_TRAIT_ACCESS,
|
||||
default::FIELD_REASSIGN_WITH_DEFAULT,
|
||||
default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY,
|
||||
default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
|
||||
default_union_representation::DEFAULT_UNION_REPRESENTATION,
|
||||
dereference::EXPLICIT_AUTO_DEREF,
|
||||
dereference::EXPLICIT_DEREF_METHODS,
|
||||
dereference::NEEDLESS_BORROW,
|
||||
dereference::REF_BINDING_TO_REFERENCE,
|
||||
derivable_impls::DERIVABLE_IMPLS,
|
||||
derive::DERIVE_HASH_XOR_EQ,
|
||||
derive::DERIVE_ORD_XOR_PARTIAL_ORD,
|
||||
derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
|
||||
derive::EXPL_IMPL_CLONE_ON_COPY,
|
||||
derive::UNSAFE_DERIVE_DESERIALIZE,
|
||||
disallowed_macros::DISALLOWED_MACROS,
|
||||
disallowed_methods::DISALLOWED_METHODS,
|
||||
disallowed_names::DISALLOWED_NAMES,
|
||||
disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
|
||||
disallowed_types::DISALLOWED_TYPES,
|
||||
doc::DOC_LINK_WITH_QUOTES,
|
||||
doc::DOC_MARKDOWN,
|
||||
doc::MISSING_ERRORS_DOC,
|
||||
doc::MISSING_PANICS_DOC,
|
||||
doc::MISSING_SAFETY_DOC,
|
||||
doc::NEEDLESS_DOCTEST_MAIN,
|
||||
double_parens::DOUBLE_PARENS,
|
||||
drop_forget_ref::DROP_COPY,
|
||||
drop_forget_ref::DROP_NON_DROP,
|
||||
drop_forget_ref::DROP_REF,
|
||||
drop_forget_ref::FORGET_COPY,
|
||||
drop_forget_ref::FORGET_NON_DROP,
|
||||
drop_forget_ref::FORGET_REF,
|
||||
drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
|
||||
duplicate_mod::DUPLICATE_MOD,
|
||||
else_if_without_else::ELSE_IF_WITHOUT_ELSE,
|
||||
empty_drop::EMPTY_DROP,
|
||||
empty_enum::EMPTY_ENUM,
|
||||
empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS,
|
||||
entry::MAP_ENTRY,
|
||||
enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
|
||||
enum_variants::ENUM_VARIANT_NAMES,
|
||||
enum_variants::MODULE_INCEPTION,
|
||||
enum_variants::MODULE_NAME_REPETITIONS,
|
||||
equatable_if_let::EQUATABLE_IF_LET,
|
||||
escape::BOXED_LOCAL,
|
||||
eta_reduction::REDUNDANT_CLOSURE,
|
||||
eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
|
||||
excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
|
||||
excessive_bools::STRUCT_EXCESSIVE_BOOLS,
|
||||
exhaustive_items::EXHAUSTIVE_ENUMS,
|
||||
exhaustive_items::EXHAUSTIVE_STRUCTS,
|
||||
exit::EXIT,
|
||||
explicit_write::EXPLICIT_WRITE,
|
||||
fallible_impl_from::FALLIBLE_IMPL_FROM,
|
||||
float_literal::EXCESSIVE_PRECISION,
|
||||
float_literal::LOSSY_FLOAT_LITERAL,
|
||||
floating_point_arithmetic::IMPRECISE_FLOPS,
|
||||
floating_point_arithmetic::SUBOPTIMAL_FLOPS,
|
||||
format::USELESS_FORMAT,
|
||||
format_args::FORMAT_IN_FORMAT_ARGS,
|
||||
format_args::TO_STRING_IN_FORMAT_ARGS,
|
||||
format_args::UNINLINED_FORMAT_ARGS,
|
||||
format_args::UNUSED_FORMAT_SPECS,
|
||||
format_impl::PRINT_IN_FORMAT_IMPL,
|
||||
format_impl::RECURSIVE_FORMAT_IMPL,
|
||||
format_push_string::FORMAT_PUSH_STRING,
|
||||
formatting::POSSIBLE_MISSING_COMMA,
|
||||
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
|
||||
formatting::SUSPICIOUS_ELSE_FORMATTING,
|
||||
formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
||||
from_over_into::FROM_OVER_INTO,
|
||||
from_str_radix_10::FROM_STR_RADIX_10,
|
||||
functions::DOUBLE_MUST_USE,
|
||||
functions::MUST_USE_CANDIDATE,
|
||||
functions::MUST_USE_UNIT,
|
||||
functions::NOT_UNSAFE_PTR_ARG_DEREF,
|
||||
functions::RESULT_LARGE_ERR,
|
||||
functions::RESULT_UNIT_ERR,
|
||||
functions::TOO_MANY_ARGUMENTS,
|
||||
functions::TOO_MANY_LINES,
|
||||
future_not_send::FUTURE_NOT_SEND,
|
||||
if_let_mutex::IF_LET_MUTEX,
|
||||
if_not_else::IF_NOT_ELSE,
|
||||
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
|
||||
implicit_hasher::IMPLICIT_HASHER,
|
||||
implicit_return::IMPLICIT_RETURN,
|
||||
implicit_saturating_add::IMPLICIT_SATURATING_ADD,
|
||||
implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
|
||||
inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
|
||||
index_refutable_slice::INDEX_REFUTABLE_SLICE,
|
||||
indexing_slicing::INDEXING_SLICING,
|
||||
indexing_slicing::OUT_OF_BOUNDS_INDEXING,
|
||||
infinite_iter::INFINITE_ITER,
|
||||
infinite_iter::MAYBE_INFINITE_ITER,
|
||||
inherent_impl::MULTIPLE_INHERENT_IMPL,
|
||||
inherent_to_string::INHERENT_TO_STRING,
|
||||
inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
|
||||
init_numbered_fields::INIT_NUMBERED_FIELDS,
|
||||
inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
|
||||
int_plus_one::INT_PLUS_ONE,
|
||||
invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
|
||||
invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED,
|
||||
items_after_statements::ITEMS_AFTER_STATEMENTS,
|
||||
iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
|
||||
large_const_arrays::LARGE_CONST_ARRAYS,
|
||||
large_enum_variant::LARGE_ENUM_VARIANT,
|
||||
large_include_file::LARGE_INCLUDE_FILE,
|
||||
large_stack_arrays::LARGE_STACK_ARRAYS,
|
||||
len_zero::COMPARISON_TO_EMPTY,
|
||||
len_zero::LEN_WITHOUT_IS_EMPTY,
|
||||
len_zero::LEN_ZERO,
|
||||
let_if_seq::USELESS_LET_IF_SEQ,
|
||||
let_underscore::LET_UNDERSCORE_DROP,
|
||||
let_underscore::LET_UNDERSCORE_LOCK,
|
||||
let_underscore::LET_UNDERSCORE_MUST_USE,
|
||||
lifetimes::EXTRA_UNUSED_LIFETIMES,
|
||||
lifetimes::NEEDLESS_LIFETIMES,
|
||||
literal_representation::DECIMAL_LITERAL_REPRESENTATION,
|
||||
literal_representation::INCONSISTENT_DIGIT_GROUPING,
|
||||
literal_representation::LARGE_DIGIT_GROUPS,
|
||||
literal_representation::MISTYPED_LITERAL_SUFFIXES,
|
||||
literal_representation::UNREADABLE_LITERAL,
|
||||
literal_representation::UNUSUAL_BYTE_GROUPINGS,
|
||||
loops::EMPTY_LOOP,
|
||||
loops::EXPLICIT_COUNTER_LOOP,
|
||||
loops::EXPLICIT_INTO_ITER_LOOP,
|
||||
loops::EXPLICIT_ITER_LOOP,
|
||||
loops::FOR_KV_MAP,
|
||||
loops::ITER_NEXT_LOOP,
|
||||
loops::MANUAL_FIND,
|
||||
loops::MANUAL_FLATTEN,
|
||||
loops::MANUAL_MEMCPY,
|
||||
loops::MISSING_SPIN_LOOP,
|
||||
loops::MUT_RANGE_BOUND,
|
||||
loops::NEEDLESS_COLLECT,
|
||||
loops::NEEDLESS_RANGE_LOOP,
|
||||
loops::NEVER_LOOP,
|
||||
loops::SAME_ITEM_PUSH,
|
||||
loops::SINGLE_ELEMENT_LOOP,
|
||||
loops::WHILE_IMMUTABLE_CONDITION,
|
||||
loops::WHILE_LET_LOOP,
|
||||
loops::WHILE_LET_ON_ITERATOR,
|
||||
macro_use::MACRO_USE_IMPORTS,
|
||||
main_recursion::MAIN_RECURSION,
|
||||
manual_assert::MANUAL_ASSERT,
|
||||
manual_async_fn::MANUAL_ASYNC_FN,
|
||||
manual_bits::MANUAL_BITS,
|
||||
manual_clamp::MANUAL_CLAMP,
|
||||
manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
|
||||
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
|
||||
manual_rem_euclid::MANUAL_REM_EUCLID,
|
||||
manual_retain::MANUAL_RETAIN,
|
||||
manual_string_new::MANUAL_STRING_NEW,
|
||||
manual_strip::MANUAL_STRIP,
|
||||
map_unit_fn::OPTION_MAP_UNIT_FN,
|
||||
map_unit_fn::RESULT_MAP_UNIT_FN,
|
||||
match_result_ok::MATCH_RESULT_OK,
|
||||
matches::COLLAPSIBLE_MATCH,
|
||||
matches::INFALLIBLE_DESTRUCTURING_MATCH,
|
||||
matches::MANUAL_FILTER,
|
||||
matches::MANUAL_MAP,
|
||||
matches::MANUAL_UNWRAP_OR,
|
||||
matches::MATCH_AS_REF,
|
||||
matches::MATCH_BOOL,
|
||||
matches::MATCH_LIKE_MATCHES_MACRO,
|
||||
matches::MATCH_ON_VEC_ITEMS,
|
||||
matches::MATCH_OVERLAPPING_ARM,
|
||||
matches::MATCH_REF_PATS,
|
||||
matches::MATCH_SAME_ARMS,
|
||||
matches::MATCH_SINGLE_BINDING,
|
||||
matches::MATCH_STR_CASE_MISMATCH,
|
||||
matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
|
||||
matches::MATCH_WILD_ERR_ARM,
|
||||
matches::NEEDLESS_MATCH,
|
||||
matches::REDUNDANT_PATTERN_MATCHING,
|
||||
matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
|
||||
matches::SIGNIFICANT_DROP_IN_SCRUTINEE,
|
||||
matches::SINGLE_MATCH,
|
||||
matches::SINGLE_MATCH_ELSE,
|
||||
matches::TRY_ERR,
|
||||
matches::WILDCARD_ENUM_MATCH_ARM,
|
||||
matches::WILDCARD_IN_OR_PATTERNS,
|
||||
mem_forget::MEM_FORGET,
|
||||
mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
|
||||
mem_replace::MEM_REPLACE_WITH_DEFAULT,
|
||||
mem_replace::MEM_REPLACE_WITH_UNINIT,
|
||||
methods::BIND_INSTEAD_OF_MAP,
|
||||
methods::BYTES_COUNT_TO_LEN,
|
||||
methods::BYTES_NTH,
|
||||
methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
|
||||
methods::CHARS_LAST_CMP,
|
||||
methods::CHARS_NEXT_CMP,
|
||||
methods::CLONED_INSTEAD_OF_COPIED,
|
||||
methods::CLONE_DOUBLE_REF,
|
||||
methods::CLONE_ON_COPY,
|
||||
methods::CLONE_ON_REF_PTR,
|
||||
methods::COLLAPSIBLE_STR_REPLACE,
|
||||
methods::ERR_EXPECT,
|
||||
methods::EXPECT_FUN_CALL,
|
||||
methods::EXPECT_USED,
|
||||
methods::EXTEND_WITH_DRAIN,
|
||||
methods::FILETYPE_IS_FILE,
|
||||
methods::FILTER_MAP_IDENTITY,
|
||||
methods::FILTER_MAP_NEXT,
|
||||
methods::FILTER_NEXT,
|
||||
methods::FLAT_MAP_IDENTITY,
|
||||
methods::FLAT_MAP_OPTION,
|
||||
methods::FROM_ITER_INSTEAD_OF_COLLECT,
|
||||
methods::GET_FIRST,
|
||||
methods::GET_LAST_WITH_LEN,
|
||||
methods::GET_UNWRAP,
|
||||
methods::IMPLICIT_CLONE,
|
||||
methods::INEFFICIENT_TO_STRING,
|
||||
methods::INSPECT_FOR_EACH,
|
||||
methods::INTO_ITER_ON_REF,
|
||||
methods::IS_DIGIT_ASCII_RADIX,
|
||||
methods::ITERATOR_STEP_BY_ZERO,
|
||||
methods::ITER_CLONED_COLLECT,
|
||||
methods::ITER_COUNT,
|
||||
methods::ITER_KV_MAP,
|
||||
methods::ITER_NEXT_SLICE,
|
||||
methods::ITER_NTH,
|
||||
methods::ITER_NTH_ZERO,
|
||||
methods::ITER_ON_EMPTY_COLLECTIONS,
|
||||
methods::ITER_ON_SINGLE_ITEMS,
|
||||
methods::ITER_OVEREAGER_CLONED,
|
||||
methods::ITER_SKIP_NEXT,
|
||||
methods::ITER_WITH_DRAIN,
|
||||
methods::MANUAL_FILTER_MAP,
|
||||
methods::MANUAL_FIND_MAP,
|
||||
methods::MANUAL_OK_OR,
|
||||
methods::MANUAL_SATURATING_ARITHMETIC,
|
||||
methods::MANUAL_SPLIT_ONCE,
|
||||
methods::MANUAL_STR_REPEAT,
|
||||
methods::MAP_CLONE,
|
||||
methods::MAP_COLLECT_RESULT_UNIT,
|
||||
methods::MAP_ERR_IGNORE,
|
||||
methods::MAP_FLATTEN,
|
||||
methods::MAP_IDENTITY,
|
||||
methods::MAP_UNWRAP_OR,
|
||||
methods::MUT_MUTEX_LOCK,
|
||||
methods::NAIVE_BYTECOUNT,
|
||||
methods::NEEDLESS_OPTION_AS_DEREF,
|
||||
methods::NEEDLESS_OPTION_TAKE,
|
||||
methods::NEEDLESS_SPLITN,
|
||||
methods::NEW_RET_NO_SELF,
|
||||
methods::NONSENSICAL_OPEN_OPTIONS,
|
||||
methods::NO_EFFECT_REPLACE,
|
||||
methods::OBFUSCATED_IF_ELSE,
|
||||
methods::OK_EXPECT,
|
||||
methods::OPTION_AS_REF_DEREF,
|
||||
methods::OPTION_FILTER_MAP,
|
||||
methods::OPTION_MAP_OR_NONE,
|
||||
methods::OR_FUN_CALL,
|
||||
methods::OR_THEN_UNWRAP,
|
||||
methods::PATH_BUF_PUSH_OVERWRITE,
|
||||
methods::RANGE_ZIP_WITH_LEN,
|
||||
methods::REPEAT_ONCE,
|
||||
methods::RESULT_MAP_OR_INTO_OPTION,
|
||||
methods::SEARCH_IS_SOME,
|
||||
methods::SHOULD_IMPLEMENT_TRAIT,
|
||||
methods::SINGLE_CHAR_ADD_STR,
|
||||
methods::SINGLE_CHAR_PATTERN,
|
||||
methods::SKIP_WHILE_NEXT,
|
||||
methods::STABLE_SORT_PRIMITIVE,
|
||||
methods::STRING_EXTEND_CHARS,
|
||||
methods::SUSPICIOUS_MAP,
|
||||
methods::SUSPICIOUS_SPLITN,
|
||||
methods::SUSPICIOUS_TO_OWNED,
|
||||
methods::UNINIT_ASSUMED_INIT,
|
||||
methods::UNIT_HASH,
|
||||
methods::UNNECESSARY_FILTER_MAP,
|
||||
methods::UNNECESSARY_FIND_MAP,
|
||||
methods::UNNECESSARY_FOLD,
|
||||
methods::UNNECESSARY_JOIN,
|
||||
methods::UNNECESSARY_LAZY_EVALUATIONS,
|
||||
methods::UNNECESSARY_SORT_BY,
|
||||
methods::UNNECESSARY_TO_OWNED,
|
||||
methods::UNWRAP_OR_ELSE_DEFAULT,
|
||||
methods::UNWRAP_USED,
|
||||
methods::USELESS_ASREF,
|
||||
methods::VEC_RESIZE_TO_ZERO,
|
||||
methods::VERBOSE_FILE_READS,
|
||||
methods::WRONG_SELF_CONVENTION,
|
||||
methods::ZST_OFFSET,
|
||||
minmax::MIN_MAX,
|
||||
misc::SHORT_CIRCUIT_STATEMENT,
|
||||
misc::TOPLEVEL_REF_ARG,
|
||||
misc::USED_UNDERSCORE_BINDING,
|
||||
misc::ZERO_PTR,
|
||||
misc_early::BUILTIN_TYPE_SHADOW,
|
||||
misc_early::DOUBLE_NEG,
|
||||
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
|
||||
misc_early::MIXED_CASE_HEX_LITERALS,
|
||||
misc_early::REDUNDANT_PATTERN,
|
||||
misc_early::SEPARATED_LITERAL_SUFFIX,
|
||||
misc_early::UNNEEDED_FIELD_PATTERN,
|
||||
misc_early::UNNEEDED_WILDCARD_PATTERN,
|
||||
misc_early::UNSEPARATED_LITERAL_SUFFIX,
|
||||
misc_early::ZERO_PREFIXED_LITERAL,
|
||||
mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER,
|
||||
missing_const_for_fn::MISSING_CONST_FOR_FN,
|
||||
missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
|
||||
missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
|
||||
missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
|
||||
missing_trait_methods::MISSING_TRAIT_METHODS,
|
||||
mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION,
|
||||
mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
|
||||
module_style::MOD_MODULE_FILES,
|
||||
module_style::SELF_NAMED_MODULE_FILES,
|
||||
multi_assignments::MULTI_ASSIGNMENTS,
|
||||
mut_key::MUTABLE_KEY_TYPE,
|
||||
mut_mut::MUT_MUT,
|
||||
mut_reference::UNNECESSARY_MUT_PASSED,
|
||||
mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
|
||||
mutex_atomic::MUTEX_ATOMIC,
|
||||
mutex_atomic::MUTEX_INTEGER,
|
||||
needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
|
||||
needless_bool::BOOL_COMPARISON,
|
||||
needless_bool::NEEDLESS_BOOL,
|
||||
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
|
||||
needless_continue::NEEDLESS_CONTINUE,
|
||||
needless_for_each::NEEDLESS_FOR_EACH,
|
||||
needless_late_init::NEEDLESS_LATE_INIT,
|
||||
needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS,
|
||||
needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
|
||||
needless_question_mark::NEEDLESS_QUESTION_MARK,
|
||||
needless_update::NEEDLESS_UPDATE,
|
||||
neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
|
||||
neg_multiply::NEG_MULTIPLY,
|
||||
new_without_default::NEW_WITHOUT_DEFAULT,
|
||||
no_effect::NO_EFFECT,
|
||||
no_effect::NO_EFFECT_UNDERSCORE_BINDING,
|
||||
no_effect::UNNECESSARY_OPERATION,
|
||||
non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
|
||||
non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
|
||||
non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
|
||||
non_expressive_names::MANY_SINGLE_CHAR_NAMES,
|
||||
non_expressive_names::SIMILAR_NAMES,
|
||||
non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
|
||||
non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
|
||||
nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
|
||||
octal_escapes::OCTAL_ESCAPES,
|
||||
only_used_in_recursion::ONLY_USED_IN_RECURSION,
|
||||
operators::ABSURD_EXTREME_COMPARISONS,
|
||||
operators::ARITHMETIC_SIDE_EFFECTS,
|
||||
operators::ASSIGN_OP_PATTERN,
|
||||
operators::BAD_BIT_MASK,
|
||||
operators::CMP_NAN,
|
||||
operators::CMP_OWNED,
|
||||
operators::DOUBLE_COMPARISONS,
|
||||
operators::DURATION_SUBSEC,
|
||||
operators::EQ_OP,
|
||||
operators::ERASING_OP,
|
||||
operators::FLOAT_ARITHMETIC,
|
||||
operators::FLOAT_CMP,
|
||||
operators::FLOAT_CMP_CONST,
|
||||
operators::FLOAT_EQUALITY_WITHOUT_ABS,
|
||||
operators::IDENTITY_OP,
|
||||
operators::INEFFECTIVE_BIT_MASK,
|
||||
operators::INTEGER_ARITHMETIC,
|
||||
operators::INTEGER_DIVISION,
|
||||
operators::MISREFACTORED_ASSIGN_OP,
|
||||
operators::MODULO_ARITHMETIC,
|
||||
operators::MODULO_ONE,
|
||||
operators::NEEDLESS_BITWISE_BOOL,
|
||||
operators::OP_REF,
|
||||
operators::PTR_EQ,
|
||||
operators::SELF_ASSIGNMENT,
|
||||
operators::VERBOSE_BIT_MASK,
|
||||
option_env_unwrap::OPTION_ENV_UNWRAP,
|
||||
option_if_let_else::OPTION_IF_LET_ELSE,
|
||||
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
|
||||
panic_in_result_fn::PANIC_IN_RESULT_FN,
|
||||
panic_unimplemented::PANIC,
|
||||
panic_unimplemented::TODO,
|
||||
panic_unimplemented::UNIMPLEMENTED,
|
||||
panic_unimplemented::UNREACHABLE,
|
||||
partial_pub_fields::PARTIAL_PUB_FIELDS,
|
||||
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
|
||||
partialeq_to_none::PARTIALEQ_TO_NONE,
|
||||
pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
|
||||
pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
|
||||
pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
|
||||
precedence::PRECEDENCE,
|
||||
ptr::CMP_NULL,
|
||||
ptr::INVALID_NULL_PTR_USAGE,
|
||||
ptr::MUT_FROM_REF,
|
||||
ptr::PTR_ARG,
|
||||
ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
|
||||
pub_use::PUB_USE,
|
||||
question_mark::QUESTION_MARK,
|
||||
ranges::MANUAL_RANGE_CONTAINS,
|
||||
ranges::RANGE_MINUS_ONE,
|
||||
ranges::RANGE_PLUS_ONE,
|
||||
ranges::REVERSED_EMPTY_RANGES,
|
||||
rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
|
||||
read_zero_byte_vec::READ_ZERO_BYTE_VEC,
|
||||
redundant_clone::REDUNDANT_CLONE,
|
||||
redundant_closure_call::REDUNDANT_CLOSURE_CALL,
|
||||
redundant_else::REDUNDANT_ELSE,
|
||||
redundant_field_names::REDUNDANT_FIELD_NAMES,
|
||||
redundant_pub_crate::REDUNDANT_PUB_CRATE,
|
||||
redundant_slicing::DEREF_BY_SLICING,
|
||||
redundant_slicing::REDUNDANT_SLICING,
|
||||
redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
|
||||
ref_option_ref::REF_OPTION_REF,
|
||||
reference::DEREF_ADDROF,
|
||||
regex::INVALID_REGEX,
|
||||
regex::TRIVIAL_REGEX,
|
||||
return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
|
||||
returns::LET_AND_RETURN,
|
||||
returns::NEEDLESS_RETURN,
|
||||
same_name_method::SAME_NAME_METHOD,
|
||||
self_named_constructors::SELF_NAMED_CONSTRUCTORS,
|
||||
semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
|
||||
serde_api::SERDE_API_MISUSE,
|
||||
shadow::SHADOW_REUSE,
|
||||
shadow::SHADOW_SAME,
|
||||
shadow::SHADOW_UNRELATED,
|
||||
single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
|
||||
single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
|
||||
size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
|
||||
slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
|
||||
std_instead_of_core::ALLOC_INSTEAD_OF_CORE,
|
||||
std_instead_of_core::STD_INSTEAD_OF_ALLOC,
|
||||
std_instead_of_core::STD_INSTEAD_OF_CORE,
|
||||
strings::STRING_ADD,
|
||||
strings::STRING_ADD_ASSIGN,
|
||||
strings::STRING_FROM_UTF8_AS_BYTES,
|
||||
strings::STRING_LIT_AS_BYTES,
|
||||
strings::STRING_SLICE,
|
||||
strings::STRING_TO_STRING,
|
||||
strings::STR_TO_STRING,
|
||||
strings::TRIM_SPLIT_WHITESPACE,
|
||||
strlen_on_c_strings::STRLEN_ON_C_STRINGS,
|
||||
suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
|
||||
suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
|
||||
suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
|
||||
swap::ALMOST_SWAPPED,
|
||||
swap::MANUAL_SWAP,
|
||||
swap_ptr_to_ref::SWAP_PTR_TO_REF,
|
||||
tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
|
||||
temporary_assignment::TEMPORARY_ASSIGNMENT,
|
||||
to_digit_is_some::TO_DIGIT_IS_SOME,
|
||||
trailing_empty_array::TRAILING_EMPTY_ARRAY,
|
||||
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
|
||||
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
|
||||
transmute::CROSSPOINTER_TRANSMUTE,
|
||||
transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
|
||||
transmute::TRANSMUTE_BYTES_TO_STR,
|
||||
transmute::TRANSMUTE_FLOAT_TO_INT,
|
||||
transmute::TRANSMUTE_INT_TO_BOOL,
|
||||
transmute::TRANSMUTE_INT_TO_CHAR,
|
||||
transmute::TRANSMUTE_INT_TO_FLOAT,
|
||||
transmute::TRANSMUTE_NUM_TO_BYTES,
|
||||
transmute::TRANSMUTE_PTR_TO_PTR,
|
||||
transmute::TRANSMUTE_PTR_TO_REF,
|
||||
transmute::TRANSMUTE_UNDEFINED_REPR,
|
||||
transmute::TRANSMUTING_NULL,
|
||||
transmute::UNSOUND_COLLECTION_TRANSMUTE,
|
||||
transmute::USELESS_TRANSMUTE,
|
||||
transmute::WRONG_TRANSMUTE,
|
||||
types::BORROWED_BOX,
|
||||
types::BOX_COLLECTION,
|
||||
types::LINKEDLIST,
|
||||
types::OPTION_OPTION,
|
||||
types::RC_BUFFER,
|
||||
types::RC_MUTEX,
|
||||
types::REDUNDANT_ALLOCATION,
|
||||
types::TYPE_COMPLEXITY,
|
||||
types::VEC_BOX,
|
||||
undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
|
||||
unicode::INVISIBLE_CHARACTERS,
|
||||
unicode::NON_ASCII_LITERAL,
|
||||
unicode::UNICODE_NOT_NFC,
|
||||
uninit_vec::UNINIT_VEC,
|
||||
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
|
||||
unit_types::LET_UNIT_VALUE,
|
||||
unit_types::UNIT_ARG,
|
||||
unit_types::UNIT_CMP,
|
||||
unnamed_address::FN_ADDRESS_COMPARISONS,
|
||||
unnamed_address::VTABLE_ADDRESS_COMPARISONS,
|
||||
unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS,
|
||||
unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
|
||||
unnecessary_wraps::UNNECESSARY_WRAPS,
|
||||
unnested_or_patterns::UNNESTED_OR_PATTERNS,
|
||||
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
|
||||
unused_async::UNUSED_ASYNC,
|
||||
unused_io_amount::UNUSED_IO_AMOUNT,
|
||||
unused_peekable::UNUSED_PEEKABLE,
|
||||
unused_rounding::UNUSED_ROUNDING,
|
||||
unused_self::UNUSED_SELF,
|
||||
unused_unit::UNUSED_UNIT,
|
||||
unwrap::PANICKING_UNWRAP,
|
||||
unwrap::UNNECESSARY_UNWRAP,
|
||||
unwrap_in_result::UNWRAP_IN_RESULT,
|
||||
upper_case_acronyms::UPPER_CASE_ACRONYMS,
|
||||
use_self::USE_SELF,
|
||||
useless_conversion::USELESS_CONVERSION,
|
||||
vec::USELESS_VEC,
|
||||
vec_init_then_push::VEC_INIT_THEN_PUSH,
|
||||
wildcard_imports::ENUM_GLOB_USE,
|
||||
wildcard_imports::WILDCARD_IMPORTS,
|
||||
write::PRINTLN_EMPTY_STRING,
|
||||
write::PRINT_LITERAL,
|
||||
write::PRINT_STDERR,
|
||||
write::PRINT_STDOUT,
|
||||
write::PRINT_WITH_NEWLINE,
|
||||
write::USE_DEBUG,
|
||||
write::WRITELN_EMPTY_STRING,
|
||||
write::WRITE_LITERAL,
|
||||
write::WRITE_WITH_NEWLINE,
|
||||
zero_div_zero::ZERO_DIVIDED_BY_ZERO,
|
||||
zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
|
||||
])
|
|
@ -1,39 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
|
||||
LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
|
||||
LintId::of(casts::AS_PTR_CAST_MUT),
|
||||
LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
|
||||
LintId::of(copies::BRANCHES_SHARING_CODE),
|
||||
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
|
||||
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
|
||||
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
|
||||
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
|
||||
LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
|
||||
LintId::of(future_not_send::FUTURE_NOT_SEND),
|
||||
LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
|
||||
LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
|
||||
LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
|
||||
LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS),
|
||||
LintId::of(methods::ITER_ON_SINGLE_ITEMS),
|
||||
LintId::of(methods::ITER_WITH_DRAIN),
|
||||
LintId::of(methods::PATH_BUF_PUSH_OVERWRITE),
|
||||
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
|
||||
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
|
||||
LintId::of(mutex_atomic::MUTEX_ATOMIC),
|
||||
LintId::of(mutex_atomic::MUTEX_INTEGER),
|
||||
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
|
||||
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
|
||||
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
|
||||
LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
|
||||
LintId::of(regex::TRIVIAL_REGEX),
|
||||
LintId::of(strings::STRING_LIT_AS_BYTES),
|
||||
LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
|
||||
LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
|
||||
LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
|
||||
LintId::of(unused_peekable::UNUSED_PEEKABLE),
|
||||
LintId::of(unused_rounding::UNUSED_ROUNDING),
|
||||
LintId::of(use_self::USE_SELF),
|
||||
])
|
|
@ -1,104 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
|
||||
LintId::of(attrs::INLINE_ALWAYS),
|
||||
LintId::of(casts::BORROW_AS_PTR),
|
||||
LintId::of(casts::CAST_LOSSLESS),
|
||||
LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
|
||||
LintId::of(casts::CAST_POSSIBLE_WRAP),
|
||||
LintId::of(casts::CAST_PRECISION_LOSS),
|
||||
LintId::of(casts::CAST_PTR_ALIGNMENT),
|
||||
LintId::of(casts::CAST_SIGN_LOSS),
|
||||
LintId::of(casts::PTR_AS_PTR),
|
||||
LintId::of(checked_conversions::CHECKED_CONVERSIONS),
|
||||
LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
|
||||
LintId::of(copy_iterator::COPY_ITERATOR),
|
||||
LintId::of(default::DEFAULT_TRAIT_ACCESS),
|
||||
LintId::of(dereference::EXPLICIT_DEREF_METHODS),
|
||||
LintId::of(dereference::REF_BINDING_TO_REFERENCE),
|
||||
LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
|
||||
LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
|
||||
LintId::of(doc::DOC_LINK_WITH_QUOTES),
|
||||
LintId::of(doc::DOC_MARKDOWN),
|
||||
LintId::of(doc::MISSING_ERRORS_DOC),
|
||||
LintId::of(doc::MISSING_PANICS_DOC),
|
||||
LintId::of(empty_enum::EMPTY_ENUM),
|
||||
LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
|
||||
LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
|
||||
LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
|
||||
LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
|
||||
LintId::of(format_args::UNINLINED_FORMAT_ARGS),
|
||||
LintId::of(functions::MUST_USE_CANDIDATE),
|
||||
LintId::of(functions::TOO_MANY_LINES),
|
||||
LintId::of(if_not_else::IF_NOT_ELSE),
|
||||
LintId::of(implicit_hasher::IMPLICIT_HASHER),
|
||||
LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
|
||||
LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
|
||||
LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
|
||||
LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
|
||||
LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR),
|
||||
LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
|
||||
LintId::of(let_underscore::LET_UNDERSCORE_DROP),
|
||||
LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
|
||||
LintId::of(literal_representation::UNREADABLE_LITERAL),
|
||||
LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
|
||||
LintId::of(loops::EXPLICIT_ITER_LOOP),
|
||||
LintId::of(macro_use::MACRO_USE_IMPORTS),
|
||||
LintId::of(manual_assert::MANUAL_ASSERT),
|
||||
LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
|
||||
LintId::of(manual_string_new::MANUAL_STRING_NEW),
|
||||
LintId::of(matches::MATCH_BOOL),
|
||||
LintId::of(matches::MATCH_ON_VEC_ITEMS),
|
||||
LintId::of(matches::MATCH_SAME_ARMS),
|
||||
LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
|
||||
LintId::of(matches::MATCH_WILD_ERR_ARM),
|
||||
LintId::of(matches::SINGLE_MATCH_ELSE),
|
||||
LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
|
||||
LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
|
||||
LintId::of(methods::FILTER_MAP_NEXT),
|
||||
LintId::of(methods::FLAT_MAP_OPTION),
|
||||
LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
|
||||
LintId::of(methods::IMPLICIT_CLONE),
|
||||
LintId::of(methods::INEFFICIENT_TO_STRING),
|
||||
LintId::of(methods::MANUAL_OK_OR),
|
||||
LintId::of(methods::MAP_UNWRAP_OR),
|
||||
LintId::of(methods::NAIVE_BYTECOUNT),
|
||||
LintId::of(methods::STABLE_SORT_PRIMITIVE),
|
||||
LintId::of(methods::UNNECESSARY_JOIN),
|
||||
LintId::of(misc::USED_UNDERSCORE_BINDING),
|
||||
LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
|
||||
LintId::of(mut_mut::MUT_MUT),
|
||||
LintId::of(needless_continue::NEEDLESS_CONTINUE),
|
||||
LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
|
||||
LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
|
||||
LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING),
|
||||
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
|
||||
LintId::of(non_expressive_names::SIMILAR_NAMES),
|
||||
LintId::of(operators::FLOAT_CMP),
|
||||
LintId::of(operators::NEEDLESS_BITWISE_BOOL),
|
||||
LintId::of(operators::VERBOSE_BIT_MASK),
|
||||
LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
|
||||
LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
|
||||
LintId::of(ranges::RANGE_MINUS_ONE),
|
||||
LintId::of(ranges::RANGE_PLUS_ONE),
|
||||
LintId::of(redundant_else::REDUNDANT_ELSE),
|
||||
LintId::of(ref_option_ref::REF_OPTION_REF),
|
||||
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
|
||||
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
|
||||
LintId::of(strings::STRING_ADD_ASSIGN),
|
||||
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
|
||||
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
|
||||
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
|
||||
LintId::of(types::LINKEDLIST),
|
||||
LintId::of(types::OPTION_OPTION),
|
||||
LintId::of(unicode::UNICODE_NOT_NFC),
|
||||
LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
|
||||
LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
|
||||
LintId::of(unused_async::UNUSED_ASYNC),
|
||||
LintId::of(unused_self::UNUSED_SELF),
|
||||
LintId::of(wildcard_imports::ENUM_GLOB_USE),
|
||||
LintId::of(wildcard_imports::WILDCARD_IMPORTS),
|
||||
LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
|
||||
])
|
|
@ -1,34 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
|
||||
LintId::of(box_default::BOX_DEFAULT),
|
||||
LintId::of(entry::MAP_ENTRY),
|
||||
LintId::of(escape::BOXED_LOCAL),
|
||||
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
|
||||
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
|
||||
LintId::of(functions::RESULT_LARGE_ERR),
|
||||
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
|
||||
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
|
||||
LintId::of(loops::MANUAL_MEMCPY),
|
||||
LintId::of(loops::MISSING_SPIN_LOOP),
|
||||
LintId::of(loops::NEEDLESS_COLLECT),
|
||||
LintId::of(manual_retain::MANUAL_RETAIN),
|
||||
LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
|
||||
LintId::of(methods::EXPECT_FUN_CALL),
|
||||
LintId::of(methods::EXTEND_WITH_DRAIN),
|
||||
LintId::of(methods::ITER_NTH),
|
||||
LintId::of(methods::ITER_OVEREAGER_CLONED),
|
||||
LintId::of(methods::MANUAL_STR_REPEAT),
|
||||
LintId::of(methods::OR_FUN_CALL),
|
||||
LintId::of(methods::SINGLE_CHAR_PATTERN),
|
||||
LintId::of(methods::UNNECESSARY_TO_OWNED),
|
||||
LintId::of(operators::CMP_OWNED),
|
||||
LintId::of(redundant_clone::REDUNDANT_CLONE),
|
||||
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
|
||||
LintId::of(types::BOX_COLLECTION),
|
||||
LintId::of(types::REDUNDANT_ALLOCATION),
|
||||
LintId::of(vec::USELESS_VEC),
|
||||
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
|
||||
])
|
|
@ -1,90 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||
LintId::of(as_conversions::AS_CONVERSIONS),
|
||||
LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
|
||||
LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
|
||||
LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
|
||||
LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
|
||||
LintId::of(casts::AS_UNDERSCORE),
|
||||
LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
|
||||
LintId::of(create_dir::CREATE_DIR),
|
||||
LintId::of(dbg_macro::DBG_MACRO),
|
||||
LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
|
||||
LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
|
||||
LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
|
||||
LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
|
||||
LintId::of(empty_drop::EMPTY_DROP),
|
||||
LintId::of(empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS),
|
||||
LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
|
||||
LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
|
||||
LintId::of(exit::EXIT),
|
||||
LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
|
||||
LintId::of(format_push_string::FORMAT_PUSH_STRING),
|
||||
LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
|
||||
LintId::of(implicit_return::IMPLICIT_RETURN),
|
||||
LintId::of(indexing_slicing::INDEXING_SLICING),
|
||||
LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
|
||||
LintId::of(large_include_file::LARGE_INCLUDE_FILE),
|
||||
LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
|
||||
LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
|
||||
LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
|
||||
LintId::of(matches::TRY_ERR),
|
||||
LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
|
||||
LintId::of(mem_forget::MEM_FORGET),
|
||||
LintId::of(methods::CLONE_ON_REF_PTR),
|
||||
LintId::of(methods::EXPECT_USED),
|
||||
LintId::of(methods::FILETYPE_IS_FILE),
|
||||
LintId::of(methods::GET_UNWRAP),
|
||||
LintId::of(methods::MAP_ERR_IGNORE),
|
||||
LintId::of(methods::UNWRAP_USED),
|
||||
LintId::of(methods::VERBOSE_FILE_READS),
|
||||
LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
|
||||
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
|
||||
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
|
||||
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
|
||||
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
|
||||
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
|
||||
LintId::of(missing_trait_methods::MISSING_TRAIT_METHODS),
|
||||
LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
|
||||
LintId::of(module_style::MOD_MODULE_FILES),
|
||||
LintId::of(module_style::SELF_NAMED_MODULE_FILES),
|
||||
LintId::of(operators::ARITHMETIC_SIDE_EFFECTS),
|
||||
LintId::of(operators::FLOAT_ARITHMETIC),
|
||||
LintId::of(operators::FLOAT_CMP_CONST),
|
||||
LintId::of(operators::INTEGER_ARITHMETIC),
|
||||
LintId::of(operators::INTEGER_DIVISION),
|
||||
LintId::of(operators::MODULO_ARITHMETIC),
|
||||
LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
|
||||
LintId::of(panic_unimplemented::PANIC),
|
||||
LintId::of(panic_unimplemented::TODO),
|
||||
LintId::of(panic_unimplemented::UNIMPLEMENTED),
|
||||
LintId::of(panic_unimplemented::UNREACHABLE),
|
||||
LintId::of(partial_pub_fields::PARTIAL_PUB_FIELDS),
|
||||
LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
|
||||
LintId::of(pub_use::PUB_USE),
|
||||
LintId::of(redundant_slicing::DEREF_BY_SLICING),
|
||||
LintId::of(same_name_method::SAME_NAME_METHOD),
|
||||
LintId::of(shadow::SHADOW_REUSE),
|
||||
LintId::of(shadow::SHADOW_SAME),
|
||||
LintId::of(shadow::SHADOW_UNRELATED),
|
||||
LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
|
||||
LintId::of(std_instead_of_core::ALLOC_INSTEAD_OF_CORE),
|
||||
LintId::of(std_instead_of_core::STD_INSTEAD_OF_ALLOC),
|
||||
LintId::of(std_instead_of_core::STD_INSTEAD_OF_CORE),
|
||||
LintId::of(strings::STRING_ADD),
|
||||
LintId::of(strings::STRING_SLICE),
|
||||
LintId::of(strings::STRING_TO_STRING),
|
||||
LintId::of(strings::STR_TO_STRING),
|
||||
LintId::of(types::RC_BUFFER),
|
||||
LintId::of(types::RC_MUTEX),
|
||||
LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
|
||||
LintId::of(unicode::NON_ASCII_LITERAL),
|
||||
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
|
||||
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
|
||||
LintId::of(write::PRINT_STDERR),
|
||||
LintId::of(write::PRINT_STDOUT),
|
||||
LintId::of(write::USE_DEBUG),
|
||||
])
|
|
@ -1,131 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::style", Some("clippy_style"), vec![
|
||||
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
|
||||
LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
|
||||
LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
|
||||
LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
|
||||
LintId::of(casts::FN_TO_NUMERIC_CAST),
|
||||
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
||||
LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
|
||||
LintId::of(collapsible_if::COLLAPSIBLE_IF),
|
||||
LintId::of(comparison_chain::COMPARISON_CHAIN),
|
||||
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
|
||||
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
|
||||
LintId::of(dereference::NEEDLESS_BORROW),
|
||||
LintId::of(disallowed_macros::DISALLOWED_MACROS),
|
||||
LintId::of(disallowed_methods::DISALLOWED_METHODS),
|
||||
LintId::of(disallowed_names::DISALLOWED_NAMES),
|
||||
LintId::of(disallowed_types::DISALLOWED_TYPES),
|
||||
LintId::of(doc::MISSING_SAFETY_DOC),
|
||||
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
|
||||
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
|
||||
LintId::of(enum_variants::MODULE_INCEPTION),
|
||||
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
|
||||
LintId::of(float_literal::EXCESSIVE_PRECISION),
|
||||
LintId::of(from_over_into::FROM_OVER_INTO),
|
||||
LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
|
||||
LintId::of(functions::DOUBLE_MUST_USE),
|
||||
LintId::of(functions::MUST_USE_UNIT),
|
||||
LintId::of(functions::RESULT_UNIT_ERR),
|
||||
LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
|
||||
LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING),
|
||||
LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
|
||||
LintId::of(len_zero::COMPARISON_TO_EMPTY),
|
||||
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
|
||||
LintId::of(len_zero::LEN_ZERO),
|
||||
LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
|
||||
LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
|
||||
LintId::of(loops::FOR_KV_MAP),
|
||||
LintId::of(loops::NEEDLESS_RANGE_LOOP),
|
||||
LintId::of(loops::SAME_ITEM_PUSH),
|
||||
LintId::of(loops::WHILE_LET_ON_ITERATOR),
|
||||
LintId::of(main_recursion::MAIN_RECURSION),
|
||||
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
|
||||
LintId::of(manual_bits::MANUAL_BITS),
|
||||
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||
LintId::of(match_result_ok::MATCH_RESULT_OK),
|
||||
LintId::of(matches::COLLAPSIBLE_MATCH),
|
||||
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||
LintId::of(matches::MANUAL_MAP),
|
||||
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
|
||||
LintId::of(matches::MATCH_OVERLAPPING_ARM),
|
||||
LintId::of(matches::MATCH_REF_PATS),
|
||||
LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
|
||||
LintId::of(matches::SINGLE_MATCH),
|
||||
LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
|
||||
LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
|
||||
LintId::of(methods::BYTES_NTH),
|
||||
LintId::of(methods::CHARS_LAST_CMP),
|
||||
LintId::of(methods::CHARS_NEXT_CMP),
|
||||
LintId::of(methods::ERR_EXPECT),
|
||||
LintId::of(methods::GET_FIRST),
|
||||
LintId::of(methods::INTO_ITER_ON_REF),
|
||||
LintId::of(methods::IS_DIGIT_ASCII_RADIX),
|
||||
LintId::of(methods::ITER_CLONED_COLLECT),
|
||||
LintId::of(methods::ITER_NEXT_SLICE),
|
||||
LintId::of(methods::ITER_NTH_ZERO),
|
||||
LintId::of(methods::ITER_SKIP_NEXT),
|
||||
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
|
||||
LintId::of(methods::MAP_CLONE),
|
||||
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
|
||||
LintId::of(methods::MUT_MUTEX_LOCK),
|
||||
LintId::of(methods::NEW_RET_NO_SELF),
|
||||
LintId::of(methods::OBFUSCATED_IF_ELSE),
|
||||
LintId::of(methods::OK_EXPECT),
|
||||
LintId::of(methods::OPTION_MAP_OR_NONE),
|
||||
LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
|
||||
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
|
||||
LintId::of(methods::SINGLE_CHAR_ADD_STR),
|
||||
LintId::of(methods::STRING_EXTEND_CHARS),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(misc::TOPLEVEL_REF_ARG),
|
||||
LintId::of(misc::ZERO_PTR),
|
||||
LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
|
||||
LintId::of(misc_early::DOUBLE_NEG),
|
||||
LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
|
||||
LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
|
||||
LintId::of(misc_early::REDUNDANT_PATTERN),
|
||||
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
|
||||
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
|
||||
LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
|
||||
LintId::of(neg_multiply::NEG_MULTIPLY),
|
||||
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
|
||||
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
|
||||
LintId::of(operators::ASSIGN_OP_PATTERN),
|
||||
LintId::of(operators::OP_REF),
|
||||
LintId::of(operators::PTR_EQ),
|
||||
LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
|
||||
LintId::of(ptr::CMP_NULL),
|
||||
LintId::of(ptr::PTR_ARG),
|
||||
LintId::of(question_mark::QUESTION_MARK),
|
||||
LintId::of(ranges::MANUAL_RANGE_CONTAINS),
|
||||
LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
|
||||
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
||||
LintId::of(returns::LET_AND_RETURN),
|
||||
LintId::of(returns::NEEDLESS_RETURN),
|
||||
LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
|
||||
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
|
||||
LintId::of(strings::TRIM_SPLIT_WHITESPACE),
|
||||
LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
|
||||
LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
|
||||
LintId::of(unit_types::LET_UNIT_VALUE),
|
||||
LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
|
||||
LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
||||
LintId::of(unused_unit::UNUSED_UNIT),
|
||||
LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
|
||||
LintId::of(write::PRINTLN_EMPTY_STRING),
|
||||
LintId::of(write::PRINT_LITERAL),
|
||||
LintId::of(write::PRINT_WITH_NEWLINE),
|
||||
LintId::of(write::WRITELN_EMPTY_STRING),
|
||||
LintId::of(write::WRITE_LITERAL),
|
||||
LintId::of(write::WRITE_WITH_NEWLINE),
|
||||
])
|
|
@ -1,38 +0,0 @@
|
|||
// This file was generated by `cargo dev update_lints`.
|
||||
// Use that command to update this file and do not edit by hand.
|
||||
// Manual edits will be overwritten.
|
||||
|
||||
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
|
||||
LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
|
||||
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
|
||||
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
|
||||
LintId::of(casts::CAST_ENUM_TRUNCATION),
|
||||
LintId::of(casts::CAST_NAN_TO_INT),
|
||||
LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
|
||||
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
|
||||
LintId::of(drop_forget_ref::DROP_NON_DROP),
|
||||
LintId::of(drop_forget_ref::FORGET_NON_DROP),
|
||||
LintId::of(duplicate_mod::DUPLICATE_MOD),
|
||||
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
|
||||
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
|
||||
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
||||
LintId::of(loops::EMPTY_LOOP),
|
||||
LintId::of(loops::MUT_RANGE_BOUND),
|
||||
LintId::of(methods::NO_EFFECT_REPLACE),
|
||||
LintId::of(methods::SUSPICIOUS_MAP),
|
||||
LintId::of(methods::SUSPICIOUS_TO_OWNED),
|
||||
LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
|
||||
LintId::of(mut_key::MUTABLE_KEY_TYPE),
|
||||
LintId::of(octal_escapes::OCTAL_ESCAPES),
|
||||
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
|
||||
LintId::of(operators::MISREFACTORED_ASSIGN_OP),
|
||||
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
|
||||
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
|
||||
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
|
||||
LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
|
||||
])
|
|
@ -32,8 +32,8 @@ extern crate rustc_driver;
|
|||
extern crate rustc_errors;
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_hir_analysis;
|
||||
extern crate rustc_hir_typeck;
|
||||
extern crate rustc_hir_pretty;
|
||||
extern crate rustc_hir_typeck;
|
||||
extern crate rustc_index;
|
||||
extern crate rustc_infer;
|
||||
extern crate rustc_lexer;
|
||||
|
@ -47,122 +47,24 @@ extern crate rustc_trait_selection;
|
|||
|
||||
#[macro_use]
|
||||
extern crate clippy_utils;
|
||||
#[macro_use]
|
||||
extern crate declare_clippy_lint;
|
||||
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clippy_utils::parse_msrv;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_lint::LintId;
|
||||
use rustc_lint::{Lint, LintId};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::Session;
|
||||
|
||||
/// Macro used to declare a Clippy lint.
|
||||
///
|
||||
/// Every lint declaration consists of 4 parts:
|
||||
///
|
||||
/// 1. The documentation, which is used for the website
|
||||
/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions.
|
||||
/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or
|
||||
/// `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of.
|
||||
/// 4. The `description` that contains a short explanation on what's wrong with code where the
|
||||
/// lint is triggered.
|
||||
///
|
||||
/// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are
|
||||
/// enabled by default. As said in the README.md of this repository, if the lint level mapping
|
||||
/// changes, please update README.md.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(rustc_private)]
|
||||
/// extern crate rustc_session;
|
||||
/// use rustc_session::declare_tool_lint;
|
||||
/// use clippy_lints::declare_clippy_lint;
|
||||
///
|
||||
/// declare_clippy_lint! {
|
||||
/// /// ### What it does
|
||||
/// /// Checks for ... (describe what the lint matches).
|
||||
/// ///
|
||||
/// /// ### Why is this bad?
|
||||
/// /// Supply the reason for linting the code.
|
||||
/// ///
|
||||
/// /// ### Example
|
||||
/// /// ```rust
|
||||
/// /// Insert a short example of code that triggers the lint
|
||||
/// /// ```
|
||||
/// ///
|
||||
/// /// Use instead:
|
||||
/// /// ```rust
|
||||
/// /// Insert a short example of improved code that doesn't trigger the lint
|
||||
/// /// ```
|
||||
/// pub LINT_NAME,
|
||||
/// pedantic,
|
||||
/// "description"
|
||||
/// }
|
||||
/// ```
|
||||
/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
|
||||
#[macro_export]
|
||||
macro_rules! declare_clippy_lint {
|
||||
{ $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, suspicious, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
{ $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
|
||||
declare_tool_lint! {
|
||||
$(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "internal")]
|
||||
pub mod deprecated_lints;
|
||||
#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
|
||||
mod utils;
|
||||
|
||||
mod declared_lints;
|
||||
mod renamed_lints;
|
||||
|
||||
// begin lints modules, do not remove this comment, it’s used in `update_lints`
|
||||
|
@ -231,6 +133,7 @@ mod format_impl;
|
|||
mod format_push_string;
|
||||
mod formatting;
|
||||
mod from_over_into;
|
||||
mod from_raw_with_void_ptr;
|
||||
mod from_str_radix_10;
|
||||
mod functions;
|
||||
mod future_not_send;
|
||||
|
@ -249,6 +152,7 @@ mod inherent_impl;
|
|||
mod inherent_to_string;
|
||||
mod init_numbered_fields;
|
||||
mod inline_fn_without_body;
|
||||
mod instant_subtraction;
|
||||
mod int_plus_one;
|
||||
mod invalid_upcast_comparisons;
|
||||
mod invalid_utf8_in_unchecked;
|
||||
|
@ -270,7 +174,8 @@ mod manual_assert;
|
|||
mod manual_async_fn;
|
||||
mod manual_bits;
|
||||
mod manual_clamp;
|
||||
mod manual_instant_elapsed;
|
||||
mod manual_is_ascii_check;
|
||||
mod manual_let_else;
|
||||
mod manual_non_exhaustive;
|
||||
mod manual_rem_euclid;
|
||||
mod manual_retain;
|
||||
|
@ -365,6 +270,7 @@ mod strings;
|
|||
mod strlen_on_c_strings;
|
||||
mod suspicious_operation_groupings;
|
||||
mod suspicious_trait_impl;
|
||||
mod suspicious_xor_used_as_pow;
|
||||
mod swap;
|
||||
mod swap_ptr_to_ref;
|
||||
mod tabs_in_doc_comments;
|
||||
|
@ -404,8 +310,8 @@ mod zero_div_zero;
|
|||
mod zero_sized_map_values;
|
||||
// end lints modules, do not remove this comment, it’s used in `update_lints`
|
||||
|
||||
pub use crate::utils::conf::Conf;
|
||||
use crate::utils::conf::{format_error, TryConf};
|
||||
pub use crate::utils::conf::{lookup_conf_file, Conf};
|
||||
|
||||
/// Register all pre expansion lints
|
||||
///
|
||||
|
@ -462,8 +368,8 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn read_conf(sess: &Session) -> Conf {
|
||||
let file_name = match utils::conf::lookup_conf_file() {
|
||||
pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
|
||||
let file_name = match path {
|
||||
Ok(Some(path)) => path,
|
||||
Ok(None) => return Conf::default(),
|
||||
Err(error) => {
|
||||
|
@ -473,7 +379,7 @@ pub fn read_conf(sess: &Session) -> Conf {
|
|||
},
|
||||
};
|
||||
|
||||
let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
|
||||
let TryConf { conf, errors, warnings } = utils::conf::read(file_name);
|
||||
// all conf errors are non-fatal, we just use the default conf in case of error
|
||||
for error in errors {
|
||||
sess.err(format!(
|
||||
|
@ -495,31 +401,121 @@ pub fn read_conf(sess: &Session) -> Conf {
|
|||
conf
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct RegistrationGroups {
|
||||
all: Vec<LintId>,
|
||||
cargo: Vec<LintId>,
|
||||
complexity: Vec<LintId>,
|
||||
correctness: Vec<LintId>,
|
||||
nursery: Vec<LintId>,
|
||||
pedantic: Vec<LintId>,
|
||||
perf: Vec<LintId>,
|
||||
restriction: Vec<LintId>,
|
||||
style: Vec<LintId>,
|
||||
suspicious: Vec<LintId>,
|
||||
#[cfg(feature = "internal")]
|
||||
internal: Vec<LintId>,
|
||||
}
|
||||
|
||||
impl RegistrationGroups {
|
||||
#[rustfmt::skip]
|
||||
fn register(self, store: &mut rustc_lint::LintStore) {
|
||||
store.register_group(true, "clippy::all", Some("clippy_all"), self.all);
|
||||
store.register_group(true, "clippy::cargo", Some("clippy_cargo"), self.cargo);
|
||||
store.register_group(true, "clippy::complexity", Some("clippy_complexity"), self.complexity);
|
||||
store.register_group(true, "clippy::correctness", Some("clippy_correctness"), self.correctness);
|
||||
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), self.nursery);
|
||||
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), self.pedantic);
|
||||
store.register_group(true, "clippy::perf", Some("clippy_perf"), self.perf);
|
||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction);
|
||||
store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
|
||||
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
|
||||
#[cfg(feature = "internal")]
|
||||
store.register_group(true, "clippy::internal", Some("clippy_internal"), self.internal);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum LintCategory {
|
||||
Cargo,
|
||||
Complexity,
|
||||
Correctness,
|
||||
Nursery,
|
||||
Pedantic,
|
||||
Perf,
|
||||
Restriction,
|
||||
Style,
|
||||
Suspicious,
|
||||
#[cfg(feature = "internal")]
|
||||
Internal,
|
||||
}
|
||||
#[allow(clippy::enum_glob_use)]
|
||||
use LintCategory::*;
|
||||
|
||||
impl LintCategory {
|
||||
fn is_all(self) -> bool {
|
||||
matches!(self, Correctness | Suspicious | Style | Complexity | Perf)
|
||||
}
|
||||
|
||||
fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> {
|
||||
match self {
|
||||
Cargo => &mut groups.cargo,
|
||||
Complexity => &mut groups.complexity,
|
||||
Correctness => &mut groups.correctness,
|
||||
Nursery => &mut groups.nursery,
|
||||
Pedantic => &mut groups.pedantic,
|
||||
Perf => &mut groups.perf,
|
||||
Restriction => &mut groups.restriction,
|
||||
Style => &mut groups.style,
|
||||
Suspicious => &mut groups.suspicious,
|
||||
#[cfg(feature = "internal")]
|
||||
Internal => &mut groups.internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LintInfo {
|
||||
/// Double reference to maintain pointer equality
|
||||
lint: &'static &'static Lint,
|
||||
category: LintCategory,
|
||||
explanation: &'static str,
|
||||
}
|
||||
|
||||
pub fn explain(name: &str) {
|
||||
let target = format!("clippy::{}", name.to_ascii_uppercase());
|
||||
match declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
|
||||
Some(info) => print!("{}", info.explanation),
|
||||
None => println!("unknown lint: {name}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn register_categories(store: &mut rustc_lint::LintStore) {
|
||||
let mut groups = RegistrationGroups::default();
|
||||
|
||||
for LintInfo { lint, category, .. } in declared_lints::LINTS {
|
||||
if category.is_all() {
|
||||
groups.all.push(LintId::of(lint));
|
||||
}
|
||||
|
||||
category.group(&mut groups).push(LintId::of(lint));
|
||||
}
|
||||
|
||||
let lints: Vec<&'static Lint> = declared_lints::LINTS.iter().map(|info| *info.lint).collect();
|
||||
|
||||
store.register_lints(&lints);
|
||||
groups.register(store);
|
||||
}
|
||||
|
||||
/// Register all lints and lint groups with the rustc plugin registry
|
||||
///
|
||||
/// Used in `./src/driver.rs`.
|
||||
#[expect(clippy::too_many_lines)]
|
||||
pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
|
||||
register_removed_non_tool_lints(store);
|
||||
register_categories(store);
|
||||
|
||||
include!("lib.deprecated.rs");
|
||||
|
||||
include!("lib.register_lints.rs");
|
||||
include!("lib.register_restriction.rs");
|
||||
include!("lib.register_pedantic.rs");
|
||||
|
||||
#[cfg(feature = "internal")]
|
||||
include!("lib.register_internal.rs");
|
||||
|
||||
include!("lib.register_all.rs");
|
||||
include!("lib.register_style.rs");
|
||||
include!("lib.register_complexity.rs");
|
||||
include!("lib.register_correctness.rs");
|
||||
include!("lib.register_suspicious.rs");
|
||||
include!("lib.register_perf.rs");
|
||||
include!("lib.register_cargo.rs");
|
||||
include!("lib.register_nursery.rs");
|
||||
|
||||
#[cfg(feature = "internal")]
|
||||
{
|
||||
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
|
||||
|
@ -614,6 +610,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
))
|
||||
});
|
||||
store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv)));
|
||||
let matches_for_let_else = conf.matches_for_let_else;
|
||||
store.register_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv, matches_for_let_else)));
|
||||
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
|
||||
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
|
||||
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv)));
|
||||
|
@ -735,7 +733,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
let max_trait_bounds = conf.max_trait_bounds;
|
||||
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
|
||||
store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
|
||||
store.register_late_pass(|_| Box::new(mut_key::MutableKeyType));
|
||||
let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
|
||||
store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
|
||||
store.register_early_pass(|| Box::new(reference::DerefAddrOf));
|
||||
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
|
||||
store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
|
||||
|
@ -794,10 +793,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
|
||||
store.register_early_pass(|| Box::new(as_conversions::AsConversions));
|
||||
store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
|
||||
store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
|
||||
store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
|
||||
let max_fn_params_bools = conf.max_fn_params_bools;
|
||||
let max_struct_bools = conf.max_struct_bools;
|
||||
store.register_early_pass(move || {
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(excessive_bools::ExcessiveBools::new(
|
||||
max_struct_bools,
|
||||
max_fn_params_bools,
|
||||
|
@ -879,13 +878,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
|
||||
let allow_dbg_in_tests = conf.allow_dbg_in_tests;
|
||||
store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
|
||||
let allow_print_in_tests = conf.allow_print_in_tests;
|
||||
store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests)));
|
||||
let cargo_ignore_publish = conf.cargo_ignore_publish;
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(cargo::Cargo {
|
||||
ignore_publish: cargo_ignore_publish,
|
||||
})
|
||||
});
|
||||
store.register_late_pass(|_| Box::<write::Write>::default());
|
||||
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
|
||||
store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
|
||||
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
|
||||
|
@ -908,7 +908,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
|
||||
store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
|
||||
store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
|
||||
store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed));
|
||||
store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv)));
|
||||
store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
|
||||
store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv)));
|
||||
store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
|
||||
|
@ -919,6 +919,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
|
||||
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
|
||||
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
|
||||
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
|
||||
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
|
||||
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv)));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::trait_ref_of_method;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
|
||||
|
@ -152,6 +152,7 @@ fn check_fn_inner<'tcx>(
|
|||
.params
|
||||
.iter()
|
||||
.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)) {
|
||||
if pred.origin == PredicateOrigin::WhereClause {
|
||||
|
@ -188,15 +189,30 @@ fn check_fn_inner<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
if could_use_elision(cx, decl, body, trait_sig, generics.params) {
|
||||
span_lint(
|
||||
|
||||
if let Some(elidable_lts) = could_use_elision(cx, decl, body, trait_sig, generics.params) {
|
||||
let lts = elidable_lts
|
||||
.iter()
|
||||
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
|
||||
// `Node::GenericParam`.
|
||||
.filter_map(|&(def_id, _)| cx.tcx.hir().get_by_def_id(def_id).ident())
|
||||
.map(|ident| ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
span.with_hi(decl.output.span().hi()),
|
||||
"explicit lifetimes given in parameter types where they could be elided \
|
||||
(or replaced with `'_` if needed by type declaration)",
|
||||
&format!("the following explicit lifetimes could be elided: {lts}"),
|
||||
|diag| {
|
||||
if let Some(span) = elidable_lts.iter().find_map(|&(_, span)| span) {
|
||||
diag.span_help(span, "replace with `'_` in generic arguments such as here");
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if report_extra_lifetimes {
|
||||
self::report_extra_lifetimes(cx, decl, generics);
|
||||
}
|
||||
|
@ -227,7 +243,7 @@ fn could_use_elision<'tcx>(
|
|||
body: Option<BodyId>,
|
||||
trait_sig: Option<&[Ident]>,
|
||||
named_generics: &'tcx [GenericParam<'_>],
|
||||
) -> bool {
|
||||
) -> Option<Vec<(LocalDefId, Option<Span>)>> {
|
||||
// There are two scenarios where elision works:
|
||||
// * no output references, all input references have different LT
|
||||
// * output references, exactly one input reference with same LT
|
||||
|
@ -254,7 +270,7 @@ fn could_use_elision<'tcx>(
|
|||
}
|
||||
|
||||
if input_visitor.abort() || output_visitor.abort() {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
|
||||
let input_lts = input_visitor.lts;
|
||||
|
@ -262,7 +278,7 @@ fn could_use_elision<'tcx>(
|
|||
|
||||
if let Some(trait_sig) = trait_sig {
|
||||
if explicit_self_type(cx, func, trait_sig.first().copied()) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +287,7 @@ fn could_use_elision<'tcx>(
|
|||
|
||||
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
|
||||
if explicit_self_type(cx, func, first_ident) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut checker = BodyLifetimeChecker {
|
||||
|
@ -279,14 +295,14 @@ fn could_use_elision<'tcx>(
|
|||
};
|
||||
checker.visit_expr(body.value);
|
||||
if checker.lifetimes_used_in_body {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// check for lifetimes from higher scopes
|
||||
for lt in input_lts.iter().chain(output_lts.iter()) {
|
||||
if !allowed_lts.contains(lt) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,48 +318,45 @@ fn could_use_elision<'tcx>(
|
|||
for lt in input_visitor.nested_elision_site_lts {
|
||||
if let RefLt::Named(def_id) = lt {
|
||||
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
for lt in output_visitor.nested_elision_site_lts {
|
||||
if let RefLt::Named(def_id) = lt {
|
||||
if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no input lifetimes? easy case!
|
||||
if input_lts.is_empty() {
|
||||
false
|
||||
} else if output_lts.is_empty() {
|
||||
// no output lifetimes, check distinctness of input lifetimes
|
||||
|
||||
// only unnamed and static, ok
|
||||
let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
|
||||
if unnamed_and_static {
|
||||
return false;
|
||||
}
|
||||
// we have no output reference, so we only need all distinct lifetimes
|
||||
input_lts.len() == unique_lifetimes(&input_lts)
|
||||
} else {
|
||||
// we have output references, so we need one input reference,
|
||||
// and all output lifetimes must be the same
|
||||
if unique_lifetimes(&output_lts) > 1 {
|
||||
return false;
|
||||
}
|
||||
if input_lts.len() == 1 {
|
||||
match (&input_lts[0], &output_lts[0]) {
|
||||
(&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true,
|
||||
(&RefLt::Named(_), &RefLt::Unnamed) => true,
|
||||
_ => false, /* already elided, different named lifetimes
|
||||
* or something static going on */
|
||||
// A lifetime can be newly elided if:
|
||||
// - It occurs only once among the inputs.
|
||||
// - If there are multiple input lifetimes, then the newly elided lifetime does not occur among the
|
||||
// outputs (because eliding such an lifetime would create an ambiguity).
|
||||
let elidable_lts = named_lifetime_occurrences(&input_lts)
|
||||
.into_iter()
|
||||
.filter_map(|(def_id, occurrences)| {
|
||||
if occurrences == 1 && (input_lts.len() == 1 || !output_lts.contains(&RefLt::Named(def_id))) {
|
||||
Some((
|
||||
def_id,
|
||||
input_visitor
|
||||
.lifetime_generic_arg_spans
|
||||
.get(&def_id)
|
||||
.or_else(|| output_visitor.lifetime_generic_arg_spans.get(&def_id))
|
||||
.copied(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if elidable_lts.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(elidable_lts)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,16 +372,31 @@ fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxH
|
|||
allowed_lts
|
||||
}
|
||||
|
||||
/// Number of unique lifetimes in the given vector.
|
||||
/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
|
||||
/// relative order.
|
||||
#[must_use]
|
||||
fn unique_lifetimes(lts: &[RefLt]) -> usize {
|
||||
lts.iter().collect::<FxHashSet<_>>().len()
|
||||
fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> {
|
||||
let mut occurrences = Vec::new();
|
||||
for lt in lts {
|
||||
if let &RefLt::Named(curr_def_id) = lt {
|
||||
if let Some(pair) = occurrences
|
||||
.iter_mut()
|
||||
.find(|(prev_def_id, _)| *prev_def_id == curr_def_id)
|
||||
{
|
||||
pair.1 += 1;
|
||||
} else {
|
||||
occurrences.push((curr_def_id, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
occurrences
|
||||
}
|
||||
|
||||
/// A visitor usable for `rustc_front::visit::walk_ty()`.
|
||||
struct RefVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
lts: Vec<RefLt>,
|
||||
lifetime_generic_arg_spans: FxHashMap<LocalDefId, Span>,
|
||||
nested_elision_site_lts: Vec<RefLt>,
|
||||
unelided_trait_object_lifetime: bool,
|
||||
}
|
||||
|
@ -378,6 +406,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
|||
Self {
|
||||
cx,
|
||||
lts: Vec::new(),
|
||||
lifetime_generic_arg_spans: FxHashMap::default(),
|
||||
nested_elision_site_lts: Vec::new(),
|
||||
unelided_trait_object_lifetime: false,
|
||||
}
|
||||
|
@ -467,6 +496,22 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
|
|||
_ => walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) {
|
||||
if let GenericArg::Lifetime(l) = generic_arg
|
||||
&& let LifetimeName::Param(def_id, _) = l.name
|
||||
{
|
||||
self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.span);
|
||||
}
|
||||
// Replace with `walk_generic_arg` if/when https://github.com/rust-lang/rust/pull/103692 lands.
|
||||
// walk_generic_arg(self, generic_arg);
|
||||
match generic_arg {
|
||||
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
|
||||
GenericArg::Type(ty) => self.visit_ty(ty),
|
||||
GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
|
||||
GenericArg::Infer(inf) => self.visit_infer(inf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
|
||||
|
|
|
@ -9,7 +9,6 @@ mod manual_flatten;
|
|||
mod manual_memcpy;
|
||||
mod missing_spin_loop;
|
||||
mod mut_range_bound;
|
||||
mod needless_collect;
|
||||
mod needless_range_loop;
|
||||
mod never_loop;
|
||||
mod same_item_push;
|
||||
|
@ -205,28 +204,6 @@ declare_clippy_lint! {
|
|||
"`loop { if let { ... } else break }`, which can be written as a `while let` loop"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for functions collecting an iterator when collect
|
||||
/// is not needed.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// `collect` causes the allocation of a new data structure,
|
||||
/// when this allocation may not be needed.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let iterator = vec![1].into_iter();
|
||||
/// let len = iterator.clone().collect::<Vec<_>>().len();
|
||||
/// // should be
|
||||
/// let len = iterator.count();
|
||||
/// ```
|
||||
#[clippy::version = "1.30.0"]
|
||||
pub NEEDLESS_COLLECT,
|
||||
perf,
|
||||
"collecting an iterator when collect is not needed"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks `for` loops over slices with an explicit counter
|
||||
|
@ -605,7 +582,6 @@ declare_lint_pass!(Loops => [
|
|||
EXPLICIT_INTO_ITER_LOOP,
|
||||
ITER_NEXT_LOOP,
|
||||
WHILE_LET_LOOP,
|
||||
NEEDLESS_COLLECT,
|
||||
EXPLICIT_COUNTER_LOOP,
|
||||
EMPTY_LOOP,
|
||||
WHILE_LET_ON_ITERATOR,
|
||||
|
@ -667,8 +643,6 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
|||
while_immutable_condition::check(cx, condition, body);
|
||||
missing_spin_loop::check(cx, condition, body);
|
||||
}
|
||||
|
||||
needless_collect::check(expr, cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,8 +52,8 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
|
|||
None
|
||||
}
|
||||
|
||||
fn check_for_mutation<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
fn check_for_mutation(
|
||||
cx: &LateContext<'_>,
|
||||
body: &Expr<'_>,
|
||||
bound_id_start: Option<HirId>,
|
||||
bound_id_end: Option<HirId>,
|
||||
|
@ -113,13 +113,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fake_read(
|
||||
&mut self,
|
||||
_: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
|
||||
_: FakeReadCause,
|
||||
_: HirId,
|
||||
) {
|
||||
}
|
||||
fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
||||
impl MutatePairDelegate<'_, '_> {
|
||||
|
|
|
@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::higher::ForLoop;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
|
||||
use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
use std::iter::{once, Iterator};
|
||||
|
@ -16,7 +16,7 @@ pub(super) fn check(
|
|||
span: Span,
|
||||
for_loop: Option<&ForLoop<'_>>,
|
||||
) {
|
||||
match never_loop_block(block, loop_id) {
|
||||
match never_loop_block(block, &mut Vec::new(), loop_id) {
|
||||
NeverLoopResult::AlwaysBreak => {
|
||||
span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
|
||||
if let Some(ForLoop {
|
||||
|
@ -92,35 +92,34 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
|
|||
}
|
||||
}
|
||||
|
||||
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
let mut iter = block
|
||||
fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
let iter = block
|
||||
.stmts
|
||||
.iter()
|
||||
.filter_map(stmt_to_expr)
|
||||
.chain(block.expr.map(|expr| (expr, None)));
|
||||
never_loop_expr_seq(&mut iter, main_loop_id)
|
||||
}
|
||||
|
||||
fn never_loop_expr_seq<'a, T: Iterator<Item = (&'a Expr<'a>, Option<&'a Block<'a>>)>>(
|
||||
es: &mut T,
|
||||
main_loop_id: HirId,
|
||||
) -> NeverLoopResult {
|
||||
es.map(|(e, els)| {
|
||||
let e = never_loop_expr(e, main_loop_id);
|
||||
els.map_or(e, |els| combine_branches(e, never_loop_block(els, main_loop_id)))
|
||||
iter.map(|(e, els)| {
|
||||
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||
// els is an else block in a let...else binding
|
||||
els.map_or(e, |els| {
|
||||
combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id))
|
||||
})
|
||||
})
|
||||
.fold(NeverLoopResult::Otherwise, combine_seq)
|
||||
}
|
||||
|
||||
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'tcx Block<'tcx>>)> {
|
||||
match stmt.kind {
|
||||
StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some((e, None)),
|
||||
StmtKind::Semi(e) | StmtKind::Expr(e) => Some((e, None)),
|
||||
// add the let...else expression (if present)
|
||||
StmtKind::Local(local) => local.init.map(|init| (init, local.els)),
|
||||
StmtKind::Item(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
|
||||
match expr.kind {
|
||||
ExprKind::Box(e)
|
||||
| ExprKind::Unary(_, e)
|
||||
|
@ -129,47 +128,56 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
|||
| ExprKind::Field(e, _)
|
||||
| ExprKind::AddrOf(_, _, e)
|
||||
| ExprKind::Repeat(e, _)
|
||||
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
|
||||
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
|
||||
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
|
||||
ExprKind::MethodCall(_, receiver, es, _) => {
|
||||
never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
|
||||
},
|
||||
| ExprKind::DropTemps(e) => never_loop_expr(e, ignore_ids, main_loop_id),
|
||||
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, ignore_ids, main_loop_id),
|
||||
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), ignore_ids, main_loop_id),
|
||||
ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
|
||||
&mut std::iter::once(receiver).chain(es.iter()),
|
||||
ignore_ids,
|
||||
main_loop_id,
|
||||
),
|
||||
ExprKind::Struct(_, fields, base) => {
|
||||
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
|
||||
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
|
||||
if let Some(base) = base {
|
||||
combine_both(fields, never_loop_expr(base, main_loop_id))
|
||||
combine_both(fields, never_loop_expr(base, ignore_ids, main_loop_id))
|
||||
} else {
|
||||
fields
|
||||
}
|
||||
},
|
||||
ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), main_loop_id),
|
||||
ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
|
||||
ExprKind::Binary(_, e1, e2)
|
||||
| ExprKind::Assign(e1, e2, _)
|
||||
| ExprKind::AssignOp(_, e1, e2)
|
||||
| ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), main_loop_id),
|
||||
| ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
|
||||
ExprKind::Loop(b, _, _, _) => {
|
||||
// Break can come from the inner loop so remove them.
|
||||
absorb_break(never_loop_block(b, main_loop_id))
|
||||
absorb_break(never_loop_block(b, ignore_ids, main_loop_id))
|
||||
},
|
||||
ExprKind::If(e, e2, e3) => {
|
||||
let e1 = never_loop_expr(e, main_loop_id);
|
||||
let e2 = never_loop_expr(e2, main_loop_id);
|
||||
let e3 = e3
|
||||
.as_ref()
|
||||
.map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
|
||||
let e1 = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||
let e2 = never_loop_expr(e2, ignore_ids, main_loop_id);
|
||||
let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
|
||||
never_loop_expr(e, ignore_ids, main_loop_id)
|
||||
});
|
||||
combine_seq(e1, combine_branches(e2, e3))
|
||||
},
|
||||
ExprKind::Match(e, arms, _) => {
|
||||
let e = never_loop_expr(e, main_loop_id);
|
||||
let e = never_loop_expr(e, ignore_ids, main_loop_id);
|
||||
if arms.is_empty() {
|
||||
e
|
||||
} else {
|
||||
let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), main_loop_id);
|
||||
let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
|
||||
combine_seq(e, arms)
|
||||
}
|
||||
},
|
||||
ExprKind::Block(b, _) => never_loop_block(b, main_loop_id),
|
||||
ExprKind::Block(b, l) => {
|
||||
if l.is_some() {
|
||||
ignore_ids.push(b.hir_id);
|
||||
}
|
||||
let ret = never_loop_block(b, ignore_ids, main_loop_id);
|
||||
ignore_ids.pop();
|
||||
ret
|
||||
},
|
||||
ExprKind::Continue(d) => {
|
||||
let id = d
|
||||
.target_id
|
||||
|
@ -180,20 +188,32 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
|||
NeverLoopResult::AlwaysBreak
|
||||
}
|
||||
},
|
||||
// checks if break targets a block instead of a loop
|
||||
ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
|
||||
.map_or(NeverLoopResult::Otherwise, |e| {
|
||||
combine_seq(never_loop_expr(e, ignore_ids, main_loop_id), NeverLoopResult::Otherwise)
|
||||
}),
|
||||
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
|
||||
combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
|
||||
combine_seq(
|
||||
never_loop_expr(e, ignore_ids, main_loop_id),
|
||||
NeverLoopResult::AlwaysBreak,
|
||||
)
|
||||
}),
|
||||
ExprKind::InlineAsm(asm) => asm
|
||||
.operands
|
||||
.iter()
|
||||
.map(|(o, _)| match o {
|
||||
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
|
||||
never_loop_expr(expr, main_loop_id)
|
||||
never_loop_expr(expr, ignore_ids, main_loop_id)
|
||||
},
|
||||
InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id),
|
||||
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
|
||||
never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id)
|
||||
InlineAsmOperand::Out { expr, .. } => {
|
||||
never_loop_expr_all(&mut expr.iter().copied(), ignore_ids, main_loop_id)
|
||||
},
|
||||
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
|
||||
&mut once(*in_expr).chain(out_expr.iter().copied()),
|
||||
ignore_ids,
|
||||
main_loop_id,
|
||||
),
|
||||
InlineAsmOperand::Const { .. }
|
||||
| InlineAsmOperand::SymFn { .. }
|
||||
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
|
||||
|
@ -208,13 +228,21 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
|
|||
}
|
||||
}
|
||||
|
||||
fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
|
||||
es.map(|e| never_loop_expr(e, main_loop_id))
|
||||
fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
||||
es: &mut T,
|
||||
ignore_ids: &mut Vec<HirId>,
|
||||
main_loop_id: HirId,
|
||||
) -> NeverLoopResult {
|
||||
es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
|
||||
.fold(NeverLoopResult::Otherwise, combine_both)
|
||||
}
|
||||
|
||||
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(e: &mut T, main_loop_id: HirId) -> NeverLoopResult {
|
||||
e.map(|e| never_loop_expr(e, main_loop_id))
|
||||
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
|
||||
e: &mut T,
|
||||
ignore_ids: &mut Vec<HirId>,
|
||||
main_loop_id: HirId,
|
||||
) -> NeverLoopResult {
|
||||
e.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
|
||||
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Lints subtraction between `Instant::now()` and another `Instant`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
|
||||
/// as `Instant` subtraction saturates.
|
||||
///
|
||||
/// `prev_instant.elapsed()` also more clearly signals intention.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// use std::time::Instant;
|
||||
/// let prev_instant = Instant::now();
|
||||
/// let duration = Instant::now() - prev_instant;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// use std::time::Instant;
|
||||
/// let prev_instant = Instant::now();
|
||||
/// let duration = prev_instant.elapsed();
|
||||
/// ```
|
||||
#[clippy::version = "1.64.0"]
|
||||
pub MANUAL_INSTANT_ELAPSED,
|
||||
pedantic,
|
||||
"subtraction between `Instant::now()` and previous `Instant`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]);
|
||||
|
||||
impl LateLintPass<'_> for ManualInstantElapsed {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
|
||||
if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind
|
||||
&& check_instant_now_call(cx, lhs)
|
||||
&& let ty_resolved = cx.typeck_results().expr_ty(rhs)
|
||||
&& let rustc_middle::ty::Adt(def, _) = ty_resolved.kind()
|
||||
&& clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT)
|
||||
&& let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_INSTANT_ELAPSED,
|
||||
expr.span,
|
||||
"manual implementation of `Instant::elapsed`",
|
||||
"try",
|
||||
format!("{}.elapsed()", sugg.maybe_par()),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
|
||||
if let ExprKind::Call(fn_expr, []) = expr_block.kind
|
||||
&& let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
|
||||
&& clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
158
clippy_lints/src/manual_is_ascii_check.rs
Normal file
158
clippy_lints/src/manual_is_ascii_check.rs
Normal file
|
@ -0,0 +1,158 @@
|
|||
use rustc_ast::LitKind::{Byte, Char};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{def_id::DefId, sym};
|
||||
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, meets_msrv, msrvs, source::snippet,
|
||||
};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Suggests to use dedicated built-in methods,
|
||||
/// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Using the built-in functions is more readable and makes it
|
||||
/// clear that it's not a specific subset of characters, but all
|
||||
/// ASCII (lowercase|uppercase|digit) characters.
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// assert!(matches!('x', 'a'..='z'));
|
||||
/// assert!(matches!(b'X', b'A'..=b'Z'));
|
||||
/// assert!(matches!('2', '0'..='9'));
|
||||
/// assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// assert!('x'.is_ascii_lowercase());
|
||||
/// assert!(b'X'.is_ascii_uppercase());
|
||||
/// assert!('2'.is_ascii_digit());
|
||||
/// assert!('x'.is_ascii_alphabetic());
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub MANUAL_IS_ASCII_CHECK,
|
||||
style,
|
||||
"use dedicated method to check ascii range"
|
||||
}
|
||||
impl_lint_pass!(ManualIsAsciiCheck => [MANUAL_IS_ASCII_CHECK]);
|
||||
|
||||
pub struct ManualIsAsciiCheck {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
|
||||
impl ManualIsAsciiCheck {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum CharRange {
|
||||
/// 'a'..='z' | b'a'..=b'z'
|
||||
LowerChar,
|
||||
/// 'A'..='Z' | b'A'..=b'Z'
|
||||
UpperChar,
|
||||
/// AsciiLower | AsciiUpper
|
||||
FullChar,
|
||||
/// '0..=9'
|
||||
Digit,
|
||||
Otherwise,
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if in_constant(cx, expr.hir_id) && !meets_msrv(self.msrv, msrvs::IS_ASCII_DIGIT_CONST) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(macro_call) = root_macro_call(expr.span) else { return };
|
||||
|
||||
if is_matches_macro(cx, macro_call.def_id) {
|
||||
if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
|
||||
let range = check_pat(&arm.pat.kind);
|
||||
|
||||
if let Some(sugg) = match range {
|
||||
CharRange::UpperChar => Some("is_ascii_uppercase"),
|
||||
CharRange::LowerChar => Some("is_ascii_lowercase"),
|
||||
CharRange::FullChar => Some("is_ascii_alphabetic"),
|
||||
CharRange::Digit => Some("is_ascii_digit"),
|
||||
CharRange::Otherwise => None,
|
||||
} {
|
||||
let default_snip = "..";
|
||||
// `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
|
||||
// macro span, so we check applicability manually by comparing `recv` is not default.
|
||||
let recv = snippet(cx, recv.span, default_snip);
|
||||
|
||||
let applicability = if recv == default_snip {
|
||||
Applicability::HasPlaceholders
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_IS_ASCII_CHECK,
|
||||
macro_call.span,
|
||||
"manual check for common ascii range",
|
||||
"try",
|
||||
format!("{recv}.{sugg}()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
|
||||
match pat_kind {
|
||||
PatKind::Or(pats) => {
|
||||
let ranges = pats.iter().map(|p| check_pat(&p.kind)).collect::<Vec<_>>();
|
||||
|
||||
if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) {
|
||||
CharRange::FullChar
|
||||
} else {
|
||||
CharRange::Otherwise
|
||||
}
|
||||
},
|
||||
PatKind::Range(Some(start), Some(end), kind) if *kind == RangeEnd::Included => check_range(start, end),
|
||||
_ => CharRange::Otherwise,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
|
||||
if let ExprKind::Lit(start_lit) = &start.kind
|
||||
&& let ExprKind::Lit(end_lit) = &end.kind {
|
||||
match (&start_lit.node, &end_lit.node) {
|
||||
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
|
||||
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
|
||||
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
|
||||
_ => CharRange::Otherwise,
|
||||
}
|
||||
} else {
|
||||
CharRange::Otherwise
|
||||
}
|
||||
}
|
||||
|
||||
fn is_matches_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
|
||||
if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) {
|
||||
return sym::matches_macro == name;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
297
clippy_lints/src/manual_let_else.rs
Normal file
297
clippy_lints/src/manual_let_else.rs
Normal file
|
@ -0,0 +1,297 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLetOrMatch;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::{for_each_expr, Descend};
|
||||
use clippy_utils::{meets_msrv, msrvs, peel_blocks};
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use serde::Deserialize;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Warn of cases where `let...else` could be used
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// `let...else` provides a standard construct for this pattern
|
||||
/// that people can easily recognize. It's also more compact.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # let w = Some(0);
|
||||
/// let v = if let Some(v) = w { v } else { return };
|
||||
/// ```
|
||||
///
|
||||
/// Could be written:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(let_else)]
|
||||
/// # fn main () {
|
||||
/// # let w = Some(0);
|
||||
/// let Some(v) = w else { return };
|
||||
/// # }
|
||||
/// ```
|
||||
#[clippy::version = "1.67.0"]
|
||||
pub MANUAL_LET_ELSE,
|
||||
pedantic,
|
||||
"manual implementation of a let...else statement"
|
||||
}
|
||||
|
||||
pub struct ManualLetElse {
|
||||
msrv: Option<RustcVersion>,
|
||||
matches_behaviour: MatchLintBehaviour,
|
||||
}
|
||||
|
||||
impl ManualLetElse {
|
||||
#[must_use]
|
||||
pub fn new(msrv: Option<RustcVersion>, matches_behaviour: MatchLintBehaviour) -> Self {
|
||||
Self {
|
||||
msrv,
|
||||
matches_behaviour,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
|
||||
let if_let_or_match = if_chain! {
|
||||
if meets_msrv(self.msrv, msrvs::LET_ELSE);
|
||||
if !in_external_macro(cx.sess(), stmt.span);
|
||||
if let StmtKind::Local(local) = stmt.kind;
|
||||
if let Some(init) = local.init;
|
||||
if local.els.is_none();
|
||||
if local.ty.is_none();
|
||||
if init.span.ctxt() == stmt.span.ctxt();
|
||||
if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init);
|
||||
then {
|
||||
if_let_or_match
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match if_let_or_match {
|
||||
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
|
||||
if expr_is_simple_identity(let_pat, if_then);
|
||||
if let Some(if_else) = if_else;
|
||||
if expr_diverges(cx, if_else);
|
||||
then {
|
||||
emit_manual_let_else(cx, stmt.span, if_let_expr, let_pat, if_else);
|
||||
}
|
||||
},
|
||||
IfLetOrMatch::Match(match_expr, arms, source) => {
|
||||
if self.matches_behaviour == MatchLintBehaviour::Never {
|
||||
return;
|
||||
}
|
||||
if source != MatchSource::Normal {
|
||||
return;
|
||||
}
|
||||
// Any other number than two arms doesn't (neccessarily)
|
||||
// have a trivial mapping to let else.
|
||||
if arms.len() != 2 {
|
||||
return;
|
||||
}
|
||||
// Guards don't give us an easy mapping either
|
||||
if arms.iter().any(|arm| arm.guard.is_some()) {
|
||||
return;
|
||||
}
|
||||
let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
|
||||
let diverging_arm_opt = arms
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
|
||||
let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
|
||||
let pat_arm = &arms[1 - idx];
|
||||
if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit_manual_let_else(cx, stmt.span, match_expr, pat_arm.pat, diverging_arm.body);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: &Pat<'_>, else_body: &Expr<'_>) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_LET_ELSE,
|
||||
span,
|
||||
"this could be rewritten as `let...else`",
|
||||
|diag| {
|
||||
// This is far from perfect, for example there needs to be:
|
||||
// * mut additions for the bindings
|
||||
// * renamings of the bindings
|
||||
// * unused binding collision detection with existing ones
|
||||
// * putting patterns with at the top level | inside ()
|
||||
// for this to be machine applicable.
|
||||
let app = Applicability::HasPlaceholders;
|
||||
|
||||
if let Some(sn_pat) = snippet_opt(cx, pat.span) &&
|
||||
let Some(sn_expr) = snippet_opt(cx, expr.span) &&
|
||||
let Some(sn_else) = snippet_opt(cx, else_body.span)
|
||||
{
|
||||
let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
|
||||
sn_else
|
||||
} else {
|
||||
format!("{{ {sn_else} }}")
|
||||
};
|
||||
let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
|
||||
diag.span_suggestion(span, "consider writing", sugg, app);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
|
||||
fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
|
||||
if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
|
||||
return ty.is_never();
|
||||
}
|
||||
false
|
||||
}
|
||||
// We can't just call is_never on expr and be done, because the type system
|
||||
// sometimes coerces the ! type to something different before we can get
|
||||
// our hands on it. So instead, we do a manual search. We do fall back to
|
||||
// is_never in some places when there is no better alternative.
|
||||
for_each_expr(expr, |ex| {
|
||||
match ex.kind {
|
||||
ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
|
||||
ExprKind::Call(call, _) => {
|
||||
if is_never(cx, ex) || is_never(cx, call) {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
ControlFlow::Continue(Descend::Yes)
|
||||
},
|
||||
ExprKind::MethodCall(..) => {
|
||||
if is_never(cx, ex) {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
ControlFlow::Continue(Descend::Yes)
|
||||
},
|
||||
ExprKind::If(if_expr, if_then, if_else) => {
|
||||
let else_diverges = if_else.map_or(false, |ex| expr_diverges(cx, ex));
|
||||
let diverges = expr_diverges(cx, if_expr) || (else_diverges && expr_diverges(cx, if_then));
|
||||
if diverges {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
ControlFlow::Continue(Descend::No)
|
||||
},
|
||||
ExprKind::Match(match_expr, match_arms, _) => {
|
||||
let diverges = expr_diverges(cx, match_expr)
|
||||
|| match_arms.iter().all(|arm| {
|
||||
let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body()));
|
||||
guard_diverges || expr_diverges(cx, arm.body)
|
||||
});
|
||||
if diverges {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
ControlFlow::Continue(Descend::No)
|
||||
},
|
||||
|
||||
// Don't continue into loops or labeled blocks, as they are breakable,
|
||||
// and we'd have to start checking labels.
|
||||
ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
|
||||
|
||||
// Default: descend
|
||||
_ => ControlFlow::Continue(Descend::Yes),
|
||||
}
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
|
||||
fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
|
||||
// Check whether the pattern contains any bindings, as the
|
||||
// binding might potentially be used in the body.
|
||||
// TODO: only look for *used* bindings.
|
||||
let mut has_bindings = false;
|
||||
pat.each_binding_or_first(&mut |_, _, _, _| has_bindings = true);
|
||||
if has_bindings {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we shouldn't check the types, exit early.
|
||||
if !check_types {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check whether any possibly "unknown" patterns are included,
|
||||
// because users might not know which values some enum has.
|
||||
// Well-known enums are excepted, as we assume people know them.
|
||||
// We do a deep check, to be able to disallow Err(En::Foo(_))
|
||||
// for usage of the En::Foo variant, as we disallow En::Foo(_),
|
||||
// but we allow Err(_).
|
||||
let typeck_results = cx.typeck_results();
|
||||
let mut has_disallowed = false;
|
||||
pat.walk_always(|pat| {
|
||||
// Only do the check if the type is "spelled out" in the pattern
|
||||
if !matches!(
|
||||
pat.kind,
|
||||
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
|
||||
) {
|
||||
return;
|
||||
};
|
||||
let ty = typeck_results.pat_ty(pat);
|
||||
// Option and Result are allowed, everything else isn't.
|
||||
if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {
|
||||
has_disallowed = true;
|
||||
}
|
||||
});
|
||||
!has_disallowed
|
||||
}
|
||||
|
||||
/// Checks if the passed block is a simple identity referring to bindings created by the pattern
|
||||
fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
|
||||
// We support patterns with multiple bindings and tuples, like:
|
||||
// let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
|
||||
let peeled = peel_blocks(expr);
|
||||
let paths = match peeled.kind {
|
||||
ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs,
|
||||
ExprKind::Path(_) => std::slice::from_ref(peeled),
|
||||
_ => return false,
|
||||
};
|
||||
let mut pat_bindings = FxHashSet::default();
|
||||
pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
|
||||
pat_bindings.insert(ident);
|
||||
});
|
||||
if pat_bindings.len() < paths.len() {
|
||||
return false;
|
||||
}
|
||||
for path in paths {
|
||||
if_chain! {
|
||||
if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind;
|
||||
if let [path_seg] = path.segments;
|
||||
then {
|
||||
if !pat_bindings.remove(&path_seg.ident) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
|
||||
pub enum MatchLintBehaviour {
|
||||
AllTypes,
|
||||
WellKnownTypes,
|
||||
Never,
|
||||
}
|
|
@ -119,7 +119,7 @@ fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
|||
/// semicolons, which causes problems when generating a suggestion. Given an
|
||||
/// expression that evaluates to '()' or '!', recursively remove useless braces
|
||||
/// and semi-colons until is suitable for including in the suggestion template
|
||||
fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<Span> {
|
||||
fn reduce_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Span> {
|
||||
if !is_unit_expression(cx, expr) {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
|||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{ExprKind, Local, MatchSource, PatKind, QPath};
|
||||
use rustc_hir::{ByRef, ExprKind, Local, MatchSource, PatKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::INFALLIBLE_DESTRUCTURING_MATCH;
|
||||
|
@ -16,7 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
|
|||
if let PatKind::TupleStruct(
|
||||
QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
|
||||
if args.len() == 1;
|
||||
if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
|
||||
if let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind;
|
||||
let body = peel_blocks(arms[0].body);
|
||||
if path_to_local_id(body, arg);
|
||||
|
||||
|
@ -30,8 +30,9 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
|
|||
Consider using `let`",
|
||||
"try this",
|
||||
format!(
|
||||
"let {}({}) = {};",
|
||||
"let {}({}{}) = {};",
|
||||
snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
|
||||
if binding.0 == ByRef::Yes { "ref " } else { "" },
|
||||
snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, target.span, "..", &mut applicability),
|
||||
),
|
||||
|
|
|
@ -62,7 +62,7 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
|
|||
// <expr>
|
||||
// }
|
||||
// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
|
||||
fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool {
|
||||
fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &Expr<'_>) -> bool {
|
||||
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
|
||||
// there can be not statements in the block as they would be removed when switching to `.filter`
|
||||
if let ExprKind::Call(callee, [arg]) = inner_expr.kind {
|
||||
|
|
|
@ -83,8 +83,8 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
|
|||
|
||||
/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that
|
||||
/// may have a surprising lifetime.
|
||||
fn has_significant_drop_in_scrutinee<'tcx, 'a>(
|
||||
cx: &'a LateContext<'tcx>,
|
||||
fn has_significant_drop_in_scrutinee<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
scrutinee: &'tcx Expr<'tcx>,
|
||||
source: MatchSource,
|
||||
) -> Option<(Vec<FoundSigDrop>, &'static str)> {
|
||||
|
@ -226,7 +226,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
|
|||
/// This will try to set the current suggestion (so it can be moved into the suggestions vec
|
||||
/// later). If `allow_move_and_clone` is false, the suggestion *won't* be set -- this gives us
|
||||
/// an opportunity to look for another type in the chain that will be trivially copyable.
|
||||
/// However, if we are at the the end of the chain, we want to accept whatever is there. (The
|
||||
/// However, if we are at the end of the chain, we want to accept whatever is there. (The
|
||||
/// suggestion won't actually be output, but the diagnostic message will be output, so the user
|
||||
/// can determine the best way to handle the lint.)
|
||||
fn try_setting_current_suggestion(&mut self, expr: &'tcx Expr<'_>, allow_move_and_clone: bool) {
|
||||
|
@ -377,7 +377,7 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn has_significant_drop_in_arms<'tcx, 'a>(cx: &'a LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
|
||||
fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
|
||||
let mut helper = ArmSigDropHelper::new(cx);
|
||||
for arm in arms {
|
||||
helper.visit_expr(arm.body);
|
||||
|
|
|
@ -153,7 +153,7 @@ fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) ->
|
|||
}
|
||||
|
||||
/// Returns `true` if the given type is an enum we know won't be expanded in the future
|
||||
fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool {
|
||||
fn in_candidate_enum(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
// list of candidate `Enum`s we know will never get any more members
|
||||
let candidates = [sym::Cow, sym::Option, sym::Result];
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ use rustc_lint::LateContext;
|
|||
use rustc_lint::Lint;
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
info: &crate::methods::BinaryExprInfo<'_>,
|
||||
chain_methods: &[&str],
|
||||
lint: &'static Lint,
|
||||
|
|
|
@ -4,7 +4,7 @@ use rustc_lint::LateContext;
|
|||
use super::CHARS_LAST_CMP;
|
||||
|
||||
/// Checks for the `CHARS_LAST_CMP` lint.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
|
||||
true
|
||||
} else {
|
||||
|
|
|
@ -4,7 +4,7 @@ use rustc_lint::LateContext;
|
|||
use super::CHARS_LAST_CMP;
|
||||
|
||||
/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
|
||||
true
|
||||
} else {
|
||||
|
|
|
@ -3,6 +3,6 @@ use rustc_lint::LateContext;
|
|||
use super::CHARS_NEXT_CMP;
|
||||
|
||||
/// Checks for the `CHARS_NEXT_CMP` lint.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ use rustc_lint::LateContext;
|
|||
use super::CHARS_NEXT_CMP;
|
||||
|
||||
/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
|
||||
crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
|
|||
// If the parent node's `to` argument is the same as the `to` argument
|
||||
// of the last replace call in the current chain, don't lint as it was already linted
|
||||
if let Some(parent) = get_parent_expr(cx, expr)
|
||||
&& let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
|
||||
&& let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent)
|
||||
&& eq_expr_value(cx, to, current_to)
|
||||
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>(
|
|||
let mut from_args = VecDeque::new();
|
||||
|
||||
let _: Option<()> = for_each_expr(expr, |e| {
|
||||
if let Some(("replace", _, [from, to], _)) = method_call(e) {
|
||||
if let Some(("replace", _, [from, to], _, _)) = method_call(e) {
|
||||
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
|
||||
methods.push_front(e);
|
||||
from_args.push_front(from);
|
||||
|
@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>(
|
|||
.collect();
|
||||
let app = Applicability::MachineApplicable;
|
||||
let earliest_replace_call = replace_methods.methods.front().unwrap();
|
||||
if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
|
||||
if let Some((_, _, [..], span_lo, _)) = method_call(earliest_replace_call) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
COLLAPSIBLE_STR_REPLACE,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_in_test_function;
|
||||
use clippy_utils::is_in_cfg_test;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -18,16 +18,16 @@ pub(super) fn check(
|
|||
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
|
||||
Some((EXPECT_USED, "an Option", "None", ""))
|
||||
Some((EXPECT_USED, "an `Option`", "None", ""))
|
||||
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
|
||||
Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let method = if is_err { "expect_err" } else { "expect" };
|
||||
|
||||
if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
|
||||
if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ pub(super) fn check(
|
|||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
&format!("used `{method}()` on `{kind}` value"),
|
||||
&format!("used `{method}()` on {kind} value"),
|
||||
None,
|
||||
&format!("if this value is {none_prefix}`{none_value}`, it will panic"),
|
||||
);
|
||||
|
|
|
@ -17,7 +17,7 @@ use super::MANUAL_FILTER_MAP;
|
|||
use super::MANUAL_FIND_MAP;
|
||||
use super::OPTION_FILTER_MAP;
|
||||
|
||||
fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
|
||||
fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
|
||||
match &expr.kind {
|
||||
hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
|
||||
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
|
||||
|
@ -46,7 +46,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
|
|||
}
|
||||
}
|
||||
|
||||
fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
|
||||
fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
|
||||
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,8 @@ fn is_filter_some_map_unwrap(
|
|||
|
||||
/// lint use of `filter().map()` or `find().map()` for `Iterators`
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
filter_recv: &hir::Expr<'_>,
|
||||
filter_arg: &hir::Expr<'_>,
|
||||
|
|
|
@ -12,8 +12,8 @@ use rustc_span::symbol::{Symbol, sym};
|
|||
use super::INEFFICIENT_TO_STRING;
|
||||
|
||||
/// Checks for the `INEFFICIENT_TO_STRING` lint
|
||||
pub fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pub fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
method_name: Symbol,
|
||||
receiver: &hir::Expr<'_>,
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc_span::sym;
|
|||
|
||||
use super::ITER_NTH_ZERO;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
|
||||
if_chain! {
|
||||
if is_trait_method(cx, expr, sym::Iterator);
|
||||
if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg);
|
||||
|
|
|
@ -25,7 +25,7 @@ impl IterType {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
|
||||
let item = match recv.kind {
|
||||
ExprKind::Array([]) => None,
|
||||
ExprKind::Array([e]) => Some(e),
|
||||
|
|
|
@ -67,7 +67,7 @@ enum MinMax {
|
|||
Max,
|
||||
}
|
||||
|
||||
fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<MinMax> {
|
||||
fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
|
||||
// `T::max_value()` `T::min_value()` inherent methods
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Call(func, args) = &expr.kind;
|
||||
|
|
|
@ -59,10 +59,8 @@ pub(super) fn check(
|
|||
if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
|
||||
if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat);
|
||||
if is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String);
|
||||
if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
|
||||
if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
|
||||
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||
if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
|
||||
if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
|
||||
if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
|
||||
let ctxt = collect_expr.span.ctxt();
|
||||
|
|
|
@ -15,11 +15,11 @@ use rustc_span::{sym, Span};
|
|||
|
||||
use super::MAP_CLONE;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
e: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
arg: &'tcx hir::Expr<'_>,
|
||||
arg: &hir::Expr<'_>,
|
||||
msrv: Option<RustcVersion>,
|
||||
) {
|
||||
if_chain! {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
|
@ -11,18 +10,10 @@ use rustc_span::symbol::sym;
|
|||
|
||||
use super::MAP_COLLECT_RESULT_UNIT;
|
||||
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
iter: &hir::Expr<'_>,
|
||||
map_fn: &hir::Expr<'_>,
|
||||
collect_recv: &hir::Expr<'_>,
|
||||
) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) {
|
||||
// return of collect `Result<(),_>`
|
||||
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
|
||||
if_chain! {
|
||||
// called on Iterator
|
||||
if is_trait_method(cx, collect_recv, sym::Iterator);
|
||||
// return of collect `Result<(),_>`
|
||||
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
|
||||
if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result);
|
||||
if let ty::Adt(_, substs) = collect_ret_ty.kind();
|
||||
if let Some(result_t) = substs.types().next();
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_span::sym;
|
|||
|
||||
use super::MAP_ERR_IGNORE;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) {
|
||||
pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
|
||||
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
|
||||
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
|
||||
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result)
|
||||
|
|
|
@ -54,6 +54,7 @@ mod map_flatten;
|
|||
mod map_identity;
|
||||
mod map_unwrap_or;
|
||||
mod mut_mutex_lock;
|
||||
mod needless_collect;
|
||||
mod needless_option_as_deref;
|
||||
mod needless_option_take;
|
||||
mod no_effect_replace;
|
||||
|
@ -69,6 +70,8 @@ mod path_buf_push_overwrite;
|
|||
mod range_zip_with_len;
|
||||
mod repeat_once;
|
||||
mod search_is_some;
|
||||
mod seek_from_current;
|
||||
mod seek_to_start_instead_of_rewind;
|
||||
mod single_char_add_str;
|
||||
mod single_char_insert_string;
|
||||
mod single_char_pattern;
|
||||
|
@ -101,12 +104,11 @@ mod zst_offset;
|
|||
use bind_instead_of_map::BindInsteadOfMap;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
|
||||
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
|
||||
use rustc_hir::{Expr, ExprKind, TraitItem, TraitItemKind};
|
||||
use rustc_hir_analysis::hir_ty_to_ty;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
@ -156,9 +158,9 @@ declare_clippy_lint! {
|
|||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
|
||||
/// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");
|
||||
/// ```
|
||||
#[clippy::version = "1.64.0"]
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub COLLAPSIBLE_STR_REPLACE,
|
||||
perf,
|
||||
"collapse consecutive calls to str::replace (2 or more) into a single call"
|
||||
|
@ -829,32 +831,30 @@ declare_clippy_lint! {
|
|||
/// etc. instead.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The function will always be called and potentially
|
||||
/// allocate an object acting as the default.
|
||||
/// The function will always be called. This is only bad if it allocates or
|
||||
/// does some non-trivial amount of work.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// If the function has side-effects, not calling it will
|
||||
/// change the semantic of the program, but you shouldn't rely on that anyway.
|
||||
/// If the function has side-effects, not calling it will change the
|
||||
/// semantic of the program, but you shouldn't rely on that.
|
||||
///
|
||||
/// The lint also cannot figure out whether the function you call is
|
||||
/// actually expensive to call or not.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let foo = Some(String::new());
|
||||
/// foo.unwrap_or(String::new());
|
||||
/// foo.unwrap_or(String::from("empty"));
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # let foo = Some(String::new());
|
||||
/// foo.unwrap_or_else(String::new);
|
||||
///
|
||||
/// // or
|
||||
///
|
||||
/// # let foo = Some(String::new());
|
||||
/// foo.unwrap_or_default();
|
||||
/// foo.unwrap_or_else(|| String::from("empty"));
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub OR_FUN_CALL,
|
||||
perf,
|
||||
nursery,
|
||||
"using any `*or` method with a function call, which suggests `*or_else`"
|
||||
}
|
||||
|
||||
|
@ -1728,7 +1728,7 @@ declare_clippy_lint! {
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
|
||||
/// Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str).
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Readability, this can be written more concisely as
|
||||
|
@ -2094,8 +2094,7 @@ declare_clippy_lint! {
|
|||
/// let s = "Hello world!";
|
||||
/// let cow = Cow::Borrowed(s);
|
||||
///
|
||||
/// let data = cow.into_owned();
|
||||
/// assert!(matches!(data, String))
|
||||
/// let _data: String = cow.into_owned();
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub SUSPICIOUS_TO_OWNED,
|
||||
|
@ -2426,7 +2425,7 @@ declare_clippy_lint! {
|
|||
/// ### Known problems
|
||||
///
|
||||
/// The type of the resulting iterator might become incompatible with its usage
|
||||
#[clippy::version = "1.64.0"]
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub ITER_ON_SINGLE_ITEMS,
|
||||
nursery,
|
||||
"Iterator for array of length 1"
|
||||
|
@ -2458,7 +2457,7 @@ declare_clippy_lint! {
|
|||
/// ### Known problems
|
||||
///
|
||||
/// The type of the resulting iterator might become incompatible with its usage
|
||||
#[clippy::version = "1.64.0"]
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub ITER_ON_EMPTY_COLLECTIONS,
|
||||
nursery,
|
||||
"Iterator for empty array"
|
||||
|
@ -3066,6 +3065,102 @@ declare_clippy_lint! {
|
|||
"iterating on map using `iter` when `keys` or `values` would do"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Checks an argument of `seek` method of `Seek` trait
|
||||
/// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Readability. Use dedicated method.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::io::{self, Write, Seek, SeekFrom};
|
||||
///
|
||||
/// fn main() -> io::Result<()> {
|
||||
/// let mut f = File::create("foo.txt")?;
|
||||
/// f.write_all(b"Hello")?;
|
||||
/// eprintln!("Written {} bytes", f.seek(SeekFrom::Current(0))?);
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust,no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::io::{self, Write, Seek, SeekFrom};
|
||||
///
|
||||
/// fn main() -> io::Result<()> {
|
||||
/// let mut f = File::create("foo.txt")?;
|
||||
/// f.write_all(b"Hello")?;
|
||||
/// eprintln!("Written {} bytes", f.stream_position()?);
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub SEEK_FROM_CURRENT,
|
||||
complexity,
|
||||
"use dedicated method for seek from current position"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Checks for jumps to the start of a stream that implements `Seek`
|
||||
/// and uses the `seek` method providing `Start` as parameter.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Readability. There is a specific method that was implemented for
|
||||
/// this exact scenario.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::io;
|
||||
/// fn foo<T: io::Seek>(t: &mut T) {
|
||||
/// t.seek(io::SeekFrom::Start(0));
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::io;
|
||||
/// fn foo<T: io::Seek>(t: &mut T) {
|
||||
/// t.rewind();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub SEEK_TO_START_INSTEAD_OF_REWIND,
|
||||
complexity,
|
||||
"jumping to the start of stream using `seek` method"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for functions collecting an iterator when collect
|
||||
/// is not needed.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// `collect` causes the allocation of a new data structure,
|
||||
/// when this allocation may not be needed.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let iterator = vec![1].into_iter();
|
||||
/// let len = iterator.clone().collect::<Vec<_>>().len();
|
||||
/// // should be
|
||||
/// let len = iterator.count();
|
||||
/// ```
|
||||
#[clippy::version = "1.30.0"]
|
||||
pub NEEDLESS_COLLECT,
|
||||
nursery,
|
||||
"collecting an iterator when collect is not needed"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Option<RustcVersion>,
|
||||
|
@ -3190,16 +3285,19 @@ impl_lint_pass!(Methods => [
|
|||
VEC_RESIZE_TO_ZERO,
|
||||
VERBOSE_FILE_READS,
|
||||
ITER_KV_MAP,
|
||||
SEEK_FROM_CURRENT,
|
||||
SEEK_TO_START_INSTEAD_OF_REWIND,
|
||||
NEEDLESS_COLLECT,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
fn method_call<'tcx>(
|
||||
recv: &'tcx hir::Expr<'tcx>,
|
||||
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
|
||||
if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
|
||||
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
|
||||
if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
|
||||
if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
|
||||
let name = path.ident.name.as_str();
|
||||
return Some((name, receiver, args, path.ident.span));
|
||||
return Some((name, receiver, args, path.ident.span, call_span));
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -3316,36 +3414,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
|
||||
let ret_ty = return_ty(cx, impl_item.hir_id());
|
||||
|
||||
// walk the return type and check for Self (this does not check associated types)
|
||||
if let Some(self_adt) = self_ty.ty_adt_def() {
|
||||
if contains_adt_constructor(ret_ty, self_adt) {
|
||||
return;
|
||||
}
|
||||
} else if ret_ty.contains(self_ty) {
|
||||
if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if return type is impl trait, check the associated types
|
||||
if let ty::Opaque(def_id, _) = *ret_ty.kind() {
|
||||
// one of the associated types must be Self
|
||||
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
|
||||
let assoc_ty = match projection_predicate.term.unpack() {
|
||||
ty::TermKind::Ty(ty) => ty,
|
||||
ty::TermKind::Const(_c) => continue,
|
||||
};
|
||||
// walk the associated type and check for Self
|
||||
if let Some(self_adt) = self_ty.ty_adt_def() {
|
||||
if contains_adt_constructor(assoc_ty, self_adt) {
|
||||
return;
|
||||
}
|
||||
} else if assoc_ty.contains(self_ty) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if name == "new" && ret_ty != self_ty {
|
||||
span_lint(
|
||||
cx,
|
||||
|
@ -3411,7 +3483,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
impl Methods {
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let Some((name, recv, args, span)) = method_call(expr) {
|
||||
if let Some((name, recv, args, span, call_span)) = method_call(expr) {
|
||||
match (name, args) {
|
||||
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
|
||||
zst_offset::check(cx, expr, recv);
|
||||
|
@ -3430,28 +3502,31 @@ impl Methods {
|
|||
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
|
||||
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
|
||||
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
|
||||
("collect", []) => match method_call(recv) {
|
||||
Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
|
||||
iter_cloned_collect::check(cx, name, expr, recv2);
|
||||
},
|
||||
Some(("map", m_recv, [m_arg], _)) => {
|
||||
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
|
||||
},
|
||||
Some(("take", take_self_arg, [take_arg], _)) => {
|
||||
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
|
||||
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
|
||||
needless_collect::check(cx, span, expr, recv, call_span);
|
||||
match method_call(recv) {
|
||||
Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
|
||||
iter_cloned_collect::check(cx, name, expr, recv2);
|
||||
},
|
||||
Some(("map", m_recv, [m_arg], _, _)) => {
|
||||
map_collect_result_unit::check(cx, expr, m_recv, m_arg);
|
||||
},
|
||||
Some(("take", take_self_arg, [take_arg], _, _)) => {
|
||||
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
|
||||
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
|
||||
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
|
||||
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
|
||||
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
|
||||
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
|
||||
iter_count::check(cx, expr, recv2, name2);
|
||||
},
|
||||
Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
|
||||
Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
|
||||
Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
|
||||
Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
|
||||
Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
|
||||
Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
|
||||
_ => {},
|
||||
},
|
||||
("drain", [arg]) => {
|
||||
|
@ -3463,8 +3538,8 @@ impl Methods {
|
|||
}
|
||||
},
|
||||
("expect", [_]) => match method_call(recv) {
|
||||
Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
|
||||
Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
|
||||
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
|
||||
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
|
||||
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
|
||||
},
|
||||
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
|
||||
|
@ -3484,13 +3559,13 @@ impl Methods {
|
|||
flat_map_option::check(cx, expr, arg, span);
|
||||
},
|
||||
("flatten", []) => match method_call(recv) {
|
||||
Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
|
||||
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
|
||||
Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
|
||||
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
|
||||
_ => {},
|
||||
},
|
||||
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
|
||||
("for_each", [_]) => {
|
||||
if let Some(("inspect", _, [_], span2)) = method_call(recv) {
|
||||
if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
|
||||
inspect_for_each::check(cx, expr, span2);
|
||||
}
|
||||
},
|
||||
|
@ -3510,12 +3585,12 @@ impl Methods {
|
|||
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
|
||||
},
|
||||
("join", [join_arg]) => {
|
||||
if let Some(("collect", _, _, span)) = method_call(recv) {
|
||||
if let Some(("collect", _, _, span, _)) = method_call(recv) {
|
||||
unnecessary_join::check(cx, expr, recv, join_arg, span);
|
||||
}
|
||||
},
|
||||
("last", []) | ("skip", [_]) => {
|
||||
if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
|
@ -3527,13 +3602,13 @@ impl Methods {
|
|||
(name @ ("map" | "map_err"), [m_arg]) => {
|
||||
if name == "map" {
|
||||
map_clone::check(cx, expr, recv, m_arg, self.msrv);
|
||||
if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _)) = method_call(recv) {
|
||||
if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
|
||||
iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
|
||||
}
|
||||
} else {
|
||||
map_err_ignore::check(cx, expr, m_arg);
|
||||
}
|
||||
if let Some((name, recv2, args, span2)) = method_call(recv) {
|
||||
if let Some((name, recv2, args, span2,_)) = method_call(recv) {
|
||||
match (name, args) {
|
||||
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
|
||||
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
|
||||
|
@ -3553,7 +3628,7 @@ impl Methods {
|
|||
manual_ok_or::check(cx, expr, recv, def, map);
|
||||
},
|
||||
("next", []) => {
|
||||
if let Some((name2, recv2, args2, _)) = method_call(recv) {
|
||||
if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
|
||||
match (name2, args2) {
|
||||
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
||||
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
|
||||
|
@ -3566,10 +3641,10 @@ impl Methods {
|
|||
}
|
||||
},
|
||||
("nth", [n_arg]) => match method_call(recv) {
|
||||
Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
|
||||
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
||||
Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
|
||||
Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
|
||||
Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
|
||||
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
||||
Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
|
||||
Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
|
||||
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
|
||||
},
|
||||
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
|
||||
|
@ -3604,6 +3679,14 @@ impl Methods {
|
|||
("resize", [count_arg, default_arg]) => {
|
||||
vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
|
||||
},
|
||||
("seek", [arg]) => {
|
||||
if meets_msrv(self.msrv, msrvs::SEEK_FROM_CURRENT) {
|
||||
seek_from_current::check(cx, expr, recv, arg);
|
||||
}
|
||||
if meets_msrv(self.msrv, msrvs::SEEK_REWIND) {
|
||||
seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
|
||||
}
|
||||
},
|
||||
("sort", []) => {
|
||||
stable_sort_primitive::check(cx, expr, recv);
|
||||
},
|
||||
|
@ -3626,7 +3709,7 @@ impl Methods {
|
|||
},
|
||||
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
|
||||
("take", [_arg]) => {
|
||||
if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
|
@ -3649,13 +3732,13 @@ impl Methods {
|
|||
},
|
||||
("unwrap", []) => {
|
||||
match method_call(recv) {
|
||||
Some(("get", recv, [get_arg], _)) => {
|
||||
Some(("get", recv, [get_arg], _, _)) => {
|
||||
get_unwrap::check(cx, expr, recv, get_arg, false);
|
||||
},
|
||||
Some(("get_mut", recv, [get_arg], _)) => {
|
||||
Some(("get_mut", recv, [get_arg], _, _)) => {
|
||||
get_unwrap::check(cx, expr, recv, get_arg, true);
|
||||
},
|
||||
Some(("or", recv, [or_arg], or_span)) => {
|
||||
Some(("or", recv, [or_arg], or_span, _)) => {
|
||||
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
|
||||
},
|
||||
_ => {},
|
||||
|
@ -3664,19 +3747,19 @@ impl Methods {
|
|||
},
|
||||
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
|
||||
("unwrap_or", [u_arg]) => match method_call(recv) {
|
||||
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
|
||||
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
|
||||
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
|
||||
},
|
||||
Some(("map", m_recv, [m_arg], span)) => {
|
||||
Some(("map", m_recv, [m_arg], span, _)) => {
|
||||
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
|
||||
},
|
||||
Some(("then_some", t_recv, [t_arg], _)) => {
|
||||
Some(("then_some", t_recv, [t_arg], _, _)) => {
|
||||
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
("unwrap_or_else", [u_arg]) => match method_call(recv) {
|
||||
Some(("map", recv, [map_arg], _))
|
||||
Some(("map", recv, [map_arg], _, _))
|
||||
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
|
||||
_ => {
|
||||
unwrap_or_else_default::check(cx, expr, recv, u_arg);
|
||||
|
@ -3697,7 +3780,7 @@ impl Methods {
|
|||
}
|
||||
|
||||
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
|
||||
if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
|
||||
if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) = method_call(recv) {
|
||||
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
|
||||
}
|
||||
}
|
||||
|
@ -3906,14 +3989,6 @@ impl OutType {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_bool(ty: &hir::Ty<'_>) -> bool {
|
||||
if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
|
||||
matches!(path.res, Res::PrimTy(PrimTy::Bool))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
|
||||
expected.constness == actual.constness
|
||||
&& expected.unsafety == actual.unsafety
|
||||
|
|
|
@ -3,94 +3,99 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
|||
use clippy_utils::higher;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind};
|
||||
use if_chain::if_chain;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
|
||||
use clippy_utils::{
|
||||
can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id,
|
||||
CaptureKind,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind};
|
||||
use rustc_hir::{
|
||||
BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
|
||||
const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
|
||||
|
||||
pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
|
||||
check_needless_collect_direct_usage(expr, cx);
|
||||
check_needless_collect_indirect_usage(expr, cx);
|
||||
}
|
||||
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
|
||||
if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
|
||||
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
|
||||
then {
|
||||
let ty = cx.typeck_results().expr_ty(receiver);
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
let is_empty_sugg = "next().is_none()".to_string();
|
||||
let method_name = method.ident.name.as_str();
|
||||
let sugg = if is_type_diagnostic_item(cx, ty, sym::Vec) ||
|
||||
is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
|
||||
is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
|
||||
is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
|
||||
match method_name {
|
||||
"len" => "count()".to_string(),
|
||||
"is_empty" => is_empty_sugg,
|
||||
"contains" => {
|
||||
let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
|
||||
let (arg, pred) = contains_arg
|
||||
.strip_prefix('&')
|
||||
.map_or(("&x", &*contains_arg), |s| ("x", s));
|
||||
format!("any(|{arg}| x == {pred})")
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
|
||||
is_type_diagnostic_item(cx, ty, sym::HashMap) {
|
||||
match method_name {
|
||||
"is_empty" => is_empty_sugg,
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_COLLECT,
|
||||
chain_method.ident.span.with_hi(expr.span.hi()),
|
||||
NEEDLESS_COLLECT_MSG,
|
||||
"replace with",
|
||||
sugg,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
name_span: Span,
|
||||
collect_expr: &'tcx Expr<'_>,
|
||||
iter_expr: &'tcx Expr<'tcx>,
|
||||
call_span: Span,
|
||||
) {
|
||||
if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) {
|
||||
match parent {
|
||||
Node::Expr(parent) => {
|
||||
if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let name = name.ident.as_str();
|
||||
let collect_ty = cx.typeck_results().expr_ty(collect_expr);
|
||||
|
||||
fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
|
||||
if let ExprKind::Block(block, _) = expr.kind {
|
||||
for stmt in block.stmts {
|
||||
if_chain! {
|
||||
if let StmtKind::Local(local) = stmt.kind;
|
||||
if let PatKind::Binding(_, id, ..) = local.pat.kind;
|
||||
if let Some(init_expr) = local.init;
|
||||
if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
|
||||
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
|
||||
let ty = cx.typeck_results().expr_ty(init_expr);
|
||||
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
|
||||
is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
|
||||
is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
|
||||
is_type_diagnostic_item(cx, ty, sym::LinkedList);
|
||||
let iter_ty = cx.typeck_results().expr_ty(iter_source);
|
||||
if let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty));
|
||||
if let [iter_call] = &*iter_calls;
|
||||
then {
|
||||
let sugg: String = match name {
|
||||
"len" => {
|
||||
if let Some(adt) = collect_ty.ty_adt_def()
|
||||
&& matches!(
|
||||
cx.tcx.get_diagnostic_name(adt.did()),
|
||||
Some(sym::Vec | sym::VecDeque | sym::LinkedList | sym::BinaryHeap)
|
||||
)
|
||||
{
|
||||
"count()".into()
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
"is_empty"
|
||||
if is_is_empty_sig(cx, parent.hir_id)
|
||||
&& iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) =>
|
||||
{
|
||||
"next().is_none()".into()
|
||||
},
|
||||
"contains" => {
|
||||
if is_contains_sig(cx, parent.hir_id, iter_expr)
|
||||
&& let Some(arg) = args.first()
|
||||
{
|
||||
let (span, prefix) = if let ExprKind::AddrOf(_, _, arg) = arg.kind {
|
||||
(arg.span, "")
|
||||
} else {
|
||||
(arg.span, "*")
|
||||
};
|
||||
let snip = snippet_with_applicability(cx, span, "??", &mut app);
|
||||
format!("any(|x| x == {prefix}{snip})")
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_COLLECT,
|
||||
call_span.with_hi(parent.span.hi()),
|
||||
NEEDLESS_COLLECT_MSG,
|
||||
"replace with",
|
||||
sugg,
|
||||
app,
|
||||
);
|
||||
}
|
||||
},
|
||||
Node::Local(l) => {
|
||||
if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None)
|
||||
= l.pat.kind
|
||||
&& let ty = cx.typeck_results().expr_ty(collect_expr)
|
||||
&& [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter()
|
||||
.any(|item| is_type_diagnostic_item(cx, ty, item))
|
||||
&& let iter_ty = cx.typeck_results().expr_ty(iter_expr)
|
||||
&& let Some(block) = get_enclosing_block(cx, l.hir_id)
|
||||
&& let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty))
|
||||
&& let [iter_call] = &*iter_calls
|
||||
{
|
||||
let mut used_count_visitor = UsedCountVisitor {
|
||||
cx,
|
||||
id,
|
||||
|
@ -102,20 +107,20 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
|
|||
}
|
||||
|
||||
// Suggest replacing iter_call with iter_replacement, and removing stmt
|
||||
let mut span = MultiSpan::from_span(method_name.ident.span);
|
||||
let mut span = MultiSpan::from_span(name_span);
|
||||
span.push_span_label(iter_call.span, "the iterator could be used here instead");
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
super::NEEDLESS_COLLECT,
|
||||
init_expr.hir_id,
|
||||
collect_expr.hir_id,
|
||||
span,
|
||||
NEEDLESS_COLLECT_MSG,
|
||||
|diag| {
|
||||
let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
|
||||
let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx));
|
||||
diag.multipart_suggestion(
|
||||
iter_call.get_suggestion_text(),
|
||||
vec![
|
||||
(stmt.span, String::new()),
|
||||
(l.span, String::new()),
|
||||
(iter_call.span, iter_replacement)
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
|
@ -123,11 +128,61 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
|
|||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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();
|
||||
sig.inputs().len() == 1 && sig.output().is_bool()
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if `<iter_ty as Iterator>::Item` is the same as `<collect_ty as IntoIter>::Item`
|
||||
fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool {
|
||||
let item = Symbol::intern("Item");
|
||||
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
||||
&& let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
|
||||
&& let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, item, [iter_ty])
|
||||
&& let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
|
||||
&& let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
|
||||
cx.param_env,
|
||||
cx.tcx.mk_projection(into_iter_item_proj.item_def_id, into_iter_item_proj.substs)
|
||||
)
|
||||
{
|
||||
iter_item_ty == into_iter_item_ty
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given method call matches the expected signature of
|
||||
/// `([&[mut]] self, &<iter_ty as Iterator>::Item) -> bool`
|
||||
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)
|
||||
&& 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()
|
||||
&& let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
||||
&& let Some(iter_item) = cx.tcx
|
||||
.associated_items(iter_trait)
|
||||
.find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
|
||||
&& let substs = cx.tcx.mk_substs([GenericArg::from(typeck.expr_ty_adjusted(iter_expr))].into_iter())
|
||||
&& let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs)
|
||||
&& let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
|
||||
{
|
||||
item_ty == EarlyBinder(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct IterFunction {
|
||||
func: IterFunctionKind,
|
||||
span: Span,
|
|
@ -13,8 +13,8 @@ use rustc_span::sym;
|
|||
use super::OPTION_AS_REF_DEREF;
|
||||
|
||||
/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
as_ref_recv: &hir::Expr<'_>,
|
||||
map_arg: &hir::Expr<'_>,
|
||||
|
|
|
@ -83,6 +83,8 @@ pub(super) fn check<'tcx>(
|
|||
method_span: Span,
|
||||
self_expr: &hir::Expr<'_>,
|
||||
arg: &'tcx hir::Expr<'_>,
|
||||
// `Some` if fn has second argument
|
||||
second_arg: Option<&hir::Expr<'_>>,
|
||||
span: Span,
|
||||
// None if lambda is required
|
||||
fun_span: Option<Span>,
|
||||
|
@ -109,30 +111,40 @@ pub(super) fn check<'tcx>(
|
|||
if poss.contains(&name);
|
||||
|
||||
then {
|
||||
let macro_expanded_snipped;
|
||||
let sugg: Cow<'_, str> = {
|
||||
let sugg = {
|
||||
let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
|
||||
(false, Some(fun_span)) => (fun_span, false),
|
||||
_ => (arg.span, true),
|
||||
};
|
||||
let snippet = {
|
||||
let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
|
||||
if not_macro_argument_snippet == "vec![]" {
|
||||
macro_expanded_snipped = snippet(cx, snippet_span, "..");
|
||||
|
||||
let format_span = |span: Span| {
|
||||
let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, "..");
|
||||
let snip = if not_macro_argument_snippet == "vec![]" {
|
||||
let macro_expanded_snipped = snippet(cx, snippet_span, "..");
|
||||
match macro_expanded_snipped.strip_prefix("$crate::vec::") {
|
||||
Some(stripped) => Cow::from(stripped),
|
||||
Some(stripped) => Cow::Owned(stripped.to_owned()),
|
||||
None => macro_expanded_snipped,
|
||||
}
|
||||
} else {
|
||||
not_macro_argument_snippet
|
||||
}
|
||||
};
|
||||
|
||||
snip.to_string()
|
||||
};
|
||||
|
||||
if use_lambda {
|
||||
let snip = format_span(snippet_span);
|
||||
let snip = if use_lambda {
|
||||
let l_arg = if fn_has_arguments { "_" } else { "" };
|
||||
format!("|{l_arg}| {snippet}").into()
|
||||
format!("|{l_arg}| {snip}")
|
||||
} else {
|
||||
snippet
|
||||
snip
|
||||
};
|
||||
|
||||
if let Some(f) = second_arg {
|
||||
let f = format_span(f.span);
|
||||
format!("{snip}, {f}")
|
||||
} else {
|
||||
snip
|
||||
}
|
||||
};
|
||||
let span_replace_word = method_span.with_hi(span.hi());
|
||||
|
@ -149,8 +161,8 @@ pub(super) fn check<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
if let [arg] = args {
|
||||
let inner_arg = if let hir::ExprKind::Block(
|
||||
let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| {
|
||||
if let hir::ExprKind::Block(
|
||||
hir::Block {
|
||||
stmts: [],
|
||||
expr: Some(expr),
|
||||
|
@ -162,19 +174,32 @@ pub(super) fn check<'tcx>(
|
|||
expr
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
if let [arg] = args {
|
||||
let inner_arg = extract_inner_arg(arg);
|
||||
match inner_arg.kind {
|
||||
hir::ExprKind::Call(fun, or_args) => {
|
||||
let or_has_args = !or_args.is_empty();
|
||||
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
|
||||
let fun_span = if or_has_args { None } else { Some(fun.span) };
|
||||
check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
|
||||
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
|
||||
}
|
||||
},
|
||||
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
|
||||
check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
|
||||
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// `map_or` takes two arguments
|
||||
if let [arg, lambda] = args {
|
||||
let inner_arg = extract_inner_arg(arg);
|
||||
if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind {
|
||||
let fun_span = if or_args.is_empty() { Some(fun.span) } else { None };
|
||||
check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
48
clippy_lints/src/methods/seek_from_current.rs
Normal file
48
clippy_lints/src/methods/seek_from_current.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use rustc_ast::ast::{LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, paths, source::snippet_with_applicability,
|
||||
ty::implements_trait,
|
||||
};
|
||||
|
||||
use super::SEEK_FROM_CURRENT;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
|
||||
let ty = cx.typeck_results().expr_ty(recv);
|
||||
|
||||
if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) {
|
||||
if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
SEEK_FROM_CURRENT,
|
||||
expr.span,
|
||||
"using `SeekFrom::Current` to start from current position",
|
||||
"replace with",
|
||||
format!("{snip}.stream_position()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
|
||||
if let ExprKind::Call(f, args) = expr.kind &&
|
||||
let ExprKind::Path(ref path) = f.kind &&
|
||||
let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() &&
|
||||
match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
|
||||
// check if argument of `SeekFrom::Current` is `0`
|
||||
if args.len() == 1 &&
|
||||
let ExprKind::Lit(ref lit) = args[0].kind &&
|
||||
let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
45
clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
Normal file
45
clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_trait_def_id, match_def_path, paths};
|
||||
use rustc_ast::ast::{LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::SEEK_TO_START_INSTEAD_OF_REWIND;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
recv: &'tcx Expr<'_>,
|
||||
arg: &'tcx Expr<'_>,
|
||||
name_span: Span,
|
||||
) {
|
||||
// Get receiver type
|
||||
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
|
||||
implements_trait(cx, ty, seek_trait_id, &[]) &&
|
||||
let ExprKind::Call(func, args1) = arg.kind &&
|
||||
let ExprKind::Path(ref path) = func.kind &&
|
||||
let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
|
||||
match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
|
||||
args1.len() == 1 &&
|
||||
let ExprKind::Lit(ref lit) = args1[0].kind &&
|
||||
let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
|
||||
{
|
||||
let method_call_span = expr.span.with_lo(name_span.lo());
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SEEK_TO_START_INSTEAD_OF_REWIND,
|
||||
method_call_span,
|
||||
"used `seek` to go to the start of the stream",
|
||||
|diag| {
|
||||
let app = Applicability::MachineApplicable;
|
||||
|
||||
diag.span_suggestion(method_call_span, "replace with", "rewind()", app);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
|
|||
let target = &arglists[0].0;
|
||||
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
|
||||
let ref_str = if *self_ty.kind() == ty::Str {
|
||||
""
|
||||
if matches!(target.kind, hir::ExprKind::Index(..)) {
|
||||
"&"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
} else if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
|
||||
"&"
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_span::sym;
|
|||
|
||||
use super::SUSPICIOUS_MAP;
|
||||
|
||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
|
||||
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);
|
||||
|
|
|
@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(
|
|||
cx,
|
||||
UNNECESSARY_JOIN,
|
||||
span.with_hi(expr.span.hi()),
|
||||
r#"called `.collect<Vec<String>>().join("")` on an iterator"#,
|
||||
r#"called `.collect::<Vec<String>>().join("")` on an iterator"#,
|
||||
"try using",
|
||||
"collect::<String>()".to_owned(),
|
||||
applicability,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_in_test_function, is_lint_allowed};
|
||||
use clippy_utils::{is_in_cfg_test, is_lint_allowed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
@ -18,16 +18,16 @@ pub(super) fn check(
|
|||
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
|
||||
Some((UNWRAP_USED, "an Option", "None", ""))
|
||||
Some((UNWRAP_USED, "an `Option`", "None", ""))
|
||||
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
|
||||
Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let method_suffix = if is_err { "_err" } else { "" };
|
||||
|
||||
if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
|
||||
if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ pub(super) fn check(
|
|||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
&format!("used `unwrap{method_suffix}()` on `{kind}` value"),
|
||||
&format!("used `unwrap{method_suffix}()` on {kind} value"),
|
||||
None,
|
||||
&help,
|
||||
);
|
||||
|
|
|
@ -59,7 +59,7 @@ impl LateLintPass<'_> for ImportRename {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for Rename { path, rename } in &self.conf_renames {
|
||||
let segs = path.split("::").collect::<Vec<_>>();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.renames.insert(id, Symbol::intern(rename));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ enum StopEarly {
|
|||
Stop,
|
||||
}
|
||||
|
||||
fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
|
||||
fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
|
||||
if expr.hir_id == vis.last_expr.hir_id {
|
||||
return StopEarly::KeepGoing;
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -
|
|||
StopEarly::KeepGoing
|
||||
}
|
||||
|
||||
fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
|
||||
fn check_stmt<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
|
||||
match stmt.kind {
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
|
||||
// If the declaration is of a local variable, check its initializer
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::trait_ref_of_method;
|
||||
use clippy_utils::{def_path_def_ids, trait_ref_of_method};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TypeVisitable;
|
||||
use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::sym;
|
||||
use std::iter;
|
||||
|
@ -78,26 +79,44 @@ declare_clippy_lint! {
|
|||
"Check for mutable `Map`/`Set` key type"
|
||||
}
|
||||
|
||||
declare_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
|
||||
#[derive(Clone)]
|
||||
pub struct MutableKeyType {
|
||||
ignore_interior_mutability: Vec<String>,
|
||||
ignore_mut_def_ids: FxHashSet<hir::def_id::DefId>,
|
||||
}
|
||||
|
||||
impl_lint_pass!(MutableKeyType => [ MUTABLE_KEY_TYPE ]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
|
||||
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
||||
self.ignore_mut_def_ids.clear();
|
||||
let mut path = Vec::new();
|
||||
for ty in &self.ignore_interior_mutability {
|
||||
path.extend(ty.split("::"));
|
||||
for id in def_path_def_ids(cx, &path[..]) {
|
||||
self.ignore_mut_def_ids.insert(id);
|
||||
}
|
||||
path.clear();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
|
||||
check_sig(cx, item.hir_id(), sig.decl);
|
||||
self.check_sig(cx, item.hir_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() {
|
||||
check_sig(cx, item.hir_id(), sig.decl);
|
||||
self.check_sig(cx, item.hir_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 {
|
||||
check_sig(cx, item.hir_id(), sig.decl);
|
||||
self.check_sig(cx, item.hir_id(), sig.decl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,73 +124,81 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
|
|||
if let hir::PatKind::Wild = local.pat.kind {
|
||||
return;
|
||||
}
|
||||
check_ty(cx, local.span, cx.typeck_results().pat_ty(local.pat));
|
||||
self.check_ty_(cx, local.span, cx.typeck_results().pat_ty(local.pat));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sig<'tcx>(cx: &LateContext<'tcx>, 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);
|
||||
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
|
||||
check_ty(cx, hir_ty.span, *ty);
|
||||
}
|
||||
check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
|
||||
}
|
||||
|
||||
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
|
||||
// generics (because the compiler cannot ensure immutability for unknown types).
|
||||
fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
|
||||
let ty = ty.peel_refs();
|
||||
if let Adt(def, substs) = ty.kind() {
|
||||
let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
|
||||
.iter()
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
|
||||
if is_keyed_type && is_interior_mutable_type(cx, substs.type_at(0), span) {
|
||||
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
|
||||
impl MutableKeyType {
|
||||
pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
|
||||
Self {
|
||||
ignore_interior_mutability,
|
||||
ignore_mut_def_ids: FxHashSet::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines if a type contains interior mutability which would affect its implementation of
|
||||
/// [`Hash`] or [`Ord`].
|
||||
fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
match *ty.kind() {
|
||||
Ref(_, inner_ty, mutbl) => {
|
||||
mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span)
|
||||
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);
|
||||
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
|
||||
self.check_ty_(cx, hir_ty.span, *ty);
|
||||
}
|
||||
Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
|
||||
Array(inner_ty, size) => {
|
||||
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
||||
&& is_interior_mutable_type(cx, inner_ty, span)
|
||||
}
|
||||
Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
|
||||
Adt(def, substs) => {
|
||||
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
|
||||
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
|
||||
// because they have no impl for `Hash` or `Ord`.
|
||||
let is_std_collection = [
|
||||
sym::Option,
|
||||
sym::Result,
|
||||
sym::LinkedList,
|
||||
sym::Vec,
|
||||
sym::VecDeque,
|
||||
sym::BTreeMap,
|
||||
sym::BTreeSet,
|
||||
sym::Rc,
|
||||
sym::Arc,
|
||||
]
|
||||
.iter()
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
|
||||
let is_box = Some(def.did()) == cx.tcx.lang_items().owned_box();
|
||||
if is_std_collection || is_box {
|
||||
// The type is mutable if any of its type parameters are
|
||||
substs.types().any(|ty| is_interior_mutable_type(cx, ty, span))
|
||||
} else {
|
||||
!ty.has_escaping_bound_vars()
|
||||
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
|
||||
&& !ty.is_freeze(cx.tcx, cx.param_env)
|
||||
self.check_ty_(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
|
||||
}
|
||||
|
||||
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
|
||||
// generics (because the compiler cannot ensure immutability for unknown types).
|
||||
fn check_ty_<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
|
||||
let ty = ty.peel_refs();
|
||||
if let Adt(def, substs) = ty.kind() {
|
||||
let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
|
||||
.iter()
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
|
||||
if is_keyed_type && self.is_interior_mutable_type(cx, substs.type_at(0)) {
|
||||
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
||||
/// Determines if a type contains interior mutability which would affect its implementation of
|
||||
/// [`Hash`] or [`Ord`].
|
||||
fn is_interior_mutable_type<'tcx>(&self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
match *ty.kind() {
|
||||
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
|
||||
Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
|
||||
Array(inner_ty, size) => {
|
||||
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
||||
&& self.is_interior_mutable_type(cx, inner_ty)
|
||||
},
|
||||
Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
|
||||
Adt(def, substs) => {
|
||||
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
|
||||
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
|
||||
// because they have no impl for `Hash` or `Ord`.
|
||||
let def_id = def.did();
|
||||
let is_std_collection = [
|
||||
sym::Option,
|
||||
sym::Result,
|
||||
sym::LinkedList,
|
||||
sym::Vec,
|
||||
sym::VecDeque,
|
||||
sym::BTreeMap,
|
||||
sym::BTreeSet,
|
||||
sym::Rc,
|
||||
sym::Arc,
|
||||
]
|
||||
.iter()
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
|
||||
let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
|
||||
if is_std_collection || is_box || self.ignore_mut_def_ids.contains(&def_id) {
|
||||
// The type is mutable if any of its type parameters are
|
||||
substs.types().any(|ty| self.is_interior_mutable_type(cx, ty))
|
||||
} else {
|
||||
!ty.has_escaping_bound_vars()
|
||||
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
|
||||
&& !ty.is_freeze(cx.tcx, cx.param_env)
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,13 +68,15 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
|
|||
expr.span,
|
||||
"generally you want to avoid `&mut &mut _` if possible",
|
||||
);
|
||||
} else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
|
||||
span_lint(
|
||||
self.cx,
|
||||
MUT_MUT,
|
||||
expr.span,
|
||||
"this expression mutably borrows a mutable reference. Consider reborrowing",
|
||||
);
|
||||
} else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
|
||||
if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) {
|
||||
span_lint(
|
||||
self.cx,
|
||||
MUT_MUT,
|
||||
expr.span,
|
||||
"this expression mutably borrows a mutable reference. Consider reborrowing",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,14 +36,14 @@ declare_clippy_lint! {
|
|||
declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
|
||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
|
||||
if pat.span.from_expansion() {
|
||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
|
||||
if ref_pat.span.from_expansion() {
|
||||
// OK, simple enough, lints doesn't check in macro.
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
|
||||
for (_, node) in cx.tcx.hir().parent_iter(pat.hir_id) {
|
||||
for (_, node) in cx.tcx.hir().parent_iter(ref_pat.hir_id) {
|
||||
let Node::Pat(pat) = node else { break };
|
||||
|
||||
if matches!(pat.kind, PatKind::Or(_)) {
|
||||
|
@ -52,20 +52,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
|
|||
}
|
||||
|
||||
// Only lint immutable refs, because `&mut ref T` may be useful.
|
||||
let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind else { return };
|
||||
let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else { return };
|
||||
|
||||
match sub_pat.kind {
|
||||
match pat.kind {
|
||||
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
|
||||
PatKind::Binding(BindingAnnotation::REF, _, ident, None) => {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_BORROWED_REFERENCE,
|
||||
pat.span,
|
||||
ref_pat.span,
|
||||
"this pattern takes a reference on something that is being dereferenced",
|
||||
|diag| {
|
||||
// `&ref ident`
|
||||
// ^^^^^
|
||||
let span = pat.span.until(ident.span);
|
||||
let span = ref_pat.span.until(ident.span);
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
"try removing the `&ref` part",
|
||||
|
@ -84,41 +84,71 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
|
|||
}),
|
||||
after,
|
||||
) => {
|
||||
let mut suggestions = Vec::new();
|
||||
|
||||
for element_pat in itertools::chain(before, after) {
|
||||
if let PatKind::Binding(BindingAnnotation::REF, _, ident, None) = element_pat.kind {
|
||||
// `&[..., ref ident, ...]`
|
||||
// ^^^^
|
||||
let span = element_pat.span.until(ident.span);
|
||||
suggestions.push((span, String::new()));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if !suggestions.is_empty() {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_BORROWED_REFERENCE,
|
||||
pat.span,
|
||||
"dereferencing a slice pattern where every element takes a reference",
|
||||
|diag| {
|
||||
// `&[...]`
|
||||
// ^
|
||||
let span = pat.span.until(sub_pat.span);
|
||||
suggestions.push((span, String::new()));
|
||||
|
||||
diag.multipart_suggestion(
|
||||
"try removing the `&` and `ref` parts",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
check_subpatterns(
|
||||
cx,
|
||||
"dereferencing a slice pattern where every element takes a reference",
|
||||
ref_pat,
|
||||
pat,
|
||||
itertools::chain(before, after),
|
||||
);
|
||||
},
|
||||
PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => {
|
||||
check_subpatterns(
|
||||
cx,
|
||||
"dereferencing a tuple pattern where every element takes a reference",
|
||||
ref_pat,
|
||||
pat,
|
||||
subpatterns,
|
||||
);
|
||||
},
|
||||
PatKind::Struct(_, fields, _) => {
|
||||
check_subpatterns(
|
||||
cx,
|
||||
"dereferencing a struct pattern where every field's pattern takes a reference",
|
||||
ref_pat,
|
||||
pat,
|
||||
fields.iter().map(|field| field.pat),
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_subpatterns<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
message: &str,
|
||||
ref_pat: &Pat<'_>,
|
||||
pat: &Pat<'_>,
|
||||
subpatterns: impl IntoIterator<Item = &'tcx Pat<'tcx>>,
|
||||
) {
|
||||
let mut suggestions = Vec::new();
|
||||
|
||||
for subpattern in subpatterns {
|
||||
match subpattern.kind {
|
||||
PatKind::Binding(BindingAnnotation::REF, _, ident, None) => {
|
||||
// `ref ident`
|
||||
// ^^^^
|
||||
let span = subpattern.span.until(ident.span);
|
||||
suggestions.push((span, String::new()));
|
||||
},
|
||||
PatKind::Wild => {},
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
if !suggestions.is_empty() {
|
||||
span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, ref_pat.span, message, |diag| {
|
||||
// `&pat`
|
||||
// ^
|
||||
let span = ref_pat.span.until(pat.span);
|
||||
suggestions.push((span, String::new()));
|
||||
|
||||
diag.multipart_suggestion(
|
||||
"try removing the `&` and `ref` parts",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,7 +287,7 @@ const DROP_ELSE_BLOCK_MSG: &str = "consider dropping the `else` clause";
|
|||
|
||||
const DROP_CONTINUE_EXPRESSION_MSG: &str = "consider dropping the `continue` expression";
|
||||
|
||||
fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
|
||||
fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: LintType) {
|
||||
// snip is the whole *help* message that appears after the warning.
|
||||
// message is the warning message.
|
||||
// expr is the expression which the lint warning message refers to.
|
||||
|
@ -313,7 +313,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str,
|
|||
);
|
||||
}
|
||||
|
||||
fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
|
||||
fn suggestion_snippet_for_continue_inside_if(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
|
||||
let cond_code = snippet(cx, data.if_cond.span, "..");
|
||||
|
||||
let continue_code = snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span));
|
||||
|
@ -327,7 +327,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'
|
|||
)
|
||||
}
|
||||
|
||||
fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>) -> String {
|
||||
fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
|
||||
let cond_code = snippet(cx, data.if_cond.span, "..");
|
||||
|
||||
// Region B
|
||||
|
@ -361,7 +361,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data:
|
|||
)
|
||||
}
|
||||
|
||||
fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) {
|
||||
fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||
if_chain! {
|
||||
if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind;
|
||||
if let Some(last_stmt) = loop_block.stmts.last();
|
||||
|
|
|
@ -340,11 +340,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
|
|||
|
||||
fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
|
||||
|
||||
fn fake_read(
|
||||
&mut self,
|
||||
_: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
|
||||
_: FakeReadCause,
|
||||
_: HirId,
|
||||
) {
|
||||
}
|
||||
fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
|
|
@ -58,9 +58,9 @@ impl EarlyLintPass for OctalEscapes {
|
|||
|
||||
if let ExprKind::Lit(token_lit) = &expr.kind {
|
||||
if matches!(token_lit.kind, LitKind::Str) {
|
||||
check_lit(cx, &token_lit, expr.span, true);
|
||||
check_lit(cx, token_lit, expr.span, true);
|
||||
} else if matches!(token_lit.kind, LitKind::ByteStr) {
|
||||
check_lit(cx, &token_lit, expr.span, false);
|
||||
check_lit(cx, token_lit, expr.span, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use super::ARITHMETIC_SIDE_EFFECTS;
|
||||
use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
|
||||
use clippy_utils::{
|
||||
consts::{constant, constant_simple},
|
||||
diagnostics::span_lint,
|
||||
peel_hir_expr_refs,
|
||||
};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
|
@ -38,24 +42,6 @@ impl ArithmeticSideEffects {
|
|||
}
|
||||
}
|
||||
|
||||
/// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a
|
||||
/// non-constant environment that won't overflow.
|
||||
fn has_valid_op(op: &Spanned<hir::BinOpKind>, expr: &hir::Expr<'_>) -> bool {
|
||||
if let hir::ExprKind::Lit(ref lit) = expr.kind &&
|
||||
let ast::LitKind::Int(value, _) = lit.node
|
||||
{
|
||||
match (&op.node, value) {
|
||||
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
|
||||
(hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
|
||||
| (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
|
||||
| (hir::BinOpKind::Mul, 0 | 1) => true,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given `expr` has any of the inner `allowed` elements.
|
||||
fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
|
||||
self.allowed
|
||||
|
@ -74,15 +60,14 @@ impl ArithmeticSideEffects {
|
|||
self.expr_span = Some(expr.span);
|
||||
}
|
||||
|
||||
/// If `expr` does not match any variant of `LiteralIntegerTy`, returns `None`.
|
||||
fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<LiteralIntegerTy<'expr, 'tcx>> {
|
||||
if matches!(expr.kind, hir::ExprKind::Lit(_)) {
|
||||
return Some(LiteralIntegerTy::Value(expr));
|
||||
/// If `expr` is not a literal integer like `1`, returns `None`.
|
||||
fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
|
||||
if let hir::ExprKind::Lit(ref lit) = expr.kind && let ast::LitKind::Int(n, _) = lit.node {
|
||||
Some(n)
|
||||
}
|
||||
if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind {
|
||||
return Some(LiteralIntegerTy::Ref(inn));
|
||||
else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Manages when the lint should be triggered. Operations in constant environments, hard coded
|
||||
|
@ -117,10 +102,20 @@ impl ArithmeticSideEffects {
|
|||
return;
|
||||
}
|
||||
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
|
||||
match (Self::literal_integer(lhs), Self::literal_integer(rhs)) {
|
||||
(None, Some(lit_int_ty)) | (Some(lit_int_ty), None) => Self::has_valid_op(op, lit_int_ty.into()),
|
||||
(Some(LiteralIntegerTy::Value(_)), Some(LiteralIntegerTy::Value(_))) => true,
|
||||
(None, None) | (Some(_), Some(_)) => false,
|
||||
let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
|
||||
let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
|
||||
match (Self::literal_integer(actual_lhs), Self::literal_integer(actual_rhs)) {
|
||||
(None, None) => false,
|
||||
(None, Some(n)) | (Some(n), None) => match (&op.node, n) {
|
||||
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
|
||||
(hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
|
||||
| (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
|
||||
| (hir::BinOpKind::Mul, 0 | 1) => true,
|
||||
_ => false,
|
||||
},
|
||||
(Some(_), Some(_)) => {
|
||||
matches!((lhs_ref_counter, rhs_ref_counter), (0, 0))
|
||||
},
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
@ -129,21 +124,45 @@ impl ArithmeticSideEffects {
|
|||
self.issue_lint(cx, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn manage_unary_ops<'tcx>(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &hir::Expr<'tcx>,
|
||||
un_expr: &hir::Expr<'tcx>,
|
||||
un_op: hir::UnOp,
|
||||
) {
|
||||
let hir::UnOp::Neg = un_op else { return; };
|
||||
if constant(cx, cx.typeck_results(), un_expr).is_some() {
|
||||
return;
|
||||
}
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
if self.is_allowed_ty(ty) {
|
||||
return;
|
||||
}
|
||||
let actual_un_expr = peel_hir_expr_refs(un_expr).0;
|
||||
if Self::literal_integer(actual_un_expr).is_some() {
|
||||
return;
|
||||
}
|
||||
self.issue_lint(cx, expr);
|
||||
}
|
||||
|
||||
fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool {
|
||||
self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
|
||||
if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
|
||||
if self.should_skip_expr(expr) {
|
||||
return;
|
||||
}
|
||||
match &expr.kind {
|
||||
hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => {
|
||||
self.manage_bin_ops(cx, expr, op, lhs, rhs);
|
||||
},
|
||||
hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
|
||||
if constant_simple(cx, cx.typeck_results(), expr).is_none() {
|
||||
self.issue_lint(cx, expr);
|
||||
}
|
||||
hir::ExprKind::Unary(un_op, un_expr) => {
|
||||
self.manage_unary_ops(cx, expr, un_expr, *un_op);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
@ -177,22 +196,3 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tells if an expression is a integer declared by value or by reference.
|
||||
///
|
||||
/// If `LiteralIntegerTy::Ref`, then the contained value will be `hir::ExprKind::Lit` rather
|
||||
/// than `hirExprKind::Addr`.
|
||||
enum LiteralIntegerTy<'expr, 'tcx> {
|
||||
/// For example, `&199`
|
||||
Ref(&'expr hir::Expr<'tcx>),
|
||||
/// For example, `1` or `i32::MAX`
|
||||
Value(&'expr hir::Expr<'tcx>),
|
||||
}
|
||||
|
||||
impl<'expr, 'tcx> From<LiteralIntegerTy<'expr, 'tcx>> for &'expr hir::Expr<'tcx> {
|
||||
fn from(from: LiteralIntegerTy<'expr, 'tcx>) -> Self {
|
||||
match from {
|
||||
LiteralIntegerTy::Ref(elem) | LiteralIntegerTy::Value(elem) => elem,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ fn in_impl<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
|
||||
fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
|
||||
if_chain! {
|
||||
if let ty::Adt(adt_def, _) = middle_ty.kind();
|
||||
if let Some(local_did) = adt_def.did().as_local();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue