Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones
2025-10-16 15:57:00 +02:00
471 changed files with 7424 additions and 2706 deletions
+2 -2
View File
@@ -17,9 +17,9 @@ jobs:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: '18.x'
node-version: '20.x'
- name: Install remark
run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm
+270 -107
View File
@@ -28,19 +28,19 @@ Note: This Clippy release does not introduce many new lints and is focused entir
### Enhancements
* [`or_fun_call`] now lints `Option::get_or_insert`, `Result::map_or`, `Option/Result::and` methods
[#15071](https://github.com/rust-lang/rust-clippy/pull/15071)
[#15073](https://github.com/rust-lang/rust-clippy/pull/15073)
* [`or_fun_call`] now lints `Option::get_or_insert`, `Result::map_or`, `Option/Result::and` methods
[#15071](https://github.com/rust-lang/rust-clippy/pull/15071)
[#15073](https://github.com/rust-lang/rust-clippy/pull/15073)
[#15074](https://github.com/rust-lang/rust-clippy/pull/15074)
* [`incompatible_msrv`] now recognizes types exceeding MSRV
* [`incompatible_msrv`] now recognizes types exceeding MSRV
[#15296](https://github.com/rust-lang/rust-clippy/pull/15296)
* [`incompatible_msrv`] now checks the right MSRV when in a `const` context
* [`incompatible_msrv`] now checks the right MSRV when in a `const` context
[#15297](https://github.com/rust-lang/rust-clippy/pull/15297)
* [`zero_ptr`] now lints in `const` context as well
* [`zero_ptr`] now lints in `const` context as well
[#15152](https://github.com/rust-lang/rust-clippy/pull/15152)
* [`map_identity`],[`flat_map_identity`] now recognizes `|[x, y]| [x, y]` as an identity function
[#15229](https://github.com/rust-lang/rust-clippy/pull/15229)
* [`exit`] no longer fails on the main function when using `--test` or `--all-targets` flag
* [`exit`] no longer fails on the main function when using `--test` or `--all-targets` flag
[#15222](https://github.com/rust-lang/rust-clippy/pull/15222)
### False Positive Fixes
@@ -51,7 +51,7 @@ Note: This Clippy release does not introduce many new lints and is focused entir
[#15319](https://github.com/rust-lang/rust-clippy/pull/15319)
* [`unused_async`] fixed FP on function with `todo!`
[#15308](https://github.com/rust-lang/rust-clippy/pull/15308)
* [`useless_attribute`] fixed FP when using `#[expect(redundant_imports)]` and similar lint attributes
* [`useless_attribute`] fixed FP when using `#[expect(redundant_imports)]` and similar lint attributes
on `use` statements
[#15318](https://github.com/rust-lang/rust-clippy/pull/15318)
* [`pattern_type_mismatch`] fixed FP in external macro
@@ -64,7 +64,7 @@ Note: This Clippy release does not introduce many new lints and is focused entir
[#15314](https://github.com/rust-lang/rust-clippy/pull/15314)
* [`ptr_as_ptr`] fixed wrong suggestions with turbo fish
[#15289](https://github.com/rust-lang/rust-clippy/pull/15289)
* [`range_plus_one`], [`range_minus_one`] fixed FP by restricting lint to cases where it is safe
* [`range_plus_one`], [`range_minus_one`] fixed FP by restricting lint to cases where it is safe
to switch the range type
[#14432](https://github.com/rust-lang/rust-clippy/pull/14432)
* [`ptr_arg`] fixed FP with underscore binding to `&T` or `&mut T` argument
@@ -129,7 +129,7 @@ Note: This Clippy release does not introduce many new lints and is focused entir
[#15022](https://github.com/rust-lang/rust-clippy/pull/15022)
* [`collapsible_else_if`] fixed FP on conditionally compiled stmt
[#14906](https://github.com/rust-lang/rust-clippy/pull/14906)
* [`missing_const_for_fn`] fixed FP by checking MSRV before emitting lint on function containing
* [`missing_const_for_fn`] fixed FP by checking MSRV before emitting lint on function containing
non-`Sized` trait bounds
[#15080](https://github.com/rust-lang/rust-clippy/pull/15080)
* [`question_mark`] fixed FP when else branch of let-else contains `#[cfg]`
@@ -137,7 +137,7 @@ Note: This Clippy release does not introduce many new lints and is focused entir
### ICE Fixes
* [`single_match`] fixed ICE with deref patterns and string literals
* [`single_match`] fixed ICE with deref patterns and string literals
[#15124](https://github.com/rust-lang/rust-clippy/pull/15124)
* [`needless_doctest_main`] fixed panic when doctest is invalid
[#15052](https://github.com/rust-lang/rust-clippy/pull/15052)
@@ -146,11 +146,11 @@ Note: This Clippy release does not introduce many new lints and is focused entir
### Documentation Improvements
* [`manual_is_variant_and`] improved documentation to include equality comparison patterns
* [`manual_is_variant_and`] improved documentation to include equality comparison patterns
[#15239](https://github.com/rust-lang/rust-clippy/pull/15239)
* [`uninlined_format_args`] improved documentation with example of how to fix a `{:?}` parameter
[#15228](https://github.com/rust-lang/rust-clippy/pull/15228)
* [`undocumented_unsafe_blocks`] improved documentation wording
* [`undocumented_unsafe_blocks`] improved documentation wording
[#15213](https://github.com/rust-lang/rust-clippy/pull/15213)
## Rust 1.89
@@ -292,7 +292,7 @@ Current stable, released 2025-06-26
[#14408](https://github.com/rust-lang/rust-clippy/pull/14408)
* [`iter_kv_map`] now recognizes references on maps
[#14596](https://github.com/rust-lang/rust-clippy/pull/14596)
* [`empty_enum_variants_with_brackets`] no longer lints reachable enums or enums used
* [`empty_enum_variants_with_brackets`] no longer lints reachable enums or enums used
as functions within same crate [#12971](https://github.com/rust-lang/rust-clippy/pull/12971)
* [`needless_lifetimes`] now checks for lifetime uses in closures
[#14608](https://github.com/rust-lang/rust-clippy/pull/14608)
@@ -928,50 +928,50 @@ Released 2024-02-08
### New Lints
- [`infinite_loop`]
* [`infinite_loop`]
[#11829](https://github.com/rust-lang/rust-clippy/pull/11829)
- [`ineffective_open_options`]
* [`ineffective_open_options`]
[#11902](https://github.com/rust-lang/rust-clippy/pull/11902)
- [`uninhabited_references`]
* [`uninhabited_references`]
[#11878](https://github.com/rust-lang/rust-clippy/pull/11878)
- [`repeat_vec_with_capacity`]
* [`repeat_vec_with_capacity`]
[#11597](https://github.com/rust-lang/rust-clippy/pull/11597)
- [`test_attr_in_doctest`]
* [`test_attr_in_doctest`]
[#11872](https://github.com/rust-lang/rust-clippy/pull/11872)
- [`option_map_or_err_ok`]
* [`option_map_or_err_ok`]
[#11864](https://github.com/rust-lang/rust-clippy/pull/11864)
- [`join_absolute_paths`]
* [`join_absolute_paths`]
[#11453](https://github.com/rust-lang/rust-clippy/pull/11453)
- [`impl_hash_borrow_with_str_and_bytes`]
* [`impl_hash_borrow_with_str_and_bytes`]
[#11781](https://github.com/rust-lang/rust-clippy/pull/11781)
- [`iter_over_hash_type`]
* [`iter_over_hash_type`]
[#11791](https://github.com/rust-lang/rust-clippy/pull/11791)
### Moves and Deprecations
- Renamed `blocks_in_if_conditions` to [`blocks_in_conditions`]
* Renamed `blocks_in_if_conditions` to [`blocks_in_conditions`]
[#11853](https://github.com/rust-lang/rust-clippy/pull/11853)
- Moved [`implied_bounds_in_impls`] to `complexity` (Now warn-by-default)
* Moved [`implied_bounds_in_impls`] to `complexity` (Now warn-by-default)
[#11867](https://github.com/rust-lang/rust-clippy/pull/11867)
- Moved [`if_same_then_else`] to `style` (Now warn-by-default)
* Moved [`if_same_then_else`] to `style` (Now warn-by-default)
[#11809](https://github.com/rust-lang/rust-clippy/pull/11809)
### Enhancements
- [`missing_safety_doc`], [`unnecessary_safety_doc`], [`missing_panics_doc`], [`missing_errors_doc`]:
* [`missing_safety_doc`], [`unnecessary_safety_doc`], [`missing_panics_doc`], [`missing_errors_doc`]:
Added the [`check-private-items`] configuration to enable lints on private items
[#11842](https://github.com/rust-lang/rust-clippy/pull/11842)
### ICE Fixes
- [`impl_trait_in_params`]: No longer crashes when a function has generics but no function parameters
* [`impl_trait_in_params`]: No longer crashes when a function has generics but no function parameters
[#11804](https://github.com/rust-lang/rust-clippy/pull/11804)
- [`unused_enumerate_index`]: No longer crashes on empty tuples
* [`unused_enumerate_index`]: No longer crashes on empty tuples
[#11756](https://github.com/rust-lang/rust-clippy/pull/11756)
### Others
- Clippy now respects the `CARGO` environment value
* Clippy now respects the `CARGO` environment value
[#11944](https://github.com/rust-lang/rust-clippy/pull/11944)
## Rust 1.75
@@ -997,7 +997,6 @@ Released 2023-12-28
* [`manual_hash_one`]
[#11556](https://github.com/rust-lang/rust-clippy/pull/11556)
### Moves and Deprecations
* Moved [`read_zero_byte_vec`] to `nursery` (Now allow-by-default)
@@ -1073,7 +1072,7 @@ Released 2023-11-16
### Enhancements
* [`undocumented_unsafe_blocks`]: The config values [`accept-comment-above-statement`] and
* [`undocumented_unsafe_blocks`]: The config values [`accept-comment-above-statement`] and
[`accept-comment-above-attributes`] are now `true` by default
[#11170](https://github.com/rust-lang/rust-clippy/pull/11170)
* [`explicit_iter_loop`]: Added [`enforce-iter-loop-reborrow`] to disable reborrow linting by default
@@ -2254,7 +2253,6 @@ Released 2022-09-22
* [`explicit_auto_deref`]
[#8355](https://github.com/rust-lang/rust-clippy/pull/8355)
### Moves and Deprecations
* Moved [`format_push_string`] to `restriction` (now allow-by-default)
@@ -2455,10 +2453,10 @@ Released 2022-08-11
* [`redundant_allocation`]: No longer lints on fat pointers that would become
thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813)
* [`derive_partial_eq_without_eq`]:
* Handle differing predicates applied by `#[derive(PartialEq)]` and
* Handle differing predicates applied by `#[derive(PartialEq)]` and
`#[derive(Eq)]`
[#8869](https://github.com/rust-lang/rust-clippy/pull/8869)
* No longer lints on non-public types and better handles generics
* No longer lints on non-public types and better handles generics
[#8950](https://github.com/rust-lang/rust-clippy/pull/8950)
* [`empty_line_after_outer_attr`]: No longer lints empty lines in inner
string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892)
@@ -2952,12 +2950,12 @@ Released 2022-02-24
[#7957](https://github.com/rust-lang/rust-clippy/pull/7957)
* [`needless_borrow`]
[#7977](https://github.com/rust-lang/rust-clippy/pull/7977)
* Lint when a borrow is auto-dereffed more than once
* Lint in the trailing expression of a block for a match arm
* Lint when a borrow is auto-dereffed more than once
* Lint in the trailing expression of a block for a match arm
* [`strlen_on_c_strings`]
[8001](https://github.com/rust-lang/rust-clippy/pull/8001)
* Lint when used without a fully-qualified path
* Suggest removing the surrounding unsafe block when possible
* Lint when used without a fully-qualified path
* Suggest removing the surrounding unsafe block when possible
* [`non_ascii_literal`]: Now also lints on `char`s, not just `string`s
[#8034](https://github.com/rust-lang/rust-clippy/pull/8034)
* [`single_char_pattern`]: Now also lints on `split_inclusive`, `split_once`,
@@ -3068,7 +3066,7 @@ Released 2022-02-24
[#7813](https://github.com/rust-lang/rust-clippy/pull/7813)
* New and improved issue templates
[#8032](https://github.com/rust-lang/rust-clippy/pull/8032)
* _Dev:_ Add `cargo dev lint` command, to run your modified Clippy version on a
* *Dev:* Add `cargo dev lint` command, to run your modified Clippy version on a
file [#7917](https://github.com/rust-lang/rust-clippy/pull/7917)
## Rust 1.58
@@ -3278,15 +3276,15 @@ Released 2021-12-02
[#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
* [`option_if_let_else`]: Multiple fixes
[#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
* `break` and `continue` statements local to the would-be closure are
* `break` and `continue` statements local to the would-be closure are
allowed
* Don't lint in const contexts
* Don't lint when yield expressions are used
* Don't lint when the captures made by the would-be closure conflict with
* Don't lint in const contexts
* Don't lint when yield expressions are used
* Don't lint when the captures made by the would-be closure conflict with
the other branch
* Don't lint when a field of a local is used when the type could be
* Don't lint when a field of a local is used when the type could be
potentially moved from
* In some cases, don't lint when scrutinee expression conflicts with the
* In some cases, don't lint when scrutinee expression conflicts with the
captures of the would-be closure
* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
wide pointers with thin pointers
@@ -3535,124 +3533,124 @@ Released 2021-07-29
### New Lints
- [`ref_binding_to_reference`]
* [`ref_binding_to_reference`]
[#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
- [`needless_bitwise_bool`]
* [`needless_bitwise_bool`]
[#7133](https://github.com/rust-lang/rust-clippy/pull/7133)
- [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
- [`manual_str_repeat`]
* [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
* [`manual_str_repeat`]
[#7265](https://github.com/rust-lang/rust-clippy/pull/7265)
- [`suspicious_splitn`]
* [`suspicious_splitn`]
[#7292](https://github.com/rust-lang/rust-clippy/pull/7292)
### Moves and Deprecations
- Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
* Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
the new `avoid-breaking-exported-api` config option (see
[Enhancements](#1-54-enhancements))
[#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
- Move [`inconsistent_struct_constructor`] to `pedantic`
* Move [`inconsistent_struct_constructor`] to `pedantic`
[#7193](https://github.com/rust-lang/rust-clippy/pull/7193)
- Move [`needless_borrow`] to `style` (now warn-by-default)
* Move [`needless_borrow`] to `style` (now warn-by-default)
[#7254](https://github.com/rust-lang/rust-clippy/pull/7254)
- Move [`suspicious_operation_groupings`] to `nursery`
* Move [`suspicious_operation_groupings`] to `nursery`
[#7266](https://github.com/rust-lang/rust-clippy/pull/7266)
- Move [`semicolon_if_nothing_returned`] to `pedantic`
* Move [`semicolon_if_nothing_returned`] to `pedantic`
[#7268](https://github.com/rust-lang/rust-clippy/pull/7268)
### Enhancements <a name="1-54-enhancements"></a>
- [`while_let_on_iterator`]: Now also lints in nested loops
* [`while_let_on_iterator`]: Now also lints in nested loops
[#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
- [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
* [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
[#7156](https://github.com/rust-lang/rust-clippy/pull/7156)
- [`needless_collect`]: Now also lints on assignments with type annotations
* [`needless_collect`]: Now also lints on assignments with type annotations
[#7163](https://github.com/rust-lang/rust-clippy/pull/7163)
- [`if_then_some_else_none`]: Now works with the MSRV config
* [`if_then_some_else_none`]: Now works with the MSRV config
[#7177](https://github.com/rust-lang/rust-clippy/pull/7177)
- Add `avoid-breaking-exported-api` config option for the lints
* Add `avoid-breaking-exported-api` config option for the lints
[`enum_variant_names`], [`large_types_passed_by_value`],
[`trivially_copy_pass_by_ref`], [`unnecessary_wraps`],
[`upper_case_acronyms`], and [`wrong_self_convention`]. We recommend to set
this configuration option to `false` before a major release (1.0/2.0/...) to
clean up the API [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
- [`needless_collect`]: Now lints on even more data structures
* [`needless_collect`]: Now lints on even more data structures
[#7188](https://github.com/rust-lang/rust-clippy/pull/7188)
- [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
* [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
attributes as sufficient documentation
[#7281](https://github.com/rust-lang/rust-clippy/pull/7281)
- [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
* [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
Now work as expected when used with `allow`
[#7282](https://github.com/rust-lang/rust-clippy/pull/7282)
### False Positive Fixes
- [`implicit_return`]: Now takes all diverging functions in account to avoid
* [`implicit_return`]: Now takes all diverging functions in account to avoid
false positives [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
- [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
* [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
and the struct is used in the loop
[#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
- [`multiple_inherent_impl`]: No longer lints with generic arguments
* [`multiple_inherent_impl`]: No longer lints with generic arguments
[#7089](https://github.com/rust-lang/rust-clippy/pull/7089)
- [`comparison_chain`]: No longer lints in a `const` context
* [`comparison_chain`]: No longer lints in a `const` context
[#7118](https://github.com/rust-lang/rust-clippy/pull/7118)
- [`while_immutable_condition`]: Fix false positive where mutation in the loop
* [`while_immutable_condition`]: Fix false positive where mutation in the loop
variable wasn't picked up
[#7144](https://github.com/rust-lang/rust-clippy/pull/7144)
- [`default_trait_access`]: No longer lints in macros
* [`default_trait_access`]: No longer lints in macros
[#7150](https://github.com/rust-lang/rust-clippy/pull/7150)
- [`needless_question_mark`]: No longer lints when the inner value is implicitly
* [`needless_question_mark`]: No longer lints when the inner value is implicitly
dereferenced [#7165](https://github.com/rust-lang/rust-clippy/pull/7165)
- [`unused_unit`]: No longer lints when multiple macro contexts are involved
* [`unused_unit`]: No longer lints when multiple macro contexts are involved
[#7167](https://github.com/rust-lang/rust-clippy/pull/7167)
- [`eval_order_dependence`]: Fix false positive in async context
* [`eval_order_dependence`]: Fix false positive in async context
[#7174](https://github.com/rust-lang/rust-clippy/pull/7174)
- [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
* [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
type [#7175](https://github.com/rust-lang/rust-clippy/pull/7175)
- [`wrong_self_convention`]: No longer lints in trait implementations of
* [`wrong_self_convention`]: No longer lints in trait implementations of
non-`Copy` types [#7182](https://github.com/rust-lang/rust-clippy/pull/7182)
- [`suboptimal_flops`]: No longer lints on `powi(2)`
* [`suboptimal_flops`]: No longer lints on `powi(2)`
[#7201](https://github.com/rust-lang/rust-clippy/pull/7201)
- [`wrong_self_convention`]: No longer lints if there is no implicit `self`
* [`wrong_self_convention`]: No longer lints if there is no implicit `self`
[#7215](https://github.com/rust-lang/rust-clippy/pull/7215)
- [`option_if_let_else`]: No longer lints on `else if let` pattern
* [`option_if_let_else`]: No longer lints on `else if let` pattern
[#7216](https://github.com/rust-lang/rust-clippy/pull/7216)
- [`use_self`], [`useless_conversion`]: Fix false positives when generic
* [`use_self`], [`useless_conversion`]: Fix false positives when generic
arguments are involved
[#7223](https://github.com/rust-lang/rust-clippy/pull/7223)
- [`manual_unwrap_or`]: Fix false positive with deref coercion
* [`manual_unwrap_or`]: Fix false positive with deref coercion
[#7233](https://github.com/rust-lang/rust-clippy/pull/7233)
- [`similar_names`]: No longer lints on `wparam`/`lparam`
* [`similar_names`]: No longer lints on `wparam`/`lparam`
[#7255](https://github.com/rust-lang/rust-clippy/pull/7255)
- [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
* [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
closure [#7263](https://github.com/rust-lang/rust-clippy/pull/7263)
### Suggestion Fixes/Improvements
- [`implicit_return`]
* [`implicit_return`]
[#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
- Fix suggestion for async functions
- Improve suggestion with macros
- Suggest to change `break` to `return` when appropriate
- [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
* Fix suggestion for async functions
* Improve suggestion with macros
* Suggest to change `break` to `return` when appropriate
* [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
[#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
- [`match_single_binding`]: Improve suggestion when match scrutinee has side
* [`match_single_binding`]: Improve suggestion when match scrutinee has side
effects [#7095](https://github.com/rust-lang/rust-clippy/pull/7095)
- [`needless_borrow`]: Now suggests to also change usage sites as needed
* [`needless_borrow`]: Now suggests to also change usage sites as needed
[#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
- [`write_with_newline`]: Improve suggestion when only `\n` is written to the
* [`write_with_newline`]: Improve suggestion when only `\n` is written to the
buffer [#7183](https://github.com/rust-lang/rust-clippy/pull/7183)
- [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
* [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
when a `<_ as Trait>::_` is involved
[#7264](https://github.com/rust-lang/rust-clippy/pull/7264)
- [`not_unsafe_ptr_arg_deref`]: Improved error message
* [`not_unsafe_ptr_arg_deref`]: Improved error message
[#7294](https://github.com/rust-lang/rust-clippy/pull/7294)
### ICE Fixes
- Fix ICE when running Clippy on `libstd`
* Fix ICE when running Clippy on `libstd`
[#7140](https://github.com/rust-lang/rust-clippy/pull/7140)
- [`implicit_return`]
* [`implicit_return`]
[#7242](https://github.com/rust-lang/rust-clippy/pull/7242)
## Rust 1.53
@@ -3697,9 +3695,9 @@ Released 2021-06-17
[#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
[#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
* Attempt to find a common path prefix in suggestion
* Don't lint on `Option` and `Result`
* Consider `Self` prefix
* Attempt to find a common path prefix in suggestion
* Don't lint on `Option` and `Result`
* Consider `Self` prefix
* [`explicit_deref_methods`]: Also lint on chained `deref` calls
[#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
* [`or_fun_call`]: Also lint on `unsafe` blocks
@@ -3959,6 +3957,7 @@ Released 2021-05-06
[#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
### Others
* Running `cargo clippy` after `cargo check` now works as expected
(`cargo clippy` and `cargo check` no longer shares the same build cache)
[#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
@@ -4174,7 +4173,6 @@ Released 2021-02-11
* [`field_reassign_with_default`] No longer lint for private fields
[#6537](https://github.com/rust-lang/rust-clippy/pull/6537)
### Suggestion Fixes/Improvements
* [`vec_box`]: Provide correct type scope suggestion
@@ -4319,8 +4317,8 @@ Released 2020-12-31
### Documentation Improvements
* Some doc improvements:
* [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
* [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
* [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
* [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
* [`doc_markdown`]: Document problematic link text style
[#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
@@ -4703,7 +4701,6 @@ Released 2020-06-04
* [`fn_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
* [`vtable_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
### Moves and Deprecations
* Deprecate [`replace_consts`] lint [#5380](https://github.com/rust-lang/rust-clippy/pull/5380)
@@ -4718,7 +4715,7 @@ Released 2020-06-04
### Enhancements
* On _nightly_ you can now use `cargo clippy --fix -Z unstable-options` to
* On *nightly* you can now use `cargo clippy --fix -Z unstable-options` to
auto-fix lints that support this [#5363](https://github.com/rust-lang/rust-clippy/pull/5363)
* Make [`redundant_clone`] also trigger on cases where the cloned value is not
consumed. [#5304](https://github.com/rust-lang/rust-clippy/pull/5304)
@@ -4745,7 +4742,6 @@ Released 2020-06-04
* [`redundant_pattern`] [#5287](https://github.com/rust-lang/rust-clippy/pull/5287)
* [`inconsistent_digit_grouping`] [#5451](https://github.com/rust-lang/rust-clippy/pull/5451)
### Suggestion Improvements
* Improved [`question_mark`] lint suggestion so that it doesn't add redundant `as_ref()` [#5481](https://github.com/rust-lang/rust-clippy/pull/5481)
@@ -4823,7 +4819,6 @@ Released 2020-04-23
* Clippy now completely runs on GitHub Actions [#5190](https://github.com/rust-lang/rust-clippy/pull/5190)
## Rust 1.42
Released 2020-03-12
@@ -4890,7 +4885,6 @@ Released 2020-03-12
* Improve documentation of [`empty_enum`], [`replace_consts`], [`redundant_clone`], and [`iterator_step_by_zero`]
## Rust 1.41
Released 2020-01-30
@@ -5106,7 +5100,6 @@ Released 2019-07-04
* Fix ICE in [`suspicious_else_formatting`] [#3960](https://github.com/rust-lang/rust-clippy/pull/3960)
* Fix ICE in [`decimal_literal_representation`] [#3931](https://github.com/rust-lang/rust-clippy/pull/3931)
## Rust 1.35
Released 2019-05-20
@@ -5129,7 +5122,7 @@ Released 2019-05-20
* Fix false positive in [`needless_continue`] pertaining to loop labels
* Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
* Fix false positive for [`use_self`] in nested functions
* Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
* Fix suggestion for [`expect_fun_call`] (<https://github.com/rust-lang/rust-clippy/pull/3846>)
* Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
* Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
* Avoid triggering [`redundant_closure`] in macros
@@ -5273,6 +5266,7 @@ Released 2018-12-06
Released 2018-10-25
[View all 88 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-08-02T16%3A54%3A12Z..2018-09-17T09%3A44%3A06Z+base%3Amaster)
* Deprecate `assign_ops` lint
* New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
[`needless_collect`], [`copy_iterator`]
@@ -5322,255 +5316,326 @@ Released 2018-09-13
* Improve website header
## 0.0.212 (2018-07-10)
* Rustup to *rustc 1.29.0-nightly (e06c87544 2018-07-06)*
## 0.0.211
* Rustup to *rustc 1.28.0-nightly (e3bf634e0 2018-06-28)*
## 0.0.210
* Rustup to *rustc 1.28.0-nightly (01cc982e9 2018-06-24)*
## 0.0.209
* Rustup to *rustc 1.28.0-nightly (523097979 2018-06-18)*
## 0.0.208
* Rustup to *rustc 1.28.0-nightly (86a8f1a63 2018-06-17)*
## 0.0.207
* Rustup to *rustc 1.28.0-nightly (2a0062974 2018-06-09)*
## 0.0.206
* Rustup to *rustc 1.28.0-nightly (5bf68db6e 2018-05-28)*
## 0.0.205
* Rustup to *rustc 1.28.0-nightly (990d8aa74 2018-05-25)*
* Rename `unused_lifetimes` to `extra_unused_lifetimes` because of naming conflict with new rustc lint
## 0.0.204
* Rustup to *rustc 1.28.0-nightly (71e87be38 2018-05-22)*
## 0.0.203
* Rustup to *rustc 1.28.0-nightly (a3085756e 2018-05-19)*
* Clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
## 0.0.202
* Rustup to *rustc 1.28.0-nightly (952f344cd 2018-05-18)*
## 0.0.201
* Rustup to *rustc 1.27.0-nightly (2f2a11dfc 2018-05-16)*
## 0.0.200
* Rustup to *rustc 1.27.0-nightly (9fae15374 2018-05-13)*
## 0.0.199
* Rustup to *rustc 1.27.0-nightly (ff2ac35db 2018-05-12)*
## 0.0.198
* Rustup to *rustc 1.27.0-nightly (acd3871ba 2018-05-10)*
## 0.0.197
* Rustup to *rustc 1.27.0-nightly (428ea5f6b 2018-05-06)*
## 0.0.196
* Rustup to *rustc 1.27.0-nightly (e82261dfb 2018-05-03)*
## 0.0.195
* Rustup to *rustc 1.27.0-nightly (ac3c2288f 2018-04-18)*
## 0.0.194
* Rustup to *rustc 1.27.0-nightly (bd40cbbe1 2018-04-14)*
* New lints: [`cast_ptr_alignment`], [`transmute_ptr_to_ptr`], [`write_literal`], [`write_with_newline`], [`writeln_empty_string`]
## 0.0.193
* Rustup to *rustc 1.27.0-nightly (eeea94c11 2018-04-06)*
## 0.0.192
* Rustup to *rustc 1.27.0-nightly (fb44b4c0e 2018-04-04)*
* New lint: [`print_literal`]
## 0.0.191
* Rustup to *rustc 1.26.0-nightly (ae544ee1c 2018-03-29)*
* Lint audit; categorize lints as style, correctness, complexity, pedantic, nursery, restriction.
## 0.0.190
* Fix a bunch of intermittent cargo bugs
## 0.0.189
* Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)*
## 0.0.188
* Rustup to *rustc 1.26.0-nightly (392645394 2018-03-15)*
* New lint: [`while_immutable_condition`]
## 0.0.187
* Rustup to *rustc 1.26.0-nightly (322d7f7b9 2018-02-25)*
* New lints: [`redundant_field_names`], [`suspicious_arithmetic_impl`], [`suspicious_op_assign_impl`]
## 0.0.186
* Rustup to *rustc 1.25.0-nightly (0c6091fbd 2018-02-04)*
* Various false positive fixes
## 0.0.185
* Rustup to *rustc 1.25.0-nightly (56733bc9f 2018-02-01)*
* New lint: [`question_mark`]
## 0.0.184
* Rustup to *rustc 1.25.0-nightly (90eb44a58 2018-01-29)*
* New lints: [`double_comparisons`], [`empty_line_after_outer_attr`]
## 0.0.183
* Rustup to *rustc 1.25.0-nightly (21882aad7 2018-01-28)*
* New lint: [`misaligned_transmute`]
## 0.0.182
* Rustup to *rustc 1.25.0-nightly (a0dcecff9 2018-01-24)*
* New lint: [`decimal_literal_representation`]
## 0.0.181
* Rustup to *rustc 1.25.0-nightly (97520ccb1 2018-01-21)*
* New lints: [`else_if_without_else`], [`option_option`], [`unit_arg`], [`unnecessary_fold`]
* Removed `unit_expr`
* Various false positive fixes for [`needless_pass_by_value`]
## 0.0.180
* Rustup to *rustc 1.25.0-nightly (3f92e8d89 2018-01-14)*
## 0.0.179
* Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)*
## 0.0.178
* Rustup to *rustc 1.25.0-nightly (ee220daca 2018-01-07)*
## 0.0.177
* Rustup to *rustc 1.24.0-nightly (250b49205 2017-12-21)*
* New lint: [`match_as_ref`]
## 0.0.176
* Rustup to *rustc 1.24.0-nightly (0077d128d 2017-12-14)*
## 0.0.175
* Rustup to *rustc 1.24.0-nightly (bb42071f6 2017-12-01)*
## 0.0.174
* Rustup to *rustc 1.23.0-nightly (63739ab7b 2017-11-21)*
## 0.0.173
* Rustup to *rustc 1.23.0-nightly (33374fa9d 2017-11-20)*
## 0.0.172
* Rustup to *rustc 1.23.0-nightly (d0f8e2913 2017-11-16)*
## 0.0.171
* Rustup to *rustc 1.23.0-nightly (ff0f5de3b 2017-11-14)*
## 0.0.170
* Rustup to *rustc 1.23.0-nightly (d6b06c63a 2017-11-09)*
## 0.0.169
* Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)*
* New lints: [`just_underscores_and_digits`], `result_map_unwrap_or_else`, [`transmute_bytes_to_str`]
## 0.0.168
* Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)*
## 0.0.167
* Rustup to *rustc 1.23.0-nightly (90ef3372e 2017-10-29)*
* New lints: `const_static_lifetime`, [`erasing_op`], [`fallible_impl_from`], [`println_empty_string`], [`useless_asref`]
## 0.0.166
* Rustup to *rustc 1.22.0-nightly (b7960878b 2017-10-18)*
* New lints: [`explicit_write`], `identity_conversion`, [`implicit_hasher`], `invalid_ref`, [`option_map_or_none`],
[`range_minus_one`], [`range_plus_one`], [`transmute_int_to_bool`], [`transmute_int_to_char`],
[`transmute_int_to_float`]
## 0.0.165
* Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27)
* New lint: [`mut_range_bound`]
## 0.0.164
* Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)*
* New lint: [`int_plus_one`]
## 0.0.163
* Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)*
## 0.0.162
* Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)*
* New lint: [`chars_last_cmp`]
* Improved suggestions for [`needless_borrow`], [`ptr_arg`],
## 0.0.161
* Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)*
## 0.0.160
* Update to *rustc 1.22.0-nightly (dd08c3070 2017-09-12)*
## 0.0.159
* Update to *rustc 1.22.0-nightly (eba374fb2 2017-09-11)*
* New lint: [`clone_on_ref_ptr`]
## 0.0.158
* New lint: [`manual_memcpy`]
* [`cast_lossless`] no longer has redundant parentheses in its suggestions
* Update to *rustc 1.22.0-nightly (dead08cb3 2017-09-08)*
## 0.0.157 - 2017-09-04
* Update to *rustc 1.22.0-nightly (981ce7d8d 2017-09-03)*
* New lint: `unit_expr`
## 0.0.156 - 2017-09-03
* Update to *rustc 1.22.0-nightly (744dd6c1d 2017-09-02)*
## 0.0.155
* Update to *rustc 1.21.0-nightly (c11f689d2 2017-08-29)*
* New lint: [`infinite_iter`], [`maybe_infinite_iter`], [`cast_lossless`]
## 0.0.154
* Update to *rustc 1.21.0-nightly (2c0558f63 2017-08-24)*
* Fix [`use_self`] triggering inside derives
* Add support for linting an entire workspace with `cargo clippy --all`
* New lint: [`naive_bytecount`]
## 0.0.153
* Update to *rustc 1.21.0-nightly (8c303ed87 2017-08-20)*
* New lint: [`use_self`]
## 0.0.152
* Update to *rustc 1.21.0-nightly (df511d554 2017-08-14)*
## 0.0.151
* Update to *rustc 1.21.0-nightly (13d94d5fa 2017-08-10)*
## 0.0.150
* Update to *rustc 1.21.0-nightly (215e0b10e 2017-08-08)*
## 0.0.148
* Update to *rustc 1.21.0-nightly (37c7d0ebb 2017-07-31)*
* New lints: [`unreadable_literal`], [`inconsistent_digit_grouping`], [`large_digit_groups`]
## 0.0.147
* Update to *rustc 1.21.0-nightly (aac223f4f 2017-07-30)*
## 0.0.146
* Update to *rustc 1.21.0-nightly (52a330969 2017-07-27)*
* Fixes false positives in `inline_always`
* Fixes false negatives in `panic_params`
## 0.0.145
* Update to *rustc 1.20.0-nightly (afe145d22 2017-07-23)*
## 0.0.144
* Update to *rustc 1.20.0-nightly (086eaa78e 2017-07-15)*
## 0.0.143
* Update to *rustc 1.20.0-nightly (d84693b93 2017-07-09)*
* Fix `cargo clippy` crashing on `dylib` projects
* Fix false positives around `nested_while_let` and `never_loop`
## 0.0.142
* Update to *rustc 1.20.0-nightly (067971139 2017-07-02)*
## 0.0.141
* Rewrite of the `doc_markdown` lint.
* Deprecated [`range_step_by_zero`]
* New lint: [`iterator_step_by_zero`]
@@ -5578,151 +5643,195 @@ Released 2018-09-13
* Update to *rustc 1.20.0-nightly (69c65d296 2017-06-28)*
## 0.0.140 - 2017-06-16
* Update to *rustc 1.19.0-nightly (258ae6dd9 2017-06-15)*
## 0.0.139 — 2017-06-10
* Update to *rustc 1.19.0-nightly (4bf5c99af 2017-06-10)*
* Fix bugs with for loop desugaring
* Check for [`AsRef`]/[`AsMut`] arguments in [`wrong_self_convention`]
## 0.0.138 — 2017-06-05
* Update to *rustc 1.19.0-nightly (0418fa9d3 2017-06-04)*
## 0.0.137 — 2017-06-05
* Update to *rustc 1.19.0-nightly (6684d176c 2017-06-03)*
## 0.0.136 — 2017—05—26
* Update to *rustc 1.19.0-nightly (557967766 2017-05-26)*
## 0.0.135 — 2017—05—24
* Update to *rustc 1.19.0-nightly (5b13bff52 2017-05-23)*
## 0.0.134 — 2017—05—19
* Update to *rustc 1.19.0-nightly (0ed1ec9f9 2017-05-18)*
## 0.0.133 — 2017—05—14
* Update to *rustc 1.19.0-nightly (826d8f385 2017-05-13)*
## 0.0.132 — 2017—05—05
* Fix various bugs and some ices
## 0.0.131 — 2017—05—04
* Update to *rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)*
## 0.0.130 — 2017—05—03
* Update to *rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)*
## 0.0.129 — 2017-05-01
* Update to *rustc 1.19.0-nightly (06fb4d256 2017-04-30)*
## 0.0.128 — 2017-04-28
* Update to *rustc 1.18.0-nightly (94e884b63 2017-04-27)*
## 0.0.127 — 2017-04-27
* Update to *rustc 1.18.0-nightly (036983201 2017-04-26)*
* New lint: [`needless_continue`]
## 0.0.126 — 2017-04-24
* Update to *rustc 1.18.0-nightly (2bd4b5c6d 2017-04-23)*
## 0.0.125 — 2017-04-19
* Update to *rustc 1.18.0-nightly (9f2abadca 2017-04-18)*
## 0.0.124 — 2017-04-16
* Update to *rustc 1.18.0-nightly (d5cf1cb64 2017-04-15)*
## 0.0.123 — 2017-04-07
* Fix various false positives
## 0.0.122 — 2017-04-07
* Rustup to *rustc 1.18.0-nightly (91ae22a01 2017-04-05)*
* New lint: [`op_ref`]
## 0.0.121 — 2017-03-21
* Rustup to *rustc 1.17.0-nightly (134c4a0f0 2017-03-20)*
## 0.0.120 — 2017-03-17
* Rustup to *rustc 1.17.0-nightly (0aeb9c129 2017-03-15)*
## 0.0.119 — 2017-03-13
* Rustup to *rustc 1.17.0-nightly (824c9ebbd 2017-03-12)*
## 0.0.118 — 2017-03-05
* Rustup to *rustc 1.17.0-nightly (b1e31766d 2017-03-03)*
## 0.0.117 — 2017-03-01
* Rustup to *rustc 1.17.0-nightly (be760566c 2017-02-28)*
## 0.0.116 — 2017-02-28
* Fix `cargo clippy` on 64 bit windows systems
## 0.0.115 — 2017-02-27
* Rustup to *rustc 1.17.0-nightly (60a0edc6c 2017-02-26)*
* New lints: [`zero_ptr`], [`never_loop`], [`mut_from_ref`]
## 0.0.114 — 2017-02-08
* Rustup to *rustc 1.17.0-nightly (c49d10207 2017-02-07)*
* Tests are now ui tests (testing the exact output of rustc)
## 0.0.113 — 2017-02-04
* Rustup to *rustc 1.16.0-nightly (eedaa94e3 2017-02-02)*
* New lint: [`large_enum_variant`]
* `explicit_into_iter_loop` provides suggestions
## 0.0.112 — 2017-01-27
* Rustup to *rustc 1.16.0-nightly (df8debf6d 2017-01-25)*
## 0.0.111 — 2017-01-21
* Rustup to *rustc 1.16.0-nightly (a52da95ce 2017-01-20)*
## 0.0.110 — 2017-01-20
* Add badges and categories to `Cargo.toml`
## 0.0.109 — 2017-01-19
* Update to *rustc 1.16.0-nightly (c07a6ae77 2017-01-17)*
## 0.0.108 — 2017-01-12
* Update to *rustc 1.16.0-nightly (2782e8f8f 2017-01-12)*
## 0.0.107 — 2017-01-11
* Update regex dependency
* Fix FP when matching `&&mut` by `&ref`
* Reintroduce `for (_, x) in &mut hash_map` -> `for x in hash_map.values_mut()`
* New lints: [`unused_io_amount`], [`forget_ref`], [`short_circuit_statement`]
## 0.0.106 — 2017-01-04
* Fix FP introduced by rustup in [`wrong_self_convention`]
## 0.0.105 — 2017-01-04
* Update to *rustc 1.16.0-nightly (468227129 2017-01-03)*
* New lints: [`deref_addrof`], [`double_parens`], [`pub_enum_variant_names`]
* Fix suggestion in [`new_without_default`]
* FP fix in [`absurd_extreme_comparisons`]
## 0.0.104 — 2016-12-15
* Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)*
## 0.0.103 — 2016-11-25
* Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)*
## 0.0.102 — 2016-11-24
* Update to *rustc 1.15.0-nightly (3bf2be9ce 2016-11-22)*
## 0.0.101 — 2016-11-23
* Update to *rustc 1.15.0-nightly (7b3eeea22 2016-11-21)*
* New lint: [`string_extend_chars`]
## 0.0.100 — 2016-11-20
* Update to *rustc 1.15.0-nightly (ac635aa95 2016-11-18)*
## 0.0.99 — 2016-11-18
* Update to rustc 1.15.0-nightly (0ed951993 2016-11-14)
* New lint: [`get_unwrap`]
## 0.0.98 — 2016-11-08
* Fixes an issue due to a change in how cargo handles `--sysroot`, which broke `cargo clippy`
## 0.0.97 — 2016-11-03
* For convenience, `cargo clippy` defines a `cargo-clippy` feature. This was
previously added for a short time under the name `clippy` but removed for
compatibility.
@@ -5731,34 +5840,43 @@ Released 2018-09-13
* New lints: [`if_let_redundant_pattern_matching`], [`partialeq_ne_impl`]
## 0.0.96 — 2016-10-22
* Rustup to *rustc 1.14.0-nightly (f09420685 2016-10-20)*
* New lint: [`iter_skip_next`]
## 0.0.95 — 2016-10-06
* Rustup to *rustc 1.14.0-nightly (3210fd5c2 2016-10-05)*
## 0.0.94 — 2016-10-04
* Fixes bustage on Windows due to forbidden directory name
## 0.0.93 — 2016-10-03
* Rustup to *rustc 1.14.0-nightly (144af3e97 2016-10-02)*
* `option_map_unwrap_or` and `option_map_unwrap_or_else` are now
allowed by default.
* New lint: [`explicit_into_iter_loop`]
## 0.0.92 — 2016-09-30
* Rustup to *rustc 1.14.0-nightly (289f3a4ca 2016-09-29)*
## 0.0.91 — 2016-09-28
* Rustup to *rustc 1.13.0-nightly (d0623cf7b 2016-09-26)*
## 0.0.90 — 2016-09-09
* Rustup to *rustc 1.13.0-nightly (f1f40f850 2016-09-09)*
## 0.0.89 — 2016-09-06
* Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)*
## 0.0.88 — 2016-09-04
* Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)*
* The following lints are not new but were only usable through the `clippy`
lint groups: [`filter_next`], `for_loop_over_option`,
@@ -5767,30 +5885,37 @@ Released 2018-09-13
through `cargo clippy`.
## 0.0.87 — 2016-08-31
* Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*
* New lints: [`builtin_type_shadow`]
* Fix FP in [`zero_prefixed_literal`] and `0b`/`0o`
## 0.0.86 — 2016-08-28
* Rustup to *rustc 1.13.0-nightly (a23064af5 2016-08-27)*
* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`]
## 0.0.85 — 2016-08-19
* Fix ICE with [`useless_attribute`]
* [`useless_attribute`] ignores `unused_imports` on `use` statements
## 0.0.84 — 2016-08-18
* Rustup to *rustc 1.13.0-nightly (aef6971ca 2016-08-17)*
## 0.0.83 — 2016-08-17
* Rustup to *rustc 1.12.0-nightly (1bf5fa326 2016-08-16)*
* New lints: [`print_with_newline`], [`useless_attribute`]
## 0.0.82 — 2016-08-17
* Rustup to *rustc 1.12.0-nightly (197be89f3 2016-08-15)*
* New lint: [`module_inception`]
## 0.0.81 — 2016-08-14
* Rustup to *rustc 1.12.0-nightly (1deb02ea6 2016-08-12)*
* New lints: [`eval_order_dependence`], [`mixed_case_hex_literals`], [`unseparated_literal_suffix`]
* False positive fix in [`too_many_arguments`]
@@ -5800,14 +5925,17 @@ Released 2018-09-13
* Doc improvements
## 0.0.80 — 2016-07-31
* Rustup to *rustc 1.12.0-nightly (1225e122f 2016-07-30)*
* New lints: [`misrefactored_assign_op`], [`serde_api_misuse`]
## 0.0.79 — 2016-07-10
* Rustup to *rustc 1.12.0-nightly (f93aaf84c 2016-07-09)*
* Major suggestions refactoring
## 0.0.78 — 2016-07-02
* Rustup to *rustc 1.11.0-nightly (01411937f 2016-07-01)*
* New lints: [`wrong_transmute`], [`double_neg`], [`filter_map`]
* For compatibility, `cargo clippy` does not defines the `clippy` feature
@@ -5815,118 +5943,148 @@ Released 2018-09-13
* [`collapsible_if`] now considers `if let`
## 0.0.77 — 2016-06-21
* Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)*
* New lints: `stutter` and [`iter_nth`]
## 0.0.76 — 2016-06-10
* Rustup to *rustc 1.11.0-nightly (7d2f75a95 2016-06-09)*
* `cargo clippy` now automatically defines the `clippy` feature
* New lint: [`not_unsafe_ptr_arg_deref`]
## 0.0.75 — 2016-06-08
* Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)*
## 0.0.74 — 2016-06-07
* Fix bug with `cargo-clippy` JSON parsing
* Add the `CLIPPY_DISABLE_DOCS_LINKS` environment variable to deactivate the
“for further information visit *lint-link*” message.
## 0.0.73 — 2016-06-05
* Fix false positives in [`useless_let_if_seq`]
## 0.0.72 — 2016-06-04
* Fix false positives in [`useless_let_if_seq`]
## 0.0.71 — 2016-05-31
* Rustup to *rustc 1.11.0-nightly (a967611d8 2016-05-30)*
* New lint: [`useless_let_if_seq`]
## 0.0.70 — 2016-05-28
* Rustup to *rustc 1.10.0-nightly (7bddce693 2016-05-27)*
* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`,
`RegexBuilder::new` and byte regexes
## 0.0.69 — 2016-05-20
* Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)*
* [`used_underscore_binding`] has been made `Allow` temporarily
## 0.0.68 — 2016-05-17
* Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)*
* New lint: [`unnecessary_operation`]
## 0.0.67 — 2016-05-12
* Rustup to *rustc 1.10.0-nightly (22ac88f1a 2016-05-11)*
## 0.0.66 — 2016-05-11
* New `cargo clippy` subcommand
* New lints: [`assign_op_pattern`], [`assign_ops`], [`needless_borrow`]
## 0.0.65 — 2016-05-08
* Rustup to *rustc 1.10.0-nightly (62e2b2fb7 2016-05-06)*
* New lints: [`float_arithmetic`], [`integer_arithmetic`]
## 0.0.64 — 2016-04-26
* Rustup to *rustc 1.10.0-nightly (645dd013a 2016-04-24)*
* New lints: `temporary_cstring_as_ptr`, [`unsafe_removed_from_name`], and [`mem_forget`]
## 0.0.63 — 2016-04-08
* Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)*
## 0.0.62 — 2016-04-07
* Rustup to *rustc 1.9.0-nightly (bf5da36f1 2016-04-06)*
## 0.0.61 — 2016-04-03
* Rustup to *rustc 1.9.0-nightly (5ab11d72c 2016-04-02)*
* New lint: [`invalid_upcast_comparisons`]
## 0.0.60 — 2016-04-01
* Rustup to *rustc 1.9.0-nightly (e1195c24b 2016-03-31)*
## 0.0.59 — 2016-03-31
* Rustup to *rustc 1.9.0-nightly (30a3849f2 2016-03-30)*
* New lints: [`logic_bug`], [`nonminimal_bool`]
* Fixed: [`match_same_arms`] now ignores arms with guards
* Improved: [`useless_vec`] now warns on `for … in vec![…]`
## 0.0.58 — 2016-03-27
* Rustup to *rustc 1.9.0-nightly (d5a91e695 2016-03-26)*
* New lint: [`doc_markdown`]
## 0.0.57 — 2016-03-27
* Update to *rustc 1.9.0-nightly (a1e29daf1 2016-03-25)*
* Deprecated lints: [`str_to_string`], [`string_to_string`], [`unstable_as_slice`], [`unstable_as_mut_slice`]
* New lint: [`crosspointer_transmute`]
## 0.0.56 — 2016-03-23
* Update to *rustc 1.9.0-nightly (0dcc413e4 2016-03-22)*
* New lints: [`many_single_char_names`] and [`similar_names`]
## 0.0.55 — 2016-03-21
* Update to *rustc 1.9.0-nightly (02310fd31 2016-03-19)*
## 0.0.54 — 2016-03-16
* Update to *rustc 1.9.0-nightly (c66d2380a 2016-03-15)*
## 0.0.53 — 2016-03-15
* Add a [configuration file]
## ~~0.0.52~~
## 0.0.51 — 2016-03-13
* Add `str` to types considered by [`len_zero`]
* New lints: [`indexing_slicing`]
## 0.0.50 — 2016-03-11
* Update to *rustc 1.9.0-nightly (c9629d61c 2016-03-10)*
## 0.0.49 — 2016-03-09
* Update to *rustc 1.9.0-nightly (eabfc160f 2016-03-08)*
* New lints: [`overflow_check_conditional`], `unused_label`, [`new_without_default`]
## 0.0.48 — 2016-03-07
* Fixed: ICE in [`needless_range_loop`] with globals
## 0.0.47 — 2016-03-07
* Update to *rustc 1.9.0-nightly (998a6720b 2016-03-07)*
* New lint: [`redundant_closure_call`]
@@ -6573,6 +6731,7 @@ Released 2018-09-13
[`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
[`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity
[`replace_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_box
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
[`repr_packed_without_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi
[`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
@@ -6738,6 +6897,7 @@ Released 2018-09-13
[`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max
[`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_option_map_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_option_map_or_else
[`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
[`unnecessary_result_map_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_result_map_or_else
[`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
@@ -6798,6 +6958,7 @@ Released 2018-09-13
[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
[`volatile_composites`]: https://rust-lang.github.io/rust-clippy/master/index.html#volatile_composites
[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
[`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake
[`while_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_float
@@ -6874,6 +7035,7 @@ Released 2018-09-13
[`excessive-nesting-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#excessive-nesting-threshold
[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold
[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability
[`inherent-impl-lint-scope`]: https://doc.rust-lang.org/clippy/lint_configuration.html#inherent-impl-lint-scope
[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold
[`lint-commented-code`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-commented-code
[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
@@ -6891,6 +7053,7 @@ Released 2018-09-13
[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv
[`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit
[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
[`recursive-self-in-type-definitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-type-definitions
[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline
[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline
[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
+1 -3
View File
@@ -759,8 +759,7 @@ for some users. Adding a configuration is done in the following steps:
Here are some pointers to things you are likely going to need for every lint:
* [Clippy utils][utils] - Various helper functions. Maybe the function you need
is already in here ([`is_type_diagnostic_item`], [`implements_trait`],
[`snippet`], etc)
is already in here ([`implements_trait`], [`snippet`], etc)
* [Clippy diagnostics][diagnostics]
* [Let chains][let-chains]
* [`from_expansion`][from_expansion] and
@@ -790,7 +789,6 @@ get away with copying things from existing similar lints. If you are stuck,
don't hesitate to ask on [Zulip] or in the issue/PR.
[utils]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/index.html
[`is_type_diagnostic_item`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.is_type_diagnostic_item.html
[`implements_trait`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.implements_trait.html
[`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
[let-chains]: https://github.com/rust-lang/rust/pull/94927
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for MyStructLint {
// Check our expr is calling a method
if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
// Check the name of this method is `some_method`
&& path.ident.name.as_str() == "some_method"
&& path.ident.name == sym::some_method
// Optionally, check the type of the self argument.
// - See "Checking for a specific type"
{
@@ -85,9 +85,8 @@ to check for. All of these methods only check for the base type, generic
arguments have to be checked separately.
```rust
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::paths;
use rustc_span::symbol::sym;
use clippy_utils::{paths, sym};
use clippy_utils::res::MaybeDef;
use rustc_hir::LangItem;
impl LateLintPass<'_> for MyStructLint {
@@ -97,12 +96,12 @@ impl LateLintPass<'_> for MyStructLint {
// 1. Using diagnostic items
// The last argument is the diagnostic item to check for
if is_type_diagnostic_item(cx, ty, sym::Option) {
if ty.is_diag_item(cx, sym::Option) {
// The type is an `Option`
}
// 2. Using lang items
if is_type_lang_item(cx, ty, LangItem::RangeFull) {
if ty.is_lang_item(cx, LangItem::RangeFull) {
// The type is a full range like `.drain(..)`
}
@@ -123,27 +122,29 @@ There are three ways to do this, depending on if the target trait has a
diagnostic item, lang item or neither.
```rust
use clippy_utils::sym;
use clippy_utils::ty::implements_trait;
use clippy_utils::is_trait_method;
use rustc_span::symbol::sym;
impl LateLintPass<'_> for MyStructLint {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
// 1. Using diagnostic items with the expression
// we use `is_trait_method` function from Clippy's utils
if is_trait_method(cx, expr, sym::Iterator) {
// method call in `expr` belongs to `Iterator` trait
// 1. Get the `DefId` of the trait.
// via lang items
let trait_id = cx.tcx.lang_items().drop_trait();
// via diagnostic items
let trait_id = cx.tcx.get_diagnostic_item(sym::Eq);
// 2. Check for the trait implementation via the `implements_trait` util.
let ty = cx.typeck_results().expr_ty(expr);
if trait_id.is_some_and(|id| implements_trait(cx, ty, id, &[])) {
// `ty` implements the trait.
}
// 2. Using lang items with the expression type
let ty = cx.typeck_results().expr_ty(expr);
if cx.tcx.lang_items()
// we are looking for the `DefId` of `Drop` trait in lang items
.drop_trait()
// then we use it with our type `ty` by calling `implements_trait` from Clippy's utils
.is_some_and(|id| implements_trait(cx, ty, id, &[])) {
// `expr` implements `Drop` trait
}
// 3. If the trait requires additional generic arguments
let trait_id = cx.tcx.lang_items().eq_trait();
if trait_id.is_some_and(|id| implements_trait(cx, ty, id, &[ty])) {
// `ty` implements `PartialEq<Self>`
}
}
}
```
@@ -173,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
// We can also check it has a parameter `self`
&& signature.decl.implicit_self.has_implicit_self()
// We can go further and even check if its return type is `String`
&& is_type_lang_item(cx, return_ty(cx, impl_item.hir_id), LangItem::String)
&& return_ty(cx, impl_item.hir_id).is_lang_item(cx, LangItem::String)
{
// ...
}
+2 -2
View File
@@ -37,7 +37,7 @@ before emitting suggestions to the end user to avoid false positives.
Several functions are available for working with macros.
### The `Span.from_expansion` method
### The `Span::from_expansion` method
We could utilize a `span`'s [`from_expansion`] method, which
detects if the `span` is from a macro expansion / desugaring.
@@ -50,7 +50,7 @@ if expr.span.from_expansion() {
}
```
### `Span.ctxt` method
### `Span::ctxt` method
The `span`'s context, given by the method [`ctxt`] and returning [SyntaxContext],
represents if the span is from a macro expansion and, if it is, which
+11 -8
View File
@@ -15,20 +15,20 @@ the [`ExprKind`] that we can access from `expr.kind`:
```rust
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_span::sym;
use clippy_utils::is_trait_method;
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use clippy_utils::sym;
impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
// Check our expr is calling a method with pattern matching
if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind
// Check if the name of this method is `our_fancy_method`
&& path.ident.name.as_str() == "our_fancy_method"
&& path.ident.name == sym::our_fancy_method
// We can check the type of the self argument whenever necessary.
// (It's necessary if we want to check that method is specifically belonging to a specific trait,
// for example, a `map` method could belong to user-defined trait instead of to `Iterator`)
// See the next section for more information.
&& is_trait_method(cx, self_arg, sym::OurFancyTrait)
&& cx.ty_based_def(self_arg).opt_parent(cx).is_diag_item(cx, sym::OurFancyTrait)
{
println!("`expr` is a method call for `our_fancy_method`");
}
@@ -41,6 +41,10 @@ information on the pattern matching. As mentioned in [Define
Lints](defining_lints.md#lint-types), the `methods` lint type is full of pattern
matching with `MethodCall` in case the reader wishes to explore more.
New symbols such as `our_fancy_method` need to be added to the `clippy_utils::sym` module.
This module extends the list of symbols already provided by the compiler crates
in `rustc_span::sym`.
## Checking if a `impl` block implements a method
While sometimes we want to check whether a method is being called or not, other
@@ -56,11 +60,10 @@ Let us take a look at how we might check for the implementation of
`our_fancy_method` on a type:
```rust
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::return_ty;
use clippy_utils::{return_ty, sym};
use clippy_utils::res::MaybeDef;
use rustc_hir::{ImplItem, ImplItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_span::symbol::sym;
impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
@@ -71,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
// We can also check it has a parameter `self`
&& signature.decl.implicit_self.has_implicit_self()
// We can go even further and even check if its return type is `String`
&& is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::String)
&& return_ty(cx, impl_item.hir_id).is_diag_item(cx, sym::String)
{
println!("`our_fancy_method` is implemented!");
}
+5 -4
View File
@@ -17,10 +17,10 @@ providing the `LateContext` (`cx`), our expression at hand, and
the symbol of the trait in question:
```rust
use clippy_utils::sym;
use clippy_utils::ty::implements_trait;
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
use rustc_span::symbol::sym;
impl LateLintPass<'_> for CheckIteratorTraitLint {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -53,7 +53,7 @@ For instance, if we want to examine whether an expression `expr` implements
we can check that the `Ty` of the `expr` implements the trait:
```rust
use clippy_utils::implements_trait;
use clippy_utils::ty::implements_trait;
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
@@ -79,7 +79,8 @@ If neither diagnostic item nor a language item is available, we can use
Below, we check if the given `expr` implements [`core::iter::Step`](https://doc.rust-lang.org/std/iter/trait.Step.html):
```rust
use clippy_utils::{implements_trait, paths};
use clippy_utils::paths;
use clippy_utils::ty::implements_trait;
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
@@ -124,8 +125,8 @@ The following code demonstrates how to do this:
```rust
use rustc_middle::ty::Ty;
use clippy_utils::sym;
use clippy_utils::ty::implements_trait;
use rustc_span::symbol::sym;
let ty = todo!("Get the `Foo` type to check for a trait implementation");
let borrow_id = cx.tcx.get_diagnostic_item(sym::Borrow).unwrap(); // avoid unwrap in real code
+20
View File
@@ -671,6 +671,16 @@ A list of paths to types that should be treated as if they do not contain interi
* [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type)
## `inherent-impl-lint-scope`
Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted.
**Default Value:** `"crate"`
---
**Affected lints:**
* [`multiple_inherent_impl`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl)
## `large-error-threshold`
The maximum size of the `Err`-variant in a `Result` returned from a function
@@ -927,6 +937,16 @@ exported visibility, or whether they are marked as "pub".
* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields)
## `recursive-self-in-type-definitions`
Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.
**Default Value:** `true`
---
**Affected lints:**
* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
## `semicolon-inside-block-ignore-singleline`
Whether to lint only if it's multiline.
+12 -6
View File
@@ -1,9 +1,9 @@
use crate::ClippyConfiguration;
use crate::types::{
DisallowedPath, DisallowedPathWithoutReplacement, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour,
Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings,
SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
SourceItemOrderingWithinModuleItemGroupings,
DisallowedPath, DisallowedPathWithoutReplacement, InherentImplLintScope, MacroMatcher, MatchLintBehaviour,
PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory,
SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind,
SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings,
};
use clippy_utils::msrvs::Msrv;
use itertools::Itertools;
@@ -248,7 +248,7 @@ fn default() -> Self {
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "kebab-case")]
#[allow(non_camel_case_types)]
#[expect(non_camel_case_types)]
enum Field { $($name,)* third_party, }
struct ConfVisitor<'a>(&'a SourceFile);
@@ -663,6 +663,9 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
/// A list of paths to types that should be treated as if they do not contain interior mutability
#[lints(borrow_interior_mutable_const, declare_interior_mutable_const, ifs_same_cond, mutable_key_type)]
ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()]),
/// Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted.
#[lints(multiple_inherent_impl)]
inherent_impl_lint_scope: InherentImplLintScope = InherentImplLintScope::Crate,
/// The maximum size of the `Err`-variant in a `Result` returned from a function
#[lints(result_large_err)]
large_error_threshold: u64 = 128,
@@ -809,6 +812,9 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
/// exported visibility, or whether they are marked as "pub".
#[lints(pub_underscore_fields)]
pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported,
/// Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.
#[lints(use_self)]
recursive_self_in_type_definitions: bool = true,
/// Whether to lint only if it's multiline.
#[lints(semicolon_inside_block)]
semicolon_inside_block_ignore_singleline: bool = false,
@@ -1213,7 +1219,7 @@ fn configs_are_tested() {
for entry in toml_files {
let file = fs::read_to_string(entry.path()).unwrap();
#[allow(clippy::zero_sized_map_values)]
#[expect(clippy::zero_sized_map_values)]
if let Ok(map) = toml::from_str::<HashMap<String, IgnoredAny>>(&file) {
for name in map.keys() {
names.remove(name.as_str());
+9 -1
View File
@@ -131,7 +131,7 @@ fn allow_invalid(&self) -> bool {
}
/// Creates a map of disallowed items to the reason they were disallowed.
#[allow(clippy::type_complexity)]
#[expect(clippy::type_complexity)]
pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
tcx: TyCtxt<'_>,
disallowed_paths: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
@@ -698,3 +698,11 @@ pub enum PubUnderscoreFieldsBehaviour {
PubliclyExported,
AllPubFields,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum InherentImplLintScope {
Crate,
File,
Module,
}
+1 -1
View File
@@ -4,7 +4,7 @@
/// # Panics
///
/// Panics if unable to run the dogfood test
#[allow(clippy::fn_params_excessive_bools)]
#[expect(clippy::fn_params_excessive_bools)]
pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) {
run_exit_on_err(
"cargo test",
+1 -1
View File
@@ -192,7 +192,7 @@ enum DevCommand {
/// Which lint's page to load initially (optional)
lint: Option<String>,
},
#[allow(clippy::doc_markdown)]
#[expect(clippy::doc_markdown)]
/// Manually run clippy on a file or package
///
/// ## Examples
-1
View File
@@ -443,7 +443,6 @@ pub(super) fn check(cx: &{context_import}{pass_lifetimes}) {{
Ok(())
}
#[allow(clippy::too_many_lines)]
fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> {
let lint_name_upper = lint.name.to_uppercase();
@@ -167,7 +167,7 @@
impl_lint_pass!(ArbitrarySourceItemOrdering => [ARBITRARY_SOURCE_ITEM_ORDERING]);
#[derive(Debug)]
#[allow(clippy::struct_excessive_bools)] // Bools are cached feature flags.
#[expect(clippy::struct_excessive_bools, reason = "Bools are cached feature flags")]
pub struct ArbitrarySourceItemOrdering {
assoc_types_order: SourceItemOrderingTraitAssocItemKinds,
enable_ordering_for_enum: bool,
+3 -2
View File
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_from_proc_macro;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::res::MaybeDef;
use clippy_utils::ty::implements_trait;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
@@ -46,7 +47,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
&& let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind
&& func_name.ident.name == sym::new
&& !expr.span.from_expansion()
&& is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc)
&& cx.typeck_results().node_type(func_ty.hir_id).is_diag_item(cx, sym::Arc)
&& let arg_ty = cx.typeck_results().expr_ty(arg)
// make sure that the type is not and does not contain any type parameters
&& arg_ty.walk().all(|arg| {
@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node};
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
use clippy_utils::sym;
use clippy_utils::ty::{has_debug_impl, is_copy};
use clippy_utils::usage::local_used_after_expr;
use clippy_utils::{path_res, sym};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Expr, ExprKind, Node};
@@ -55,13 +56,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
&& let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
&& let result_type = result_type_with_refs.peel_refs()
&& is_type_diagnostic_item(cx, result_type, sym::Result)
&& result_type.is_diag_item(cx, sym::Result)
&& let ty::Adt(_, args) = result_type.kind()
{
if !is_copy(cx, result_type) {
if result_type_with_refs != result_type {
return;
} else if let Res::Local(binding_id) = path_res(cx, recv)
} else if let Res::Local(binding_id) = *recv.basic_res()
&& local_used_after_expr(cx, binding_id, recv)
{
return;
+11 -10
View File
@@ -2,8 +2,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::sugg::Sugg;
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym};
use clippy_utils::{is_in_test, last_path_segment, local_is_initialized, sym};
use rustc_errors::Applicability;
use rustc_hir::{self as hir, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -68,15 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::Assign(lhs, rhs, _) = e.kind
&& let typeck = cx.typeck_results()
&& let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind {
&& let (call_kind, fn_name, fn_def, fn_arg, fn_gen_args) = match rhs.kind {
ExprKind::Call(f, [arg])
if let ExprKind::Path(fn_path) = &f.kind
&& let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() =>
&& let Some(def) = typeck.qpath_res(fn_path, f.hir_id).opt_def(cx) =>
{
(CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id))
(CallKind::Ufcs, last_path_segment(fn_path).ident.name, def, arg, typeck.node_args(f.hir_id))
},
ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => {
(CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id))
ExprKind::MethodCall(name, recv, [], _) if let Some(def) = typeck.type_dependent_def(rhs.hir_id) => {
(CallKind::Method, name.ident.name, def, recv, typeck.node_args(rhs.hir_id))
},
_ => return,
}
@@ -84,20 +85,20 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
// Don't lint in macros.
&& ctxt.is_root()
&& let which_trait = match fn_name {
sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
sym::clone if fn_def.assoc_fn_parent(cx).is_diag_item(cx, sym::Clone) => CloneTrait::Clone,
sym::to_owned
if is_diag_trait_item(cx, fn_id, sym::ToOwned)
if fn_def.assoc_fn_parent(cx).is_diag_item(cx, sym::ToOwned)
&& self.msrv.meets(cx, msrvs::CLONE_INTO) =>
{
CloneTrait::ToOwned
},
_ => return,
}
&& let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_id, fn_gen_args)
&& let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_def.1, fn_gen_args)
// TODO: This check currently bails if the local variable has no initializer.
// That is overly conservative - the lint should fire even if there was no initializer,
// but the variable has been initialized before `lhs` was evaluated.
&& path_to_local(lhs).is_none_or(|lhs| local_is_initialized(cx, lhs))
&& lhs.res_local_id().is_none_or(|lhs| local_is_initialized(cx, lhs))
&& let Some(resolved_impl) = cx.tcx.impl_of_assoc(resolved_fn.def_id())
// Derived forms don't implement `clone_from`/`clone_into`.
// See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
+3 -4
View File
@@ -2,9 +2,10 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::higher::has_let_expr;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::ty::implements_trait;
use clippy_utils::{eq_expr_value, sym};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -431,9 +432,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
},
ExprKind::MethodCall(path, receiver, args, _) => {
let type_of_receiver = cx.typeck_results().expr_ty(receiver);
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
{
if !type_of_receiver.is_diag_item(cx, sym::Option) && !type_of_receiver.is_diag_item(cx, sym::Result) {
return None;
}
METHODS_WITH_NEGATION
+4 -3
View File
@@ -1,11 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_default_equivalent;
use clippy_utils::macros::macro_backtrace;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::ty::expr_sig;
use clippy_utils::{is_default_equivalent, path_def_id};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind};
use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LangItem, LetStmt, Node, QPath, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass;
use rustc_span::{Span, sym};
@@ -44,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
// And that method is `new`
&& seg.ident.name == sym::new
// And the call is that of a `Box` method
&& path_def_id(cx, ty).is_some_and(|id| Some(id) == cx.tcx.lang_items().owned_box())
&& ty.basic_res().is_lang_item(cx, LangItem::OwnedBox)
// And the single argument to the call is another function call
// This is the `T::default()` (or default equivalent) of `Box::new(T::default())`
&& let ExprKind::Call(arg_path, _) = arg.kind
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{expr_or_init, is_path_diagnostic_item, std_or_core, sym};
use clippy_utils::{expr_or_init, std_or_core, sym};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind};
@@ -53,7 +54,7 @@ fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) ->
fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool {
if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind
&& is_path_diagnostic_item(cx, fun, sym::mem_align_of)
&& fun.basic_res().is_diag_item(cx, sym::mem_align_of)
&& let Some(args) = path.segments.last().and_then(|seg| seg.args)
&& let [GenericArg::Type(generic_ty)] = args.args
{
+4 -3
View File
@@ -1,8 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal::NumericLiteral;
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::{SpanRangeExt, snippet_opt};
use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias};
use rustc_ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -167,11 +168,11 @@ fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
sym::assert_ne_macro,
sym::debug_assert_ne_macro,
];
matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if
matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if
cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym)))
}
if let Some(id) = path_to_local(cast_expr)
if let Some(id) = cast_expr.res_local_id()
&& !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span)
{
// Binding context is different than the identifiers context.
+3 -2
View File
@@ -1,9 +1,10 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use clippy_utils::sugg::Sugg;
use clippy_utils::visitors::is_const_evaluatable;
use clippy_utils::{is_in_const_context, is_mutable, is_trait_method};
use clippy_utils::{is_in_const_context, is_mutable};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -73,7 +74,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
// check for clones
&& let ExprKind::MethodCall(_, val, _, _) = item.kind
&& is_trait_method(cx, item, sym::Clone)
&& cx.ty_based_def(item).opt_parent(cx).is_diag_item(cx, sym::Clone)
// check for immutability or purity
&& (!is_mutable(cx, val) || is_const_evaluatable(cx, val))
+2 -2
View File
@@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::{IntoSpan, SpanRangeExt};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{LimitStack, get_async_fn_body, sym};
use core::ops::ControlFlow;
@@ -93,7 +93,7 @@ fn check<'tcx>(
});
let ret_ty = cx.typeck_results().node_type(expr.hir_id);
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) {
let ret_adjust = if ret_ty.is_diag_item(cx, sym::Result) {
returns
} else {
#[expect(clippy::integer_division)]
+7 -7
View File
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
use clippy_utils::get_enclosing_block;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::visitors::{Visitable, for_each_expr};
use clippy_utils::{get_enclosing_block, path_to_local_id};
use core::ops::ControlFlow;
use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -59,7 +59,7 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
let ty = cx.typeck_results().pat_ty(local.pat);
matches!(
get_type_diagnostic_name(cx, ty),
ty.opt_diag_name(cx),
Some(
sym::BTreeMap
| sym::BTreeSet
@@ -71,7 +71,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
| sym::Vec
| sym::VecDeque
)
) || is_type_lang_item(cx, ty, LangItem::String)
) || ty.is_lang_item(cx, LangItem::String)
}
fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool {
@@ -81,7 +81,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
// Inspect all expressions and sub-expressions in the block.
for_each_expr(cx, block, |expr| {
// Ignore expressions that are not simply `id`.
if !path_to_local_id(expr, id) {
if expr.res_local_id() != Some(id) {
return ControlFlow::Continue(());
}
@@ -93,7 +93,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
// id = ...; // Not reading `id`.
if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
&& let ExprKind::Assign(lhs, ..) = parent.kind
&& path_to_local_id(lhs, id)
&& lhs.res_local_id() == Some(id)
{
return ControlFlow::Continue(());
}
@@ -107,7 +107,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
// have side effects, so consider them a read.
if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
&& let ExprKind::MethodCall(_, receiver, args, _) = parent.kind
&& path_to_local_id(receiver, id)
&& receiver.res_local_id() == Some(id)
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& !method_def_id.is_local()
{
+3
View File
@@ -488,6 +488,7 @@
crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
crate::methods::UNNECESSARY_MAP_OR_INFO,
crate::methods::UNNECESSARY_MIN_OR_MAX_INFO,
crate::methods::UNNECESSARY_OPTION_MAP_OR_ELSE_INFO,
crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
crate::methods::UNNECESSARY_SORT_BY_INFO,
crate::methods::UNNECESSARY_TO_OWNED_INFO,
@@ -655,6 +656,7 @@
crate::regex::REGEX_CREATION_IN_LOOPS_INFO,
crate::regex::TRIVIAL_REGEX_INFO,
crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO,
crate::replace_box::REPLACE_BOX_INFO,
crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
crate::returns::LET_AND_RETURN_INFO,
@@ -780,6 +782,7 @@
crate::visibility::NEEDLESS_PUB_SELF_INFO,
crate::visibility::PUB_WITHOUT_SHORTHAND_INFO,
crate::visibility::PUB_WITH_SHORTHAND_INFO,
crate::volatile_composites::VOLATILE_COMPOSITES_INFO,
crate::wildcard_imports::ENUM_GLOB_USE_INFO,
crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
crate::write::PRINTLN_EMPTY_STRING_INFO,
-1
View File
@@ -7,7 +7,6 @@ macro_rules! declare_with_version {
$e:expr,
)*]) => {
pub static $name: &[(&str, &str)] = &[$($e),*];
#[allow(unused)]
pub static $name_version: &[&str] = &[$($version),*];
};
}
+2 -2
View File
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop, peel_and_count_ty_refs};
use clippy_utils::{
DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_from_proc_macro, is_lint_allowed,
path_to_local,
};
use rustc_ast::util::parser::ExprPrecedence;
use rustc_data_structures::fx::FxIndexMap;
@@ -239,7 +239,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
return;
}
if let Some(local) = path_to_local(expr) {
if let Some(local) = expr.res_local_id() {
self.check_local_usage(cx, expr, local);
}
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::fulfill_or_allowed;
use clippy_utils::ty::{implements_trait, is_copy};
use rustc_hir::{self as hir, HirId, Item};
use rustc_lint::LateContext;
@@ -60,14 +61,16 @@ pub(super) fn check<'tcx>(
return;
}
span_lint_hir_and_then(
if fulfill_or_allowed(cx, EXPL_IMPL_CLONE_ON_COPY, [adt_hir_id]) {
return;
}
span_lint_and_help(
cx,
EXPL_IMPL_CLONE_ON_COPY,
adt_hir_id,
item.span,
"you are implementing `Clone` explicitly on a `Copy` type",
|diag| {
diag.span_help(item.span, "consider deriving `Clone` or removing `Copy`");
},
None,
"consider deriving `Clone` or removing `Copy`",
);
}
+2 -2
View File
@@ -1,4 +1,4 @@
use clippy_utils::path_res;
use clippy_utils::res::MaybeResPath;
use rustc_hir::def::Res;
use rustc_hir::{Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -199,7 +199,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
self_ty,
..
}) = item.kind
&& let Res::Def(_, def_id) = path_res(cx, self_ty)
&& let Res::Def(_, def_id) = *self_ty.basic_res()
&& let Some(local_def_id) = def_id.as_local()
{
let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+5 -7
View File
@@ -1,7 +1,8 @@
use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item};
use clippy_utils::res::MaybeDef;
use clippy_utils::ty::implements_trait_with_env;
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{fulfill_or_allowed, is_doc_hidden, is_inside_always_const_context, method_chain_args, return_ty};
use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
@@ -62,7 +63,7 @@ pub fn check(
);
}
if !headers.errors {
if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
if return_ty(cx, owner_id).is_diag_item(cx, sym::Result) {
span_lint(
cx,
MISSING_ERRORS_DOC,
@@ -83,7 +84,7 @@ pub fn check(
&[],
)
&& let ty::Coroutine(_, subs) = ret_ty.kind()
&& is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
&& subs.as_coroutine().return_ty().is_diag_item(cx, sym::Result)
{
span_lint(
cx,
@@ -119,10 +120,7 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
if let Some(arglists) =
method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect]))
&& let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs()
&& matches!(
get_type_diagnostic_name(cx, receiver_ty),
Some(sym::Option | sym::Result)
)
&& matches!(receiver_ty.opt_diag_name(cx), Some(sym::Option | sym::Result))
&& !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id])
&& panic_span.is_none()
{
+1 -1
View File
@@ -970,7 +970,7 @@ fn check_for_code_clusters<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a
/// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`,
/// so lints here will generally access that information.
/// Returns documentation headers -- whether a "Safety", "Errors", "Panic" section was found
#[allow(clippy::too_many_lines)] // Only a big match statement
#[expect(clippy::too_many_lines, reason = "big match statement")]
fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
cx: &LateContext<'_>,
valid_idents: &FxHashSet<String>,
+3 -2
View File
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_must_use_func_call;
use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
use clippy_utils::res::MaybeDef;
use clippy_utils::ty::{is_copy, is_must_use_ty};
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
@@ -97,7 +98,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
sym::mem_forget if arg_ty.is_ref() => return,
sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
sym::mem_forget if is_copy => return,
sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => return,
sym::mem_drop if arg_ty.is_lang_item(cx, LangItem::ManuallyDrop) => return,
sym::mem_drop
if !(arg_ty.needs_drop(cx.tcx, cx.typing_env())
|| is_must_use_func_call(cx, arg)
+2 -2
View File
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
use clippy_utils::path_res;
use clippy_utils::res::MaybeResPath;
use clippy_utils::ty::implements_trait;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{Item, ItemKind};
@@ -55,7 +55,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_ref.trait_def_id())
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
&& error_def_id == trait_def_id
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
&& let Some(def_id) = imp.self_ty.basic_res().opt_def_id().and_then(DefId::as_local)
&& let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
&& ident.name == sym::Error
&& is_visible_outside_module(cx, def_id) =>
+6 -8
View File
@@ -1,11 +1,9 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::higher::VecArgs;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::ty::get_type_diagnostic_name;
use clippy_utils::usage::{local_used_after_expr, local_used_in};
use clippy_utils::{
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
};
use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate};
use rustc_abi::ExternAbi;
use rustc_errors::Applicability;
use rustc_hir::attrs::AttributeKind;
@@ -86,7 +84,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
}
}
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
let body = if let ExprKind::Closure(c) = expr.kind
&& c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(())))
@@ -144,7 +142,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
{
let callee_ty_raw = typeck.expr_ty(callee);
let callee_ty = callee_ty_raw.peel_refs();
if matches!(get_type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
if matches!(callee_ty.opt_diag_name(cx), Some(sym::Arc | sym::Rc))
|| !check_inputs(typeck, body.params, None, args)
{
return;
@@ -218,7 +216,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
"redundant closure",
|diag| {
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
if path_to_local(callee).is_some_and(|l| {
if callee.res_local_id().is_some_and(|l| {
// FIXME: Do we really need this `local_used_in` check?
// Isn't it checking something like... `callee(callee)`?
// If somehow this check is needed, add some test for it,
@@ -307,7 +305,7 @@ fn check_inputs(
matches!(
p.pat.kind,
PatKind::Binding(BindingMode::NONE, id, _, None)
if path_to_local_id(arg, id)
if arg.res_local_id() == Some(id)
)
// Only allow adjustments which change regions (i.e. re-borrowing).
&& typeck
+8 -2
View File
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span};
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_expn_of, path_def_id, sym};
use clippy_utils::{is_expn_of, is_in_test, sym};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
@@ -59,7 +60,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&& let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind)
&& let ExprKind::Call(write_recv_path, []) = write_recv.kind
&& write_fun.ident.name == sym::write_fmt
&& let Some(def_id) = path_def_id(cx, write_recv_path)
&& let Some(def_id) = write_recv_path.basic_res().opt_def_id()
{
// match calls to std::io::stdout() / std::io::stderr ()
let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) {
@@ -71,6 +72,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
return;
};
// Performing an explicit write in a test circumvent's libtest's capture of stdio and stdout.
if is_in_test(cx.tcx, expr.hir_id) {
return;
}
// ordering is important here, since `writeln!` uses `write!` internally
let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() {
Some("writeln")
+2 -4
View File
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
use clippy_utils::method_chain_args;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::res::MaybeDef;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
@@ -84,9 +84,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) {
let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{
if receiver_ty.is_diag_item(self.lcx, sym::Option) || receiver_ty.is_diag_item(self.lcx, sym::Result) {
self.result.push(expr.span);
}
}
@@ -1,9 +1,10 @@
use clippy_utils::consts::Constant::{F32, F64, Int};
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use clippy_utils::{
eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context,
is_inherent_method_call, is_no_std_crate, numeric_literal, peel_blocks, sugg, sym,
eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context, is_no_std_crate,
numeric_literal, peel_blocks, sugg, sym,
};
use rustc_ast::ast;
use rustc_errors::Applicability;
@@ -737,7 +738,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
let recv_ty = cx.typeck_results().expr_ty(receiver);
if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) {
if recv_ty.is_floating_point() && !is_no_std_crate(cx) && cx.ty_based_def(expr).opt_parent(cx).is_impl(cx) {
match path.ident.name {
sym::ln => check_ln1p(cx, expr, receiver),
sym::log => check_log_base(cx, expr, receiver, args),
-1
View File
@@ -39,7 +39,6 @@
"useless use of `format!`"
}
#[allow(clippy::module_name_repetitions)]
pub struct UselessFormat {
format_args: FormatArgsStorage,
}
+10 -6
View File
@@ -9,9 +9,10 @@
root_macro_call_first_node,
};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::{SpanRangeExt, snippet};
use clippy_utils::ty::{implements_trait, is_type_lang_item};
use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test, trait_ref_of_method};
use clippy_utils::ty::implements_trait;
use clippy_utils::{is_from_proc_macro, is_in_test, trait_ref_of_method};
use itertools::Itertools;
use rustc_ast::{
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
@@ -237,7 +238,7 @@
POINTER_FORMAT,
]);
#[allow(clippy::struct_field_names)]
#[expect(clippy::struct_field_names)]
pub struct FormatArgs<'tcx> {
format_args: FormatArgsStorage,
msrv: Msrv,
@@ -344,7 +345,7 @@ fn check_unused_format_specifier(&self, placeholder: &FormatPlaceholder, arg: &E
if let Some(placeholder_span) = placeholder.span
&& *options != FormatOptions::default()
&& let ty = self.cx.typeck_results().expr_ty(arg).peel_refs()
&& is_type_lang_item(self.cx, ty, LangItem::FormatArguments)
&& ty.is_lang_item(self.cx, LangItem::FormatArguments)
{
span_lint_and_then(
self.cx,
@@ -497,8 +498,11 @@ fn check_to_string_in_format_args(&self, name: Symbol, value: &Expr<'_>) {
let cx = self.cx;
if !value.span.from_expansion()
&& let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
&& is_diag_trait_item(cx, method_def_id, sym::ToString)
&& cx
.typeck_results()
.type_dependent_def_id(value.hir_id)
.opt_parent(cx)
.is_diag_item(cx, sym::ToString)
&& let receiver_ty = cx.typeck_results().expr_ty(receiver)
&& let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display)
&& let (n_needed_derefs, target) =
+9 -4
View File
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node};
use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators, sym};
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::{get_parent_as_impl, peel_ref_operators, sym};
use rustc_ast::{FormatArgsPiece, FormatTrait};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
@@ -157,8 +158,12 @@ fn check_to_string_in_display(&self) {
&& path.ident.name == sym::to_string
// Is the method a part of the ToString trait? (i.e. not to_string() implemented
// separately)
&& let Some(expr_def_id) = self.cx.typeck_results().type_dependent_def_id(self.expr.hir_id)
&& is_diag_trait_item(self.cx, expr_def_id, sym::ToString)
&& self
.cx
.typeck_results()
.type_dependent_def_id(self.expr.hir_id)
.opt_parent(self.cx)
.is_diag_item(self.cx, sym::ToString)
// Is the method is called on self
&& let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind
&& let [segment] = path.segments
@@ -210,7 +215,7 @@ fn check_format_arg_self(&self, arg: &Expr<'_>) {
// Since the argument to fmt is itself a reference: &self
let reference = peel_ref_operators(self.cx, arg);
// Is the reference self?
if path_to_local(reference).map(|x| self.cx.tcx.hir_name(x)) == Some(kw::SelfLower) {
if reference.res_local_id().map(|x| self.cx.tcx.hir_name(x)) == Some(kw::SelfLower) {
let FormatTraitNames { name, .. } = self.format_trait_impl;
span_lint(
self.cx,
+5 -2
View File
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::res::MaybeDef;
use rustc_hir::{AssignOpKind, Expr, ExprKind, LangItem, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
@@ -41,7 +41,10 @@
declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
cx.typeck_results()
.expr_ty(e)
.peel_refs()
.is_lang_item(cx, LangItem::String)
}
fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
let e = e.peel_blocks().peel_borrows();
+7 -2
View File
@@ -4,7 +4,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::path_def_id;
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_path};
@@ -90,7 +90,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|diag| {
// If the target type is likely foreign mention the orphan rules as it's a common source of
// confusion
if path_def_id(cx, target_ty.peel_refs()).is_none_or(|id| !id.is_local()) {
if target_ty
.peel_refs()
.basic_res()
.opt_def_id()
.is_none_or(|id| !id.is_local())
{
diag.help(
"`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
+3 -2
View File
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::res::MaybeResPath;
use clippy_utils::sym;
use clippy_utils::ty::is_c_void;
use clippy_utils::{path_def_id, sym};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
@@ -41,7 +42,7 @@ 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 Some(type_str) = ty.basic_res().opt_def_id().and_then(|id| def_id_matches_type(cx, id))
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
&& let ty::RawPtr(ty, _) = arg_kind
&& is_c_void(cx, *ty)
+2 -2
View File
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::MaybeDef;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{is_in_const_context, is_integer_literal, sym};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def};
@@ -89,5 +89,5 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
/// Checks if a Ty is `String` or `&str`
fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
is_type_lang_item(cx, ty, LangItem::String) || ty.peel_refs().is_str()
ty.is_lang_item(cx, LangItem::String) || ty.peel_refs().is_str()
}
+1 -1
View File
@@ -132,7 +132,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
}
// FIXME: needs to be an EARLY LINT. all attribute lints should be
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
fn check_needless_must_use(
cx: &LateContext<'_>,
decl: &hir::FnDecl<'_>,
@@ -1,12 +1,13 @@
use clippy_utils::res::MaybeResPath;
use rustc_hir::{self as hir, HirId, HirIdSet, intravisit};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::def_id::LocalDefId;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::iter_input_pats;
use clippy_utils::ty::is_unsafe_fn;
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{iter_input_pats, path_to_local};
use core::ops::ControlFlow;
@@ -87,7 +88,7 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<HirId> {
}
fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) {
if path_to_local(arg).is_some_and(|id| raw_ptrs.contains(&id)) {
if arg.res_local_id().is_some_and(|id| raw_ptrs.contains(&id)) {
span_lint(
cx,
NOT_UNSAFE_PTR_ARG_DEREF,
+1 -1
View File
@@ -62,7 +62,7 @@ fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty
}
}
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
pub(crate) fn check_fn<'a>(
cx: &LateContext<'a>,
kind: FnKind<'a>,
+3 -2
View File
@@ -1,4 +1,5 @@
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use rustc_errors::Diag;
use rustc_hir as hir;
use rustc_lint::{LateContext, LintContext};
@@ -6,7 +7,7 @@
use rustc_span::{Span, sym};
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item};
use clippy_utils::ty::{AdtVariantInfo, approx_ty_size};
use clippy_utils::{is_no_std_crate, trait_ref_of_method};
use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
@@ -24,7 +25,7 @@ fn result_err_ty<'tcx>(
&& let ty = cx
.tcx
.instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output())
&& is_type_diagnostic_item(cx, ty, sym::Result)
&& ty.is_diag_item(cx, sym::Result)
&& let ty::Adt(_, args) = ty.kind()
{
let err_ty = args.type_at(1);
+2 -2
View File
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::res::MaybeDef;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{eq_expr_value, higher, sym};
use core::ops::ControlFlow;
@@ -95,7 +95,7 @@ fn mutex_lock_call<'tcx>(
if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind
&& path.ident.name == sym::lock
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
&& is_type_diagnostic_item(cx, ty, sym::Mutex)
&& ty.is_diag_item(cx, sym::Mutex)
&& op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op))
{
ControlFlow::Break(self_arg)
+4 -4
View File
@@ -2,11 +2,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeDef, MaybeQPath};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
use clippy_utils::sugg::Sugg;
use clippy_utils::{
contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor,
path_res, peel_blocks, sym,
contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, peel_blocks, sym,
};
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -73,8 +73,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
&& !expr.span.from_expansion()
&& !then_expr.span.from_expansion()
&& is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
&& is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
&& then_call.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
&& peel_blocks(els).res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
&& !is_else_clause(cx.tcx, expr)
&& !is_in_const_context(cx)
&& self.msrv.meets(cx, msrvs::BOOL_THEN)
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
use clippy_utils::ty::needs_ordered_drop;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{
ContainsName, HirEqInterExpr, SpanlessEq, capture_local_usage, get_enclosing_block, hash_expr, hash_stmt,
path_to_local,
};
use core::iter;
use core::ops::ControlFlow;
@@ -149,7 +149,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool {
/// Checks if the statement modifies or moves any of the given locals.
fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: &HirIdSet) -> bool {
for_each_expr_without_closures(s, |e| {
if let Some(id) = path_to_local(e)
if let Some(id) = e.res_local_id()
&& locals.contains(&id)
&& !capture_local_usage(cx, e).is_imm_ref()
{
@@ -198,7 +198,7 @@ fn scan_block_for_eq<'tcx>(
let mut cond_locals = HirIdSet::default();
for &cond in conds {
let _: Option<!> = for_each_expr_without_closures(cond, |e| {
if let Some(id) = path_to_local(e) {
if let Some(id) = e.res_local_id() {
cond_locals.insert(id);
}
ControlFlow::Continue(())
+3 -2
View File
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::res::MaybeResPath;
use clippy_utils::ty::InteriorMut;
use clippy_utils::{SpanlessEq, eq_expr_value, find_binding_init, hash_expr, path_to_local, search_same};
use clippy_utils::{SpanlessEq, eq_expr_value, find_binding_init, hash_expr, search_same};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
@@ -16,7 +17,7 @@ fn method_caller_is_mutable<'tcx>(
interior_mut.is_interior_mut_ty(cx, caller_ty)
|| caller_ty.is_mutable_ptr()
// `find_binding_init` will return the binding iff its not mutable
|| path_to_local(caller_expr)
|| caller_expr.res_local_id()
.and_then(|hid| find_binding_init(cx, hid))
.is_none()
}
+3 -3
View File
@@ -1,6 +1,7 @@
use std::borrow::Cow;
use std::collections::BTreeMap;
use clippy_utils::res::MaybeDef;
use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_body, walk_expr, walk_ty};
use rustc_hir::{self as hir, AmbigArg, Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
@@ -14,7 +15,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
use clippy_utils::sym;
use clippy_utils::ty::is_type_diagnostic_item;
declare_clippy_lint! {
/// ### What it does
@@ -227,14 +227,14 @@ fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Option<Self> {
let ty = lower_ty(cx.tcx, hir_ty);
if is_type_diagnostic_item(cx, ty, sym::HashMap) && params_len == 2 {
if ty.is_diag_item(cx, sym::HashMap) && params_len == 2 {
Some(ImplicitHasherType::HashMap(
hir_ty.span,
ty,
snippet(cx, params[0].span, "K"),
snippet(cx, params[1].span, "V"),
))
} else if is_type_diagnostic_item(cx, ty, sym::HashSet) && params_len == 1 {
} else if ty.is_diag_item(cx, sym::HashSet) && params_len == 1 {
Some(ImplicitHasherType::HashSet(
hir_ty.span,
ty,
+3 -3
View File
@@ -112,7 +112,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
}
}
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
fn check_manual_check<'tcx>(
cx: &LateContext<'tcx>,
expr: &Expr<'tcx>,
@@ -165,7 +165,7 @@ fn check_manual_check<'tcx>(
}
}
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
fn check_gt(
cx: &LateContext<'_>,
condition_span: Span,
@@ -196,7 +196,7 @@ fn is_side_effect_free(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
eq_expr_value(cx, expr, expr)
}
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
fn check_subtraction(
cx: &LateContext<'_>,
condition_span: Span,
+3 -2
View File
@@ -2,9 +2,10 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet;
use clippy_utils::is_lint_allowed;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeResPath;
use clippy_utils::ty::is_copy;
use clippy_utils::{is_lint_allowed, path_to_local};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -225,7 +226,7 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if let Some(local_id) = path_to_local(expr) {
if let Some(local_id) = expr.res_local_id() {
let Self {
cx,
ref mut slice_lint_info,
+6 -2
View File
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{peel_blocks, peel_hir_expr_while, sym};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
@@ -47,7 +47,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(name, recv, [_], _) = expr.kind
&& name.ident.name == sym::open
&& !expr.span.from_expansion()
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::FsOpenOptions)
&& cx
.typeck_results()
.expr_ty(recv)
.peel_refs()
.is_diag_item(cx, sym::FsOpenOptions)
{
let mut append = false;
let mut write = None;
+3 -2
View File
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
use clippy_utils::res::MaybeDef;
use clippy_utils::ty::implements_trait;
use clippy_utils::{higher, sym};
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -235,7 +236,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
} else if method.ident.name == sym::collect {
let ty = cx.typeck_results().expr_ty(expr);
if matches!(
get_type_diagnostic_name(cx, ty),
ty.opt_diag_name(cx),
Some(
sym::BinaryHeap
| sym::BTreeMap
+44 -11
View File
@@ -1,17 +1,23 @@
use clippy_config::Conf;
use clippy_config::types::InherentImplLintScope;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_lint_allowed;
use clippy_utils::fulfill_or_allowed;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::{Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use rustc_session::impl_lint_pass;
use rustc_span::{FileName, Span};
use std::collections::hash_map::Entry;
declare_clippy_lint! {
/// ### What it does
/// Checks for multiple inherent implementations of a struct
///
/// The config option controls the scope in which multiple inherent `impl` blocks for the same
/// struct are linted, allowing values of `module` (only within the same module), `file`
/// (within the same file), or `crate` (anywhere in the crate, default).
///
/// ### Why restrict this?
/// Splitting the implementation of a type makes the code harder to navigate.
///
@@ -41,7 +47,26 @@
"Multiple inherent impl that could be grouped"
}
declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
pub struct MultipleInherentImpl {
scope: InherentImplLintScope,
}
impl MultipleInherentImpl {
pub fn new(conf: &'static Conf) -> Self {
Self {
scope: conf.inherent_impl_lint_scope,
}
}
}
#[derive(Hash, Eq, PartialEq, Clone)]
enum Criterion {
Module(LocalModDefId),
File(FileName),
Crate,
}
impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
@@ -55,18 +80,27 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
for (&id, impl_ids) in &impls.inherent_impls {
if impl_ids.len() < 2
// Check for `#[allow]` on the type definition
|| is_lint_allowed(
// Check for `#[expect]` or `#[allow]` on the type definition
|| fulfill_or_allowed(
cx,
MULTIPLE_INHERENT_IMPL,
cx.tcx.local_def_id_to_hir_id(id),
[cx.tcx.local_def_id_to_hir_id(id)],
) {
continue;
}
for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity();
match type_map.entry(impl_ty) {
let hir_id = cx.tcx.local_def_id_to_hir_id(impl_id);
let criterion = match self.scope {
InherentImplLintScope::Module => Criterion::Module(cx.tcx.parent_module(hir_id)),
InherentImplLintScope::File => {
let span = cx.tcx.hir_span(hir_id);
Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone())
},
InherentImplLintScope::Crate => Criterion::Crate,
};
match type_map.entry((impl_ty, criterion)) {
Entry::Vacant(e) => {
// Store the id for the first impl block of this type. The span is retrieved lazily.
e.insert(IdOrSpan::Id(impl_id));
@@ -97,7 +131,6 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
// Switching to the next type definition, no need to keep the current entries around.
type_map.clear();
}
// `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
lint_spans.sort_by_key(|x| x.0.lo());
for (span, first_span) in lint_spans {
@@ -125,7 +158,7 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
{
(!span.from_expansion()
&& impl_item.generics.params.is_empty()
&& !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
&& !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id]))
.then_some(span)
} else {
None
+3 -2
View File
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{implements_trait, is_type_lang_item};
use clippy_utils::res::MaybeDef;
use clippy_utils::ty::implements_trait;
use clippy_utils::{return_ty, trait_ref_of_method};
use rustc_abi::ExternAbi;
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
@@ -104,7 +105,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
&& impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
&& !impl_item.span.from_expansion()
// Check if return type is String
&& is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
&& return_ty(cx, impl_item.owner_id).is_lang_item(cx, LangItem::String)
// Filters instances of to_string which are required by a trait
&& trait_ref_of_method(cx, impl_item.owner_id).is_none()
{
+2 -4
View File
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::higher::ForLoop;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::res::MaybeDef;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
@@ -55,9 +55,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
if let Some(for_loop) = ForLoop::hir(expr)
&& !for_loop.body.span.from_expansion()
&& let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs()
&& hash_iter_tys
.into_iter()
.any(|sym| is_type_diagnostic_item(cx, ty, sym))
&& hash_iter_tys.into_iter().any(|sym| ty.is_diag_item(cx, sym))
{
span_lint(
cx,
+7 -23
View File
@@ -113,35 +113,18 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
// since this would only require removing a `use` import (which is already linted).
&& !is_numeric_const_path_canonical(path, [*mod_name, *name])
{
(
vec![(expr.span, format!("{mod_name}::{name}"))],
"usage of a legacy numeric constant",
)
(format!("{mod_name}::{name}"), "usage of a legacy numeric constant")
// `<integer>::xxx_value` check
} else if let ExprKind::Call(func, []) = &expr.kind
&& let ExprKind::Path(qpath) = &func.kind
&& let QPath::TypeRelative(ty, last_segment) = qpath
&& let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
&& is_integer_method(cx, def_id)
&& let Some(mod_name) = ty.span.get_source_text(cx)
&& ty.span.eq_ctxt(last_segment.ident.span)
{
let mut sugg = vec![
// Replace the function name up to the end by the constant name
(
last_segment.ident.span.to(expr.span.shrink_to_hi()),
last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(),
),
];
let before_span = expr.span.shrink_to_lo().until(ty.span);
if !before_span.is_empty() {
// Remove everything before the type name
sugg.push((before_span, String::new()));
}
// Use `::` between the type name and the constant
let between_span = ty.span.shrink_to_hi().until(last_segment.ident.span);
if !between_span.check_source_text(cx, |s| s == "::") {
sugg.push((between_span, String::from("::")));
}
(sugg, "usage of a legacy numeric method")
let name = last_segment.ident.name.as_str()[..=2].to_ascii_uppercase();
(format!("{mod_name}::{name}"), "usage of a legacy numeric method")
} else {
return;
};
@@ -151,7 +134,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
&& !is_from_proc_macro(cx, expr)
{
span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.span, msg, |diag| {
diag.multipart_suggestion_verbose(
diag.span_suggestion_verbose(
expr.span,
"use the associated constant instead",
sugg,
Applicability::MaybeIncorrect,
+3 -4
View File
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use clippy_utils::source::{SpanRangeExt, snippet_with_context};
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
use clippy_utils::ty::implements_trait;
use clippy_utils::{
fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym,
};
use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, parent_item_name, peel_ref_operators, sym};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -204,7 +203,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
if let ExprKind::MethodCall(method, lhs_expr, [rhs_expr], _) = expr.kind
&& is_trait_method(cx, expr, sym::PartialEq)
&& cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::PartialEq)
&& !expr.span.from_expansion()
{
check_empty_expr(
+2 -2
View File
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::path_to_local_id;
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::snippet;
use clippy_utils::visitors::is_local_used;
use rustc_errors::Applicability;
@@ -145,7 +145,7 @@ fn check_assign<'tcx>(
&& let Some(expr) = block.stmts.iter().last()
&& let hir::StmtKind::Semi(expr) = expr.kind
&& let hir::ExprKind::Assign(var, value, _) = expr.kind
&& path_to_local_id(var, decl)
&& var.res_local_id() == Some(decl)
{
if block
.stmts
+7 -3
View File
@@ -318,6 +318,7 @@
mod reference;
mod regex;
mod repeat_vec_with_capacity;
mod replace_box;
mod reserve_after_initialization;
mod return_self_not_must_use;
mod returns;
@@ -394,6 +395,7 @@
mod vec;
mod vec_init_then_push;
mod visibility;
mod volatile_composites;
mod wildcard_imports;
mod write;
mod zero_div_zero;
@@ -581,7 +583,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
store.register_late_pass(move |_| Box::new(inherent_impl::MultipleInherentImpl::new(conf)));
store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
store.register_late_pass(move |_| Box::new(unwrap::Unwrap::new(conf)));
store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
@@ -612,7 +614,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements));
store.register_early_pass(|| Box::new(precedence::Precedence));
store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
store.register_late_pass(|_| Box::new(needless_continue::NeedlessContinue));
store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
store.register_late_pass(|_| Box::new(create_dir::CreateDir));
store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
@@ -758,7 +760,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(conf)));
store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
store.register_late_pass(move |_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(conf)));
store.register_late_pass(|_| Box::new(non_canonical_impls::NonCanonicalImpls));
store.register_late_pass(|tcx| Box::new(non_canonical_impls::NonCanonicalImpls::new(tcx)));
store.register_late_pass(move |_| Box::new(single_call_fn::SingleCallFn::new(conf)));
store.register_early_pass(move || Box::new(raw_strings::RawStrings::new(conf)));
store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(conf)));
@@ -825,5 +827,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
store.register_late_pass(|_| Box::new(toplevel_ref_arg::ToplevelRefArg));
store.register_late_pass(|_| Box::new(volatile_composites::VolatileComposites));
store.register_late_pass(|_| Box::new(replace_box::ReplaceBox));
// add lints here, do not remove this comment, it's used in `new_lint`
}
+2 -2
View File
@@ -184,7 +184,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
}
}
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
fn check_fn_inner<'tcx>(
cx: &LateContext<'tcx>,
sig: &'tcx FnSig<'_>,
@@ -540,7 +540,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
false
}
#[allow(clippy::struct_excessive_bools)]
#[expect(clippy::struct_excessive_bools)]
struct Usage {
lifetime: Lifetime,
in_where_predicate: bool,
+15 -7
View File
@@ -1,8 +1,8 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym};
use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
use clippy_utils::sym;
use rustc_errors::Applicability;
use rustc_hir::{Body, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -73,10 +73,13 @@ pub fn new(conf: &Conf) -> Self {
impl LateLintPass<'_> for LinesFilterMapOk {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
&& is_trait_method(cx, expr, sym::Iterator)
&& cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
&& let fm_method_name = fm_method.ident.name
&& matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
&& cx
.typeck_results()
.expr_ty_adjusted(fm_receiver)
.is_diag_item(cx, sym::IoLines)
&& should_lint(cx, fm_args, fm_method_name)
&& self.msrv.meets(cx, msrvs::MAP_WHILE)
{
@@ -117,10 +120,15 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) ->
params: [param], value, ..
} = cx.tcx.hir_body(*body)
&& let ExprKind::MethodCall(method, receiver, [], _) = value.kind
&& path_to_local_id(receiver, param.pat.hir_id)
&& let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
{
is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok
method.ident.name == sym::ok
&& receiver.res_local_id() == Some(param.pat.hir_id)
&& cx
.typeck_results()
.type_dependent_def_id(value.hir_id)
.opt_parent(cx)
.opt_impl_ty(cx)
.is_diag_item(cx, sym::Result)
} else {
false
}
@@ -1,9 +1,9 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym};
use clippy_utils::{eq_expr_value, higher, sym};
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind};
use rustc_lint::LateContext;
@@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
{
// Destructured iterator element `(idx, _)`, look for uses of the binding
for_each_expr(cx, body, |expr| {
if path_to_local_id(expr, binding_id) {
if expr.res_local_id() == Some(binding_id) {
check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
}
CONTINUE
@@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
// Bound as a tuple, look for `tup.0`
for_each_expr(cx, body, |expr| {
if let ExprKind::Field(e, field) = expr.kind
&& path_to_local_id(e, binding_id)
&& e.res_local_id() == Some(binding_id)
&& field.name == sym::integer(0)
{
check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
@@ -81,7 +81,7 @@ fn check_index_usage<'tcx>(
return;
};
let is_string_like = |ty: Ty<'_>| ty.is_str() || is_type_lang_item(cx, ty, LangItem::String);
let is_string_like = |ty: Ty<'_>| ty.is_str() || ty.is_lang_item(cx, LangItem::String);
let message = match parent_expr.kind {
ExprKind::MethodCall(segment, recv, ..)
// We currently only lint `str` methods (which `String` can deref to), so a `.is_str()` check is sufficient here
@@ -1,6 +1,6 @@
use super::EXPLICIT_INTO_ITER_LOOP;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use clippy_utils::source::snippet_with_context;
use rustc_errors::Applicability;
use rustc_hir::Expr;
@@ -43,7 +43,11 @@ fn display(self) -> &'static str {
}
pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) {
if !is_trait_method(cx, call_expr, sym::IntoIterator) {
if !cx
.ty_based_def(call_expr)
.opt_parent(cx)
.is_diag_item(cx, sym::IntoIterator)
{
return;
}
+3 -3
View File
@@ -1,10 +1,11 @@
use super::EXPLICIT_ITER_LOOP;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet_with_context;
use clippy_utils::sym;
use clippy_utils::ty::{
implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
implements_trait, implements_trait_with_env, is_copy, make_normalized_projection,
make_normalized_projection_with_regions, normalize_with_regions,
};
use rustc_errors::Applicability;
@@ -127,8 +128,7 @@ fn is_ref_iterable<'tcx>(
let self_ty = typeck.expr_ty(self_arg);
let self_is_copy = is_copy(cx, self_ty);
if is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox)
&& !msrv.meets(cx, msrvs::BOX_INTO_ITER)
if self_ty.peel_refs().is_lang_item(cx, rustc_hir::LangItem::OwnedBox) && !msrv.meets(cx, msrvs::BOX_INTO_ITER)
{
return None;
}
+2 -2
View File
@@ -1,7 +1,7 @@
use super::FOR_KV_MAP;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{pat_is_wild, sugg};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
_ => arg,
};
if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) {
if ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) {
span_lint_and_then(
cx,
FOR_KV_MAP,
+2 -2
View File
@@ -1,12 +1,12 @@
use super::ITER_NEXT_LOOP;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_trait_method;
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_span::sym;
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) {
if is_trait_method(cx, arg, sym::Iterator) {
if cx.ty_based_def(arg).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
span_lint(
cx,
ITER_NEXT_LOOP,
+5 -5
View File
@@ -1,12 +1,12 @@
use super::MANUAL_FIND;
use super::utils::make_iterator_snippet;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::usage::contains_return_break_continue_macro;
use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt};
use clippy_utils::{higher, peel_blocks_with_stmt};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
@@ -34,8 +34,8 @@ pub(super) fn check<'tcx>(
&& let StmtKind::Semi(semi) = stmt.kind
&& let ExprKind::Ret(Some(ret_value)) = semi.kind
&& let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind
&& is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome)
&& path_res(cx, inner_ret) == Res::Local(binding_id)
&& ctor.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
&& inner_ret.res_local_id() == Some(binding_id)
&& !contains_return_break_continue_macro(cond)
&& let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr)
{
@@ -150,7 +150,7 @@ fn extract<'tcx>(block: &Block<'tcx>) -> Option<(&'tcx Stmt<'tcx>, &'tcx Expr<'t
&& let Some((_, Node::Block(block))) = parent_iter.next()
&& let Some((last_stmt, last_ret)) = extract(block)
&& last_stmt.hir_id == node_hir
&& is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone)
&& last_ret.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionNone)
&& let Some((_, Node::Expr(_block))) = parent_iter.next()
// This includes the function header
&& let Some((_, func)) = parent_iter.next()
+3 -2
View File
@@ -2,9 +2,10 @@
use super::utils::make_iterator_snippet;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability};
use clippy_utils::visitors::is_local_used;
use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt, span_contains_comment};
use clippy_utils::{higher, is_refutable, peel_blocks_with_stmt, span_contains_comment};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, Pat, PatKind};
@@ -27,7 +28,7 @@ pub(super) fn check<'tcx>(
= higher::IfLet::hir(cx, inner_expr)
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
&& let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind
&& path_to_local_id(let_expr, pat_hir_id)
&& let_expr.res_local_id() == Some(pat_hir_id)
// Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
&& let PatKind::TupleStruct(ref qpath, [inner_pat], _) = let_pat.kind
&& let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id)
+6 -5
View File
@@ -1,10 +1,11 @@
use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_copy;
use clippy_utils::usage::local_used_in;
use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
use clippy_utils::{get_enclosing_block, higher, sugg};
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir::intravisit::walk_block;
@@ -67,7 +68,7 @@ pub(super) fn check<'tcx>(
&& !local_used_in(cx, canonical_id, base_left)
&& !local_used_in(cx, canonical_id, base_right)
// Source and destination must be different
&& path_to_local(base_left) != path_to_local(base_right)
&& base_left.res_local_id() != base_right.res_local_id()
{
Some((
ty,
@@ -128,7 +129,7 @@ fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
if let ExprKind::MethodCall(method, recv, [], _) = end.kind
&& method.ident.name == sym::len
&& path_to_local(recv) == path_to_local(base)
&& recv.res_local_id() == base.res_local_id()
{
if sugg.to_string() == end_str {
sugg::EMPTY.into()
@@ -364,7 +365,7 @@ fn get_details_from_idx<'tcx>(
starts: &[Start<'tcx>],
) -> Option<(StartKind<'tcx>, Offset)> {
fn get_start<'tcx>(e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option<StartKind<'tcx>> {
let id = path_to_local(e)?;
let id = e.res_local_id()?;
starts.iter().find(|start| start.id == id).map(|start| start.kind)
}
@@ -425,7 +426,7 @@ fn get_assignments<'a, 'tcx>(
.chain(*expr)
.filter(move |e| {
if let ExprKind::AssignOp(_, place, _) = e.kind {
path_to_local(place).is_some_and(|id| {
place.res_local_id().is_some_and(|id| {
!loop_counters
.iter()
// skip the first item which should be `StartKind::Range`
+2 -2
View File
@@ -1,7 +1,7 @@
use super::MISSING_SPIN_LOOP;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::MaybeDef;
use clippy_utils::std_or_core;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability;
use rustc_hir::{Block, Expr, ExprKind};
use rustc_lint::LateContext;
@@ -40,7 +40,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
&& let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind
&& [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
&& let callee_ty = cx.typeck_results().expr_ty(callee)
&& is_type_diagnostic_item(cx, callee_ty, sym::AtomicBool)
&& callee_ty.is_diag_item(cx, sym::AtomicBool)
&& let Some(std_or_core) = std_or_core(cx)
{
span_lint_and_sugg(
+6 -2
View File
@@ -861,6 +861,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// check for `loop { if let {} else break }` that could be `while let`
// (also matches an explicit "match" instead of "if let")
// (even if the "match" or "if let" is used for declaration)
// (also matches on `let {} else break`)
if let ExprKind::Loop(block, label, LoopSource::Loop, _) = expr.kind {
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
empty_loop::check(cx, expr, block);
@@ -870,7 +871,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
while_let_on_iterator::check(cx, expr);
if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
if let Some(higher::While {
condition, body, span, ..
}) = higher::While::hir(expr)
{
while_immutable_condition::check(cx, condition, body);
while_float::check(cx, condition);
missing_spin_loop::check(cx, condition, body);
@@ -880,7 +884,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
impl Loops {
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
fn check_for_loop<'tcx>(
&self,
cx: &LateContext<'tcx>,
+3 -2
View File
@@ -1,6 +1,7 @@
use super::MUT_RANGE_BOUND;
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::{get_enclosing_block, higher, path_to_local};
use clippy_utils::res::MaybeResPath;
use clippy_utils::{get_enclosing_block, higher};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Node, PatKind};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
@@ -39,7 +40,7 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
}
fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
if let Some(hir_id) = path_to_local(bound)
if let Some(hir_id) = bound.res_local_id()
&& let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
&& let PatKind::Binding(BindingMode::MUT, ..) = pat.kind
{
+1 -1
View File
@@ -240,7 +240,7 @@ fn is_label_for_block(cx: &LateContext<'_>, dest: &Destination) -> bool {
.is_ok_and(|hir_id| matches!(cx.tcx.hir_node(hir_id), Node::Block(_)))
}
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
fn never_loop_expr<'tcx>(
cx: &LateContext<'tcx>,
expr: &Expr<'tcx>,
+6 -5
View File
@@ -1,9 +1,10 @@
use super::SAME_ITEM_PUSH;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::Msrv;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{msrvs, path_to_local, std_or_core, sym};
use clippy_utils::ty::implements_trait;
use clippy_utils::{msrvs, std_or_core, sym};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -125,7 +126,7 @@ fn should_lint(&self) -> bool {
if !self.non_deterministic_expr
&& !self.multiple_pushes
&& let Some((vec, _, _)) = self.vec_push
&& let Some(hir_id) = path_to_local(vec)
&& let Some(hir_id) = vec.res_local_id()
{
!self.used_locals.contains(&hir_id)
} else {
@@ -141,7 +142,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::If(..) => self.non_deterministic_expr = true,
ExprKind::Block(block, _) => self.visit_block(block),
_ => {
if let Some(hir_id) = path_to_local(expr) {
if let Some(hir_id) = expr.res_local_id() {
self.used_locals.insert(hir_id);
}
walk_expr(self, expr);
@@ -186,7 +187,7 @@ fn get_vec_push<'tcx>(
&& let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
// Check that the method being called is push() on a Vec
&& path.ident.name == sym::push
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
&& cx.typeck_results().expr_ty(self_expr).is_diag_item(cx, sym::Vec)
{
return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
}
@@ -1,7 +1,7 @@
use super::UNUSED_ENUMERATE_INDEX;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{pat_is_wild, sugg};
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_
&& let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind
&& let ty = cx.typeck_results().expr_ty(arg)
&& pat_is_wild(cx, &index.kind, body)
&& is_type_diagnostic_item(cx, ty, sym::Enumerate)
&& ty.is_diag_item(cx, sym::Enumerate)
&& let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id)
&& cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id)
{
+8 -7
View File
@@ -1,5 +1,6 @@
use clippy_utils::res::MaybeResPath;
use clippy_utils::ty::{has_iter_method, implements_trait};
use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
use clippy_utils::{get_parent_expr, is_integer_const, sugg};
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_expr, walk_local};
@@ -47,7 +48,7 @@ pub(super) fn into_results(self) -> impl Iterator<Item = HirId> {
impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
// If node is a variable
if let Some(def_id) = path_to_local(expr) {
if let Some(def_id) = expr.res_local_id() {
if let Some(parent) = get_parent_expr(self.cx, expr) {
let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial);
if *state == IncrementVisitorVarState::IncrOnce {
@@ -175,7 +176,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
}
// If node is the desired variable, see how it's used
if path_to_local_id(expr, self.var_id) {
if expr.res_local_id() == Some(self.var_id) {
if self.past_loop {
self.state = InitializeVisitorState::DontWarn;
return;
@@ -255,7 +256,7 @@ fn is_conditional(expr: &Expr<'_>) -> bool {
/// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
/// actual `Iterator` that the loop uses.
pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applicability: &mut Applicability) -> String {
let impls_iterator = cx
.tcx
.get_diagnostic_item(sym::Iterator)
@@ -263,7 +264,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
if impls_iterator {
format!(
"{}",
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
sugg::Sugg::hir_with_applicability(cx, arg, "_", applicability).maybe_paren()
)
} else {
// (&x).into_iter() ==> x.iter()
@@ -281,12 +282,12 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
};
format!(
"{}.{method_name}()",
sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_paren(),
sugg::Sugg::hir_with_applicability(cx, caller, "_", applicability).maybe_paren(),
)
},
_ => format!(
"{}.into_iter()",
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
sugg::Sugg::hir_with_applicability(cx, arg, "_", applicability).maybe_paren()
),
}
}
+21 -9
View File
@@ -10,19 +10,19 @@
use rustc_lint::LateContext;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
let (init, let_info) = match (loop_block.stmts, loop_block.expr) {
let (init, let_info, els) = match (loop_block.stmts, loop_block.expr) {
([stmt, ..], _) => match stmt.kind {
StmtKind::Let(LetStmt {
init: Some(e),
els: None,
els,
pat,
ty,
..
}) => (*e, Some((*pat, *ty))),
StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None),
}) => (*e, Some((*pat, *ty)), *els),
StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None, None),
_ => return,
},
([], Some(e)) => (e, None),
([], Some(e)) => (e, None, None),
_ => return,
};
let has_trailing_exprs = loop_block.stmts.len() + usize::from(loop_block.expr.is_some()) > 1;
@@ -38,14 +38,26 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo
if_let.let_expr,
has_trailing_exprs,
let_info,
if_let.if_then,
Some(if_let.if_then),
);
} else if els.and_then(|x| x.expr).is_some_and(is_simple_break_expr)
&& let Some((pat, _)) = let_info
{
could_be_while_let(cx, expr, pat, init, has_trailing_exprs, let_info, None);
} else if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal) = init.kind
&& arm1.guard.is_none()
&& arm2.guard.is_none()
&& is_simple_break_expr(arm2.body)
{
could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs, let_info, arm1.body);
could_be_while_let(
cx,
expr,
arm1.pat,
scrutinee,
has_trailing_exprs,
let_info,
Some(arm1.body),
);
}
}
@@ -70,7 +82,7 @@ fn could_be_while_let<'tcx>(
let_expr: &'tcx Expr<'_>,
has_trailing_exprs: bool,
let_info: Option<(&Pat<'_>, Option<&Ty<'_>>)>,
inner_expr: &Expr<'_>,
inner_expr: Option<&Expr<'_>>,
) {
if has_trailing_exprs
&& (needs_ordered_drop(cx, cx.typeck_results().expr_ty(let_expr))
@@ -85,7 +97,7 @@ fn could_be_while_let<'tcx>(
// 1) it was ugly with big bodies;
// 2) it was not indented properly;
// 3) it wasnt very smart (see #675).
let inner_content = if let Some((pat, ty)) = let_info
let inner_content = if let Some(((pat, ty), inner_expr)) = let_info.zip(inner_expr)
// Prevent trivial reassignments such as `let x = x;` or `let _ = …;`, but
// keep them if the type has been explicitly specified.
&& (!is_trivial_assignment(pat, peel_blocks(inner_expr)) || ty.is_some())
@@ -2,9 +2,10 @@
use super::WHILE_LET_ON_ITERATOR;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::visitors::is_res_used;
use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method};
use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{Visitor, walk_expr};
@@ -19,11 +20,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr)
// check for `Some(..)` pattern
&& let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
&& is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
&& cx.qpath_res(pat_path, let_pat.hir_id).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
// check for call to `Iterator::next`
&& let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind
&& method_name.ident.name == sym::next
&& is_trait_method(cx, let_expr, sym::Iterator)
&& cx.ty_based_def(let_expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
&& let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr)
// get the loop containing the match expression
&& !uses_iter(cx, &iter_expr_struct, if_then)
+3 -2
View File
@@ -2,9 +2,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::If;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::HasSession as _;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
use clippy_utils::ty::peel_and_count_ty_refs;
use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
@@ -104,7 +105,7 @@ impl ManualAbsDiff {
fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option<(Ty<'tcx>, usize)> {
let is_int = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) && self.msrv.meets(cx, msrvs::ABS_DIFF);
let is_duration =
|ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
|ty: Ty<'_>| ty.is_diag_item(cx, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
let a_ty = cx.typeck_results().expr_ty(a).peel_refs();
let (b_ty, b_n_refs, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(b));
+19 -18
View File
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{is_panic, root_macro_call};
use clippy_utils::source::{indent_of, reindent_multiline};
use clippy_utils::{higher, is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
@@ -50,32 +51,32 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
// Should this have a config value?
&& !is_else_clause(cx.tcx, expr)
{
let mut applicability = Applicability::MachineApplicable;
let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
if !comments.is_empty() {
comments += "\n";
}
let cond_sugg = !sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
let sugg = format!("assert!({cond_sugg}, {format_args_snip}){semicolon}");
// we show to the user the suggestion without the comments, but when applying the fix, include the
// comments in the block
span_lint_and_then(
cx,
MANUAL_ASSERT,
expr.span,
"only a `panic!` in `if`-then statement",
|diag| {
// comments can be noisy, do not show them to the user
let mut applicability = Applicability::MachineApplicable;
let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
if !comments.is_empty() {
diag.tool_only_span_suggestion(
expr.span.shrink_to_lo(),
"add comments back",
comments,
applicability,
);
comments += "\n";
}
diag.span_suggestion(expr.span, "try instead", sugg, applicability);
let cond_sugg = !sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
let indent = indent_of(cx, expr.span);
let full_sugg = reindent_multiline(
format!("{comments}assert!({cond_sugg}, {format_args_snip}){semicolon}").as_str(),
true,
indent,
);
diag.span_suggestion_verbose(
expr.span,
"replace `if`-then-`panic!` with `assert!`",
full_sugg,
applicability,
);
},
);
}
+15 -15
View File
@@ -3,13 +3,11 @@
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::higher::If;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::is_const_evaluatable;
use clippy_utils::{
MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id,
peel_blocks, peel_blocks_with_stmt, sym,
};
use clippy_utils::{eq_expr_value, is_in_const_context, peel_blocks, peel_blocks_with_stmt, sym};
use itertools::Itertools;
use rustc_errors::{Applicability, Diag};
use rustc_hir::def::Res;
@@ -292,10 +290,12 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx
/// # ;
/// ```
fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = &expr.kind
&& (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord))
if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = expr.kind
&& (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point()
|| cx.ty_based_def(expr).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord))
&& let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind
&& (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord))
&& (cx.typeck_results().expr_ty_adjusted(input).is_floating_point()
|| cx.ty_based_def(receiver).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord))
{
let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
let (min, max) = match (seg_first.ident.name, seg_second.ident.name) {
@@ -331,18 +331,18 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
fn segment<'tcx>(cx: &LateContext<'_>, func: &Expr<'tcx>) -> Option<FunctionType<'tcx>> {
match func.kind {
ExprKind::Path(QPath::Resolved(None, path)) => {
let id = path.res.opt_def_id()?;
match cx.tcx.get_diagnostic_name(id) {
let def = path.res.opt_def(cx)?;
match cx.tcx.get_diagnostic_name(def.1) {
Some(sym::cmp_min) => Some(FunctionType::CmpMin),
Some(sym::cmp_max) => Some(FunctionType::CmpMax),
_ if is_diag_trait_item(cx, id, sym::Ord) => {
_ if def.assoc_fn_parent(cx).is_diag_item(cx, sym::Ord) => {
Some(FunctionType::OrdOrFloat(path.segments.last().expect("infallible")))
},
_ => None,
}
},
ExprKind::Path(QPath::TypeRelative(ty, seg)) => {
matches!(path_res(cx, ty), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
matches!(ty.basic_res(), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
},
_ => None,
}
@@ -435,7 +435,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt
let first = BinaryOp::new(first)?;
let second = BinaryOp::new(second)?;
if let PatKind::Binding(_, binding, _, None) = &last_arm.pat.kind
&& path_to_local_id(peel_blocks_with_stmt(last_arm.body), *binding)
&& peel_blocks_with_stmt(last_arm.body).res_local_id() == Some(*binding)
&& last_arm.guard.is_none()
{
// Proceed as normal
@@ -516,7 +516,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) ->
},
span: first_expr.span.to(second_expr.span),
make_assignment: Some(maybe_input_first_path),
hir_with_ignore_attr: Some(first_expr.hir_id()),
hir_with_ignore_attr: Some(first_expr.hir_id),
})
} else {
None
@@ -655,8 +655,8 @@ fn check<'tcx>(
let (min, max) = (second_expr, first_expr);
let refers_to_input = match input_hir_ids {
Some((first_hir_id, second_hir_id)) => {
path_to_local_id(peel_blocks(first_bin.left), first_hir_id)
&& path_to_local_id(peel_blocks(second_bin.left), second_hir_id)
peel_blocks(first_bin.left).res_local_id() == Some(first_hir_id)
&& peel_blocks(second_bin.left).res_local_id() == Some(second_hir_id)
},
None => eq_expr_value(cx, first_bin.left, second_bin.left),
};
+8 -5
View File
@@ -1,7 +1,6 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
use clippy_utils::{SpanlessEq, sym};
use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
@@ -165,6 +164,7 @@ fn build_suggestion(
applicability: &mut Applicability,
) {
let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_paren();
let rhs_ty = cx.typeck_results().expr_ty(rhs);
let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric()
&& matches!(
lhs.kind,
@@ -182,7 +182,7 @@ fn build_suggestion(
}
)
) {
format!("_{}", cx.typeck_results().expr_ty(rhs))
format!("_{rhs_ty}")
} else {
String::new()
};
@@ -199,9 +199,12 @@ fn build_suggestion(
} else {
format!("{dividend_sugg_str}{type_suffix}")
};
let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability);
let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0);
// Dereference the RHS if it is a reference type
let divisor_snippet = match Sugg::hir_with_context(cx, rhs, expr.span.ctxt(), "_", applicability) {
sugg if rhs_ty.is_ref() => sugg.deref(),
sugg => sugg,
};
span_lint_and_sugg(
cx,
@@ -209,7 +212,7 @@ fn build_suggestion(
expr.span,
"manually reimplementing `div_ceil`",
"consider using `.div_ceil()`",
sugg,
format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"),
*applicability,
);
}
+4 -3
View File
@@ -1,9 +1,10 @@
use clippy_config::Conf;
use clippy_utils::consts::ConstEvalCtxt;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_from_proc_macro;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{is_from_proc_macro, path_to_local};
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
@@ -138,7 +139,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
// Checking all possible scenarios using a function would be a hopeless task, as we have
// 16 possible alignments of constants/operands. For now, let's use `partition`.
&& let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
&& exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
&& exprs.iter_mut().partition_in_place(|i| i.res_local_id().is_some()) == 2
&& !expr.span.in_external_macro(cx.sess().source_map())
&& (
is_not_const(cx.tcx, cx.tcx.hir_enclosing_body_owner(expr.hir_id).into())
@@ -149,7 +150,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
&& let ctxt = expr.span.ctxt()
&& let Some(const_1) = ecx.eval_local(const_1, ctxt)
&& let Some(const_2) = ecx.eval_local(const_2, ctxt)
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
&& first.res_local_id().is_some_and(|f| second.res_local_id().is_some_and(|s| f == s))
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
// case somebody does that for some reason
&& (const_1.is_pos_infinity() && const_2.is_neg_infinity()
+4 -3
View File
@@ -1,9 +1,10 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::sym;
use clippy_utils::visitors::{is_local_used, local_used_once};
use clippy_utils::{is_trait_method, path_to_local_id, sym};
use rustc_errors::Applicability;
use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -81,8 +82,8 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
&& !hash_expr.span.from_expansion()
&& let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind
&& seg.ident.name == sym::hash
&& is_trait_method(cx, hash_expr, sym::Hash)
&& path_to_local_id(ref_to_hasher.peel_borrows(), hasher)
&& cx.ty_based_def(hash_expr).opt_parent(cx).is_diag_item(cx, sym::Hash)
&& ref_to_hasher.peel_borrows().res_local_id() == Some(hasher)
&& let maybe_finish_stmt = stmts.next()
// There should be no more statements referencing `hasher`
+4 -4
View File
@@ -1,8 +1,8 @@
use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sym;
use clippy_utils::ty::{get_type_diagnostic_name, is_type_diagnostic_item, is_type_lang_item};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::ExprKind::{Binary, Lit, MethodCall};
@@ -58,7 +58,7 @@ fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Op
if needs_ref_to_cmp(cx, ty)
|| ty.is_str()
|| ty.is_slice()
|| matches!(get_type_diagnostic_name(cx, ty), Some(sym::OsStr | sym::OsString))
|| matches!(ty.opt_diag_name(cx), Some(sym::OsStr | sym::OsString))
{
return Some((expr.span, ToAscii(is_lower, ty_raw)));
}
@@ -72,8 +72,8 @@ fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Op
fn needs_ref_to_cmp(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
ty.is_char()
|| *ty.kind() == ty::Uint(UintTy::U8)
|| is_type_diagnostic_item(cx, ty, sym::Vec)
|| is_type_lang_item(cx, ty, LangItem::String)
|| ty.is_diag_item(cx, sym::Vec)
|| ty.is_lang_item(cx, LangItem::String)
}
impl LateLintPass<'_> for ManualIgnoreCaseCmp {
+3 -2
View File
@@ -2,8 +2,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeResPath;
use clippy_utils::sugg::Sugg;
use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym};
use clippy_utils::{higher, is_in_const_context, peel_ref_operators, sym};
use rustc_ast::LitKind::{Byte, Char};
use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability;
@@ -125,7 +126,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
let local_hid = path_to_local(arg)?;
let local_hid = arg.res_local_id()?;
if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
// `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given
&& ty_span == span
+23 -39
View File
@@ -2,16 +2,14 @@
use clippy_config::types::MatchLintBehaviour;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::res::{MaybeDef, MaybeQPath};
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
MaybePath, is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, path_res, peel_blocks,
};
use clippy_utils::{is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
use rustc_ast::BindingMode;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_hir::{Arm, Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LintContext};
use rustc_span::Span;
use rustc_span::symbol::{Symbol, sym};
@@ -131,39 +129,25 @@ fn is_arms_disjointed(cx: &LateContext<'_>, arm1: &Arm<'_>, arm2: &Arm<'_>) -> b
/// Returns `true` if the given pattern is a variant of an enum.
pub fn is_enum_variant(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
struct Pat<'hir>(&'hir rustc_hir::Pat<'hir>);
impl<'hir> MaybePath<'hir> for Pat<'hir> {
fn qpath_opt(&self) -> Option<&QPath<'hir>> {
match self.0.kind {
PatKind::Struct(ref qpath, fields, _)
if fields
.iter()
.all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) =>
{
Some(qpath)
},
PatKind::TupleStruct(ref qpath, pats, _)
if pats
.iter()
.all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) =>
{
Some(qpath)
},
PatKind::Expr(&PatExpr {
kind: PatExprKind::Path(ref qpath),
..
}) => Some(qpath),
_ => None,
}
}
fn hir_id(&self) -> HirId {
self.0.hir_id
}
}
let res = path_res(cx, &Pat(pat));
let path = match pat.kind {
PatKind::Struct(ref qpath, fields, _)
if fields
.iter()
.all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) =>
{
(qpath, pat.hir_id)
},
PatKind::TupleStruct(ref qpath, pats, _)
if pats
.iter()
.all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) =>
{
(qpath, pat.hir_id)
},
PatKind::Expr(e) if let Some((qpath, id)) = e.opt_qpath() => (qpath, id),
_ => return false,
};
let res = path.res(cx);
matches!(
res,
Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
@@ -384,7 +368,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
}
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)) {
if !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) {
has_disallowed = true;
}
});
@@ -1,7 +1,8 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{is_trait_method, peel_hir_expr_refs};
use clippy_utils::peel_hir_expr_refs;
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, Mutability, QPath};
@@ -52,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
&& path.ident.name == sym::to_string
&& let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
&& let Res::Def(DefKind::Const, receiver_def_id) = path.res
&& is_trait_method(cx, target, sym::ToString)
&& cx.ty_based_def(target).opt_parent(cx).is_diag_item(cx, sym::ToString)
&& cx.tcx.is_diagnostic_item(sym::path_main_separator, receiver_def_id)
&& let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
&& ty.is_str()
+4 -3
View File
@@ -1,6 +1,7 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::msrvs::Msrv;
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
use clippy_utils::{is_none_pattern, msrvs, peel_hir_expr_refs, sym};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -189,7 +190,7 @@ fn check_arms(cx: &LateContext<'_>, none_arm: &Arm<'_>, some_arm: &Arm<'_>) -> b
fn returns_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match expr.kind {
ExprKind::Path(_) => clippy_utils::is_path_diagnostic_item(cx, expr, sym::default_fn),
ExprKind::Path(_) => expr.res(cx).is_diag_item(cx, sym::default_fn),
ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir_body(cl.body).value),
_ => false,
}
@@ -214,11 +215,11 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
_ => false,
},
ExprKind::Array([]) => true,
ExprKind::Call(def, []) => clippy_utils::is_path_diagnostic_item(cx, def, sym::default_fn),
ExprKind::Call(def, []) => def.res(cx).is_diag_item(cx, sym::default_fn),
_ => false,
}
}
fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
clippy_utils::is_path_diagnostic_item(cx, expr, sym::slice_from_ref)
expr.basic_res().is_diag_item(cx, sym::slice_from_ref)
}
+3 -2
View File
@@ -1,9 +1,10 @@
use clippy_config::Conf;
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_in_const_context;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeResPath;
use clippy_utils::source::snippet_with_context;
use clippy_utils::{is_in_const_context, path_to_local};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -64,7 +65,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&& let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
&& rem2_op.node == BinOpKind::Rem
&& const1 == const2
&& let Some(hir_id) = path_to_local(rem2_lhs)
&& let Some(hir_id) = rem2_lhs.res_local_id()
&& let Some(const3) = check_for_unsigned_int_constant(cx, ctxt, rem2_rhs)
// Also ensures the const is nonzero since zero can't be a divisor
&& const2 == const3
+4 -4
View File
@@ -2,8 +2,8 @@
use clippy_utils::SpanlessEq;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet;
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::ExprKind::Assign;
@@ -189,7 +189,7 @@ fn check_to_owned(
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
&& cx.tcx.is_diagnostic_item(sym::str_chars, chars_expr_def_id)
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
&& is_type_lang_item(cx, ty, hir::LangItem::String)
&& ty.is_lang_item(cx, hir::LangItem::String)
&& SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
&& let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
&& let hir::ExprKind::Closure(closure) = closure_expr.kind
@@ -250,7 +250,7 @@ fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool {
fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv) -> bool {
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
let required = match get_type_diagnostic_name(cx, ty) {
let required = match ty.opt_diag_name(cx) {
Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN,
Some(sym::BTreeSet) => msrvs::BTREE_SET_RETAIN,
Some(sym::BTreeMap) => msrvs::BTREE_MAP_RETAIN,
@@ -264,7 +264,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv)
fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
matches!(get_type_diagnostic_name(cx, ty), Some(sym::BTreeMap | sym::HashMap))
matches!(ty.opt_diag_name(cx), Some(sym::BTreeMap | sym::HashMap))
}
fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) {
+51 -35
View File
@@ -56,20 +56,14 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
}
}
fn parse_shift<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> {
fn parse_shift<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(ShiftDirection, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
if let ExprKind::Binary(op, l, r) = expr.kind {
let dir = match op.node {
BinOpKind::Shl => ShiftDirection::Left,
BinOpKind::Shr => ShiftDirection::Right,
_ => return None,
};
let const_expr = ConstEvalCtxt::new(cx).eval_local(r, expr.span.ctxt())?;
if let Constant::Int(shift) = const_expr {
return Some((dir, shift, l));
}
return Some((dir, l, r));
}
None
}
@@ -78,40 +72,62 @@ impl LateLintPass<'_> for ManualRotate {
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if let ExprKind::Binary(op, l, r) = expr.kind
&& let BinOpKind::Add | BinOpKind::BitOr = op.node
&& let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l)
&& let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r)
{
if l_shift_dir == r_shift_dir {
return;
}
if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) {
return;
}
let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() {
&& let Some((l_shift_dir, l_expr, l_amount)) = parse_shift(l)
&& let Some((r_shift_dir, r_expr, r_amount)) = parse_shift(r)
&& l_shift_dir != r_shift_dir
&& clippy_utils::eq_expr_value(cx, l_expr, r_expr)
&& let Some(bit_width) = match cx.typeck_results().expr_ty(expr).kind() {
ty::Int(itype) => itype.bit_width(),
ty::Uint(itype) => itype.bit_width(),
_ => return,
}) else {
return;
};
if l_amount + r_amount == u128::from(bit_width) {
let (shift_function, amount) = if l_amount < r_amount {
}
{
let const_eval = ConstEvalCtxt::new(cx);
let ctxt = expr.span.ctxt();
let (shift_function, amount) = if let Some(Constant::Int(l_amount_val)) =
const_eval.eval_local(l_amount, ctxt)
&& let Some(Constant::Int(r_amount_val)) = const_eval.eval_local(r_amount, ctxt)
&& l_amount_val + r_amount_val == u128::from(bit_width)
{
if l_amount_val < r_amount_val {
(l_shift_dir, l_amount)
} else {
(r_shift_dir, r_amount)
}
} else {
let (amount1, binop, minuend, amount2, shift_direction) = match (l_amount.kind, r_amount.kind) {
(_, ExprKind::Binary(binop, minuend, other)) => (l_amount, binop, minuend, other, l_shift_dir),
(ExprKind::Binary(binop, minuend, other), _) => (r_amount, binop, minuend, other, r_shift_dir),
_ => return,
};
let mut applicability = Applicability::MachineApplicable;
let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren();
span_lint_and_sugg(
cx,
MANUAL_ROTATE,
expr.span,
"there is no need to manually implement bit rotation",
"this expression can be rewritten as",
format!("{expr_sugg}.{shift_function}({amount})"),
Applicability::MachineApplicable,
);
}
if let Some(Constant::Int(minuend)) = const_eval.eval_local(minuend, ctxt)
&& clippy_utils::eq_expr_value(cx, amount1, amount2)
// (x << s) | (x >> bit_width - s)
&& ((binop.node == BinOpKind::Sub && u128::from(bit_width) == minuend)
// (x << s) | (x >> (bit_width - 1) ^ s)
|| (binop.node == BinOpKind::BitXor && u128::from(bit_width).checked_sub(minuend) == Some(1)))
{
// NOTE: we take these from the side that _doesn't_ have the binop, since it's probably simpler
(shift_direction, amount1)
} else {
return;
}
};
let mut applicability = Applicability::MachineApplicable;
let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren();
let amount = sugg::Sugg::hir_with_applicability(cx, amount, "_", &mut applicability);
span_lint_and_sugg(
cx,
MANUAL_ROTATE,
expr.span,
"there is no need to manually implement bit rotation",
"this expression can be rewritten as",
format!("{expr_sugg}.{shift_function}({amount})"),
Applicability::MachineApplicable,
);
}
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{iter_input_pats, method_chain_args};
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -205,9 +205,9 @@ fn lint_map_unit_fn(
) {
let var_arg = &map_args.0;
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
let (map_type, variant, lint) = if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Option) {
("Option", "Some", OPTION_MAP_UNIT_FN)
} else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) {
} else if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Result) {
("Result", "Ok", RESULT_MAP_UNIT_FN)
} else {
return;
+4 -4
View File
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{higher, is_res_lang_ctor, sym};
use clippy_utils::{higher, sym};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, PatKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -57,8 +57,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
&& let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind //get operation
&& ok_path.ident.name == sym::ok
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
&& is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
&& cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
&& cx.qpath_res(pat_path, let_pat.hir_id).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
&& let ctxt = expr.span.ctxt()
&& let_expr.span.ctxt() == ctxt
&& let_pat.span.ctxt() == ctxt
+30 -28
View File
@@ -1,18 +1,17 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::msrvs::Msrv;
use clippy_utils::res::{MaybeDef, MaybeResPath};
use clippy_utils::source::snippet;
use clippy_utils::visitors::is_local_used;
use clippy_utils::{
SpanlessEq, get_ref_operators, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt,
peel_ref_operators,
};
use clippy_utils::{SpanlessEq, get_ref_operators, is_unit_expr, peel_blocks_with_stmt, peel_ref_operators};
use rustc_ast::BorrowKind;
use rustc_errors::MultiSpan;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatExpr, PatExprKind, PatKind};
use rustc_lint::LateContext;
use rustc_span::Span;
use rustc_span::symbol::Ident;
use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or};
@@ -35,7 +34,7 @@ pub(super) fn check_if_let<'tcx>(
check_arm(cx, false, pat, let_expr, body, None, else_expr, msrv);
}
#[allow(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments)]
fn check_arm<'tcx>(
cx: &LateContext<'tcx>,
outer_is_match: bool,
@@ -50,26 +49,28 @@ fn check_arm<'tcx>(
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
&& let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
IfLetOrMatch::IfLet(scrutinee, pat, _, els, _) => Some((scrutinee, pat, els)),
IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
// if there are more than two arms, collapsing would be non-trivial
// one of the arms must be "wild-like"
&& let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a))
{
let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
Some((scrutinee, then.pat, Some(els.body)))
} else {
None
IfLetOrMatch::Match(scrutinee, arms, ..) => {
if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
// if there are more than two arms, collapsing would be non-trivial
// one of the arms must be "wild-like"
&& let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a))
{
let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
Some((scrutinee, then.pat, Some(els.body)))
} else {
None
}
},
}
&& outer_pat.span.eq_ctxt(inner_scrutinee.span)
// match expression must be a local binding
// match <local> { .. }
&& let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee))
&& let Some(binding_id) = peel_ref_operators(cx, inner_scrutinee).res_local_id()
&& !pat_contains_disallowed_or(cx, inner_then_pat, msrv)
// the binding must come from the pattern of the containing match arm
// ..<local>.. => match <local> { .. }
&& let (Some(binding_span), is_innermost_parent_pat_struct)
= find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id)
&& let (Some((binding_ident, binding_span)), is_innermost_parent_pat_struct) =
find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id)
// the "else" branches must be equal
&& match (outer_else_body, inner_else_body) {
(None, None) => true,
@@ -77,9 +78,7 @@ fn check_arm<'tcx>(
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
}
// the binding must not be used in the if guard
&& outer_guard.is_none_or(
|e| !is_local_used(cx, e, binding_id)
)
&& outer_guard.is_none_or(|e| !is_local_used(cx, e, binding_id))
// ...or anywhere in the inner expression
&& match inner {
IfLetOrMatch::IfLet(_, _, body, els, _) => {
@@ -103,7 +102,7 @@ fn check_arm<'tcx>(
// collapsing patterns need an explicit field name in struct pattern matching
// ex: Struct {x: Some(1)}
let replace_msg = if is_innermost_parent_pat_struct {
format!(", prefixed by `{}`:", snippet(cx, binding_span, "their field name"))
format!(", prefixed by `{binding_ident}: `")
} else {
String::new()
};
@@ -135,21 +134,24 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
kind: PatExprKind::Path(qpath),
hir_id,
..
}) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
}) => cx
.qpath_res(qpath, *hir_id)
.ctor_parent(cx)
.is_lang_item(cx, OptionNone),
_ => false,
}
}
fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<Span>, bool) {
let mut span = None;
fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<(Ident, Span)>, bool) {
let mut binding = None;
let mut is_innermost_parent_pat_struct = false;
pat.walk_short(|p| match &p.kind {
pat.walk_short(|p| match p.kind {
// ignore OR patterns
PatKind::Or(_) => false,
PatKind::Binding(_bm, _, _ident, _) => {
PatKind::Binding(_bm, _, ident, _) => {
let found = p.hir_id == hir_id;
if found {
span = Some(p.span);
binding = Some((ident, p.span));
}
!found
},
@@ -158,7 +160,7 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi
true
},
});
(span, is_innermost_parent_pat_struct)
(binding, is_innermost_parent_pat_struct)
}
/// Builds a chain of reference-manipulation method calls (e.g., `.as_ref()`, `.as_mut()`,

Some files were not shown because too many files have changed in this diff Show More