mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
9ff84af787
126 changed files with 2576 additions and 351 deletions
68
CHANGELOG.md
68
CHANGELOG.md
|
@ -6,11 +6,68 @@ document.
|
||||||
|
|
||||||
## Unreleased / Beta / In Rust Nightly
|
## Unreleased / Beta / In Rust Nightly
|
||||||
|
|
||||||
[7671c283...master](https://github.com/rust-lang/rust-clippy/compare/7671c283...master)
|
[09ac14c9...master](https://github.com/rust-lang/rust-clippy/compare/09ac14c9...master)
|
||||||
|
|
||||||
|
## Rust 1.75
|
||||||
|
|
||||||
|
Current stable, released 2023-12-28
|
||||||
|
|
||||||
|
[View all 69 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-09-25T11%3A47%3A47Z..2023-11-02T16%3A41%3A59Z+base%3Amaster)
|
||||||
|
|
||||||
|
### New Lints
|
||||||
|
|
||||||
|
* [`unused_enumerate_index`]
|
||||||
|
[#10404](https://github.com/rust-lang/rust-clippy/pull/10404)
|
||||||
|
* [`unnecessary_fallible_conversions`]
|
||||||
|
[#11669](https://github.com/rust-lang/rust-clippy/pull/11669)
|
||||||
|
* [`waker_clone_wake`]
|
||||||
|
[#11698](https://github.com/rust-lang/rust-clippy/pull/11698)
|
||||||
|
* [`struct_field_names`]
|
||||||
|
[#11496](https://github.com/rust-lang/rust-clippy/pull/11496)
|
||||||
|
* [`into_iter_without_iter`]
|
||||||
|
[#11587](https://github.com/rust-lang/rust-clippy/pull/11587)
|
||||||
|
* [`iter_without_into_iter`]
|
||||||
|
[#11527](https://github.com/rust-lang/rust-clippy/pull/11527)
|
||||||
|
* [`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)
|
||||||
|
[#11727](https://github.com/rust-lang/rust-clippy/pull/11727)
|
||||||
|
* Moved [`missing_enforced_import_renames`] to `style` (Now warn-by-default)
|
||||||
|
[#11539](https://github.com/rust-lang/rust-clippy/pull/11539)
|
||||||
|
* Moved [`needless_raw_string_hashes`] to `pedantic` (Now allow-by-default)
|
||||||
|
[#11415](https://github.com/rust-lang/rust-clippy/pull/11415)
|
||||||
|
* Moved [`needless_pass_by_ref_mut`] to `nursery` (Now allow-by-default)
|
||||||
|
[#11596](https://github.com/rust-lang/rust-clippy/pull/11596)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: Now check the
|
||||||
|
[`ignore-interior-mutability`] config value
|
||||||
|
[#11678](https://github.com/rust-lang/rust-clippy/pull/11678)
|
||||||
|
|
||||||
|
### Suggestion Fixes/Improvements
|
||||||
|
|
||||||
|
* [`items_after_test_module`]: The suggestion is now machine-applicable
|
||||||
|
[#11611](https://github.com/rust-lang/rust-clippy/pull/11611)
|
||||||
|
|
||||||
|
### ICE Fixes
|
||||||
|
|
||||||
|
* [`redundant_locals`]: No longer crashes if variables are rebound above macros
|
||||||
|
[#11623](https://github.com/rust-lang/rust-clippy/pull/11623)
|
||||||
|
* [`implicit_hasher`]: No longer lints inside macros, which could cause ICEs
|
||||||
|
[#11593](https://github.com/rust-lang/rust-clippy/pull/11593)
|
||||||
|
|
||||||
|
### Documentation Improvements
|
||||||
|
|
||||||
|
* `cargo clippy --help` now uses colors for readability :tada:
|
||||||
|
|
||||||
## Rust 1.74
|
## Rust 1.74
|
||||||
|
|
||||||
Current stable, released 2023-11-16
|
Released 2023-11-16
|
||||||
|
|
||||||
[View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-08-11T15%3A29%3A18Z..2023-09-25T08%3A48%3A22Z+base%3Amaster)
|
[View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-08-11T15%3A29%3A18Z..2023-09-25T08%3A48%3A22Z+base%3Amaster)
|
||||||
|
|
||||||
|
@ -51,7 +108,7 @@ Current stable, released 2023-11-16
|
||||||
### Enhancements
|
### 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`] to `true` by default
|
[`accept-comment-above-attributes`] are now `true` by default
|
||||||
[#11170](https://github.com/rust-lang/rust-clippy/pull/11170)
|
[#11170](https://github.com/rust-lang/rust-clippy/pull/11170)
|
||||||
* [`explicit_iter_loop`]: Added [`enforce-iter-loop-reborrow`] to disable reborrow linting by default
|
* [`explicit_iter_loop`]: Added [`enforce-iter-loop-reborrow`] to disable reborrow linting by default
|
||||||
[#11418](https://github.com/rust-lang/rust-clippy/pull/11418)
|
[#11418](https://github.com/rust-lang/rust-clippy/pull/11418)
|
||||||
|
@ -5044,6 +5101,7 @@ Released 2018-09-13
|
||||||
[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
|
[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
|
||||||
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
|
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
|
||||||
[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
|
[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
|
||||||
|
[`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute
|
||||||
[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
|
[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
|
||||||
[`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop
|
[`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop
|
||||||
[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
|
[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
|
||||||
|
@ -5177,6 +5235,8 @@ Released 2018-09-13
|
||||||
[`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module
|
[`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module
|
||||||
[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
|
[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
|
||||||
[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
|
[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
|
||||||
|
[`iter_filter_is_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_filter_is_ok
|
||||||
|
[`iter_filter_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_filter_is_some
|
||||||
[`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map
|
[`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map
|
||||||
[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
|
[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
|
||||||
[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
|
[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
|
||||||
|
@ -5470,6 +5530,7 @@ Released 2018-09-13
|
||||||
[`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
|
[`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
|
||||||
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
|
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
|
||||||
[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
|
[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
|
||||||
|
[`result_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_filter_map
|
||||||
[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
|
[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
|
||||||
[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
|
[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
|
||||||
[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
|
[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
|
||||||
|
@ -5582,6 +5643,7 @@ Released 2018-09-13
|
||||||
[`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box
|
[`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box
|
||||||
[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
|
[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
|
||||||
[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
|
[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
|
||||||
|
[`unconditional_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#unconditional_recursion
|
||||||
[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
|
[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
|
||||||
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
|
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
|
||||||
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
|
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
|
||||||
|
|
|
@ -212,7 +212,7 @@ default configuration of Clippy. By default, any configuration will replace the
|
||||||
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
|
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
|
||||||
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
|
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
|
||||||
|
|
||||||
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
|
**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
|
||||||
|
|
||||||
---
|
---
|
||||||
**Affected lints:**
|
**Affected lints:**
|
||||||
|
|
|
@ -27,7 +27,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
|
||||||
"OAuth", "GraphQL",
|
"OAuth", "GraphQL",
|
||||||
"OCaml",
|
"OCaml",
|
||||||
"OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS",
|
"OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS",
|
||||||
"WebGL",
|
"WebGL", "WebGL2", "WebGPU",
|
||||||
"TensorFlow",
|
"TensorFlow",
|
||||||
"TrueType",
|
"TrueType",
|
||||||
"iOS", "macOS", "FreeBSD",
|
"iOS", "macOS", "FreeBSD",
|
||||||
|
@ -640,7 +640,8 @@ impl Conf {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
sess.dcx().err(format!("error finding Clippy's configuration file: {error}"));
|
sess.dcx()
|
||||||
|
.err(format!("error finding Clippy's configuration file: {error}"));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ msrv_aliases! {
|
||||||
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
|
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
|
||||||
1,34,0 { TRY_FROM }
|
1,34,0 { TRY_FROM }
|
||||||
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
|
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
|
||||||
|
1,29,0 { ITER_FLATTEN }
|
||||||
1,28,0 { FROM_BOOL }
|
1,28,0 { FROM_BOOL }
|
||||||
1,27,0 { ITERATOR_TRY_FOLD }
|
1,27,0 { ITERATOR_TRY_FOLD }
|
||||||
1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
|
1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
|
||||||
|
@ -106,7 +107,8 @@ impl Msrv {
|
||||||
|
|
||||||
if let Some(msrv_attr) = msrv_attrs.next() {
|
if let Some(msrv_attr) = msrv_attrs.next() {
|
||||||
if let Some(duplicate) = msrv_attrs.last() {
|
if let Some(duplicate) = msrv_attrs.last() {
|
||||||
sess.dcx().struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
|
sess.dcx()
|
||||||
|
.struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
|
||||||
.span_note(msrv_attr.span, "first definition found here")
|
.span_note(msrv_attr.span, "first definition found here")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -116,7 +118,8 @@ impl Msrv {
|
||||||
return Some(version);
|
return Some(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
sess.dcx().span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
|
sess.dcx()
|
||||||
|
.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
|
||||||
} else {
|
} else {
|
||||||
sess.dcx().span_err(msrv_attr.span, "bad clippy attribute");
|
sess.dcx().span_err(msrv_attr.span, "bad clippy attribute");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use clippy_utils::consts::{constant, Constant};
|
use clippy_utils::consts::{constant_with_source, Constant, ConstantSource};
|
||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
use clippy_utils::diagnostics::span_lint_and_help;
|
||||||
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
|
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
|
||||||
use rustc_hir::Expr;
|
use rustc_hir::{Expr, Item, ItemKind, Node};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
@ -42,9 +42,18 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
|
||||||
let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
|
let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
|
let Some((Constant::Bool(val), source)) = constant_with_source(cx, cx.typeck_results(), condition) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
if let ConstantSource::Constant = source
|
||||||
|
&& let Some(node) = cx.tcx.hir().find_parent(e.hir_id)
|
||||||
|
&& let Node::Item(Item {
|
||||||
|
kind: ItemKind::Const(..),
|
||||||
|
..
|
||||||
|
}) = node
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
if val {
|
if val {
|
||||||
span_lint_and_help(
|
span_lint_and_help(
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -2,9 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::ty::implements_trait;
|
use clippy_utils::ty::implements_trait;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{
|
use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath};
|
||||||
Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath,
|
|
||||||
};
|
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
|
||||||
|
|
|
@ -369,6 +369,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
|
crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
|
||||||
crate::methods::ITER_CLONED_COLLECT_INFO,
|
crate::methods::ITER_CLONED_COLLECT_INFO,
|
||||||
crate::methods::ITER_COUNT_INFO,
|
crate::methods::ITER_COUNT_INFO,
|
||||||
|
crate::methods::ITER_FILTER_IS_OK_INFO,
|
||||||
|
crate::methods::ITER_FILTER_IS_SOME_INFO,
|
||||||
crate::methods::ITER_KV_MAP_INFO,
|
crate::methods::ITER_KV_MAP_INFO,
|
||||||
crate::methods::ITER_NEXT_SLICE_INFO,
|
crate::methods::ITER_NEXT_SLICE_INFO,
|
||||||
crate::methods::ITER_NTH_INFO,
|
crate::methods::ITER_NTH_INFO,
|
||||||
|
@ -419,6 +421,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
|
crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
|
||||||
crate::methods::REDUNDANT_AS_STR_INFO,
|
crate::methods::REDUNDANT_AS_STR_INFO,
|
||||||
crate::methods::REPEAT_ONCE_INFO,
|
crate::methods::REPEAT_ONCE_INFO,
|
||||||
|
crate::methods::RESULT_FILTER_MAP_INFO,
|
||||||
crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
|
crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
|
||||||
crate::methods::SEARCH_IS_SOME_INFO,
|
crate::methods::SEARCH_IS_SOME_INFO,
|
||||||
crate::methods::SEEK_FROM_CURRENT_INFO,
|
crate::methods::SEEK_FROM_CURRENT_INFO,
|
||||||
|
@ -650,6 +653,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
|
crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
|
||||||
crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
|
crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
|
||||||
crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
|
crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
|
||||||
|
crate::transmute::EAGER_TRANSMUTE_INFO,
|
||||||
crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
|
crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
|
||||||
crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
|
crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
|
||||||
crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
|
crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
|
||||||
|
@ -676,6 +680,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::types::REDUNDANT_ALLOCATION_INFO,
|
crate::types::REDUNDANT_ALLOCATION_INFO,
|
||||||
crate::types::TYPE_COMPLEXITY_INFO,
|
crate::types::TYPE_COMPLEXITY_INFO,
|
||||||
crate::types::VEC_BOX_INFO,
|
crate::types::VEC_BOX_INFO,
|
||||||
|
crate::unconditional_recursion::UNCONDITIONAL_RECURSION_INFO,
|
||||||
crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
|
crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
|
||||||
crate::undocumented_unsafe_blocks::UNNECESSARY_SAFETY_COMMENT_INFO,
|
crate::undocumented_unsafe_blocks::UNNECESSARY_SAFETY_COMMENT_INFO,
|
||||||
crate::unicode::INVISIBLE_CHARACTERS_INFO,
|
crate::unicode::INVISIBLE_CHARACTERS_INFO,
|
||||||
|
|
|
@ -42,7 +42,7 @@ declare_clippy_lint! {
|
||||||
#[clippy::version = "1.71.0"]
|
#[clippy::version = "1.71.0"]
|
||||||
pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
|
pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
|
||||||
complexity,
|
complexity,
|
||||||
"unit structs can be contructed without calling `default`"
|
"unit structs can be constructed without calling `default`"
|
||||||
}
|
}
|
||||||
declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
|
declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||||
Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => {
|
Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => {
|
||||||
arms.iter().any(|arm| is_format(cx, arm.body))
|
arms.iter().any(|arm| is_format(cx, arm.body))
|
||||||
},
|
},
|
||||||
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
|
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else, _)) => {
|
||||||
is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
|
is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -158,7 +158,7 @@ fn try_resolve_type<'tcx>(
|
||||||
|
|
||||||
/// This function tries to, for all generic type parameters in a supertrait predicate `trait ...<U>:
|
/// This function tries to, for all generic type parameters in a supertrait predicate `trait ...<U>:
|
||||||
/// GenericTrait<U>`, check if the substituted type in the implied-by bound matches with what's
|
/// GenericTrait<U>`, check if the substituted type in the implied-by bound matches with what's
|
||||||
/// subtituted in the implied bound.
|
/// substituted in the implied bound.
|
||||||
///
|
///
|
||||||
/// Consider this example.
|
/// Consider this example.
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
|
|
|
@ -170,7 +170,23 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Index is a constant uint.
|
// Index is a constant uint.
|
||||||
if constant(cx, cx.typeck_results(), index).is_some() {
|
if let Some(constant) = constant(cx, cx.typeck_results(), index) {
|
||||||
|
// only `usize` index is legal in rust array index
|
||||||
|
// leave other type to rustc
|
||||||
|
if let Constant::Int(off) = constant
|
||||||
|
&& let ty::Uint(utype) = cx.typeck_results().expr_ty(index).kind()
|
||||||
|
&& *utype == ty::UintTy::Usize
|
||||||
|
&& let ty::Array(_, s) = ty.kind()
|
||||||
|
&& let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env)
|
||||||
|
{
|
||||||
|
// get constant offset and check whether it is in bounds
|
||||||
|
let off = usize::try_from(off).unwrap();
|
||||||
|
let size = usize::try_from(size).unwrap();
|
||||||
|
|
||||||
|
if off >= size {
|
||||||
|
span_lint(cx, OUT_OF_BOUNDS_INDEXING, expr.span, "index is out of bounds");
|
||||||
|
}
|
||||||
|
}
|
||||||
// Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
|
// Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ declare_clippy_lint! {
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// `.append(true)` already enables `write(true)`, making this one
|
/// `.append(true)` already enables `write(true)`, making this one
|
||||||
/// superflous.
|
/// superfluous.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
|
|
|
@ -49,7 +49,7 @@ declare_clippy_lint! {
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.74.0"]
|
#[clippy::version = "1.75.0"]
|
||||||
pub ITER_WITHOUT_INTO_ITER,
|
pub ITER_WITHOUT_INTO_ITER,
|
||||||
pedantic,
|
pedantic,
|
||||||
"implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl"
|
"implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl"
|
||||||
|
@ -101,7 +101,7 @@ declare_clippy_lint! {
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.74.0"]
|
#[clippy::version = "1.75.0"]
|
||||||
pub INTO_ITER_WITHOUT_ITER,
|
pub INTO_ITER_WITHOUT_ITER,
|
||||||
pedantic,
|
pedantic,
|
||||||
"implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method"
|
"implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method"
|
||||||
|
|
|
@ -8,8 +8,8 @@ use rustc_hir::def::Res;
|
||||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
|
||||||
ImplicitSelfKind, Item, ItemKind, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
|
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
|
||||||
TyKind, TypeBindingKind, OpaqueTyOrigin,
|
TraitItemRef, TyKind, TypeBindingKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
// FIXME: switch to something more ergonomic here, once available.
|
// FIXME: switch to something more ergonomic here, once available.
|
||||||
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
|
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
|
||||||
extern crate pulldown_cmark;
|
extern crate pulldown_cmark;
|
||||||
|
extern crate rustc_abi;
|
||||||
extern crate rustc_arena;
|
extern crate rustc_arena;
|
||||||
extern crate rustc_ast;
|
extern crate rustc_ast;
|
||||||
extern crate rustc_ast_pretty;
|
extern crate rustc_ast_pretty;
|
||||||
|
@ -327,6 +328,7 @@ mod trait_bounds;
|
||||||
mod transmute;
|
mod transmute;
|
||||||
mod tuple_array_conversions;
|
mod tuple_array_conversions;
|
||||||
mod types;
|
mod types;
|
||||||
|
mod unconditional_recursion;
|
||||||
mod undocumented_unsafe_blocks;
|
mod undocumented_unsafe_blocks;
|
||||||
mod unicode;
|
mod unicode;
|
||||||
mod uninhabited_references;
|
mod uninhabited_references;
|
||||||
|
@ -1078,6 +1080,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
||||||
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
|
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
|
||||||
store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
|
store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
|
||||||
store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
|
store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
|
||||||
|
store.register_late_pass(|_| Box::new(unconditional_recursion::UnconditionalRecursion));
|
||||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(
|
||||||
if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret {
|
if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret {
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
ret_span,
|
ret_span,
|
||||||
"if this is intentional, consider specifing `!` as function return",
|
"if this is intentional, consider specifying `!` as function return",
|
||||||
" -> !",
|
" -> !",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
let inner_expr = peel_blocks_with_stmt(body);
|
let inner_expr = peel_blocks_with_stmt(body);
|
||||||
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
|
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None, .. })
|
||||||
= higher::IfLet::hir(cx, inner_expr)
|
= higher::IfLet::hir(cx, inner_expr)
|
||||||
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
|
// 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
|
&& let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr)
|
if let Some(higher::WhileLet { if_then, let_pat, let_expr, .. }) = higher::WhileLet::hir(expr)
|
||||||
// check for `Some(..)` pattern
|
// check for `Some(..)` pattern
|
||||||
&& let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
|
&& 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)
|
&& is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
|
||||||
|
|
|
@ -36,7 +36,8 @@ struct PathAndSpan {
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `MacroRefData` includes the name of the macro.
|
/// `MacroRefData` includes the name of the macro
|
||||||
|
/// and the path from `SourceMap::span_to_filename`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MacroRefData {
|
pub struct MacroRefData {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
|
@ -3,9 +3,9 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::FnKind;
|
use rustc_hir::intravisit::FnKind;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
Block, Body, Closure, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy,
|
Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
|
||||||
GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind,
|
FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind,
|
||||||
TypeBindingKind, ClosureKind,
|
TypeBindingKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::declare_lint_pass;
|
use rustc_session::declare_lint_pass;
|
||||||
|
@ -172,23 +172,13 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
|
||||||
.all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
|
.all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desugared_async_block<'tcx>(
|
fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
|
||||||
cx: &LateContext<'tcx>,
|
|
||||||
block: &'tcx Block<'tcx>,
|
|
||||||
) -> Option<&'tcx Body<'tcx>> {
|
|
||||||
if let Some(Expr {
|
if let Some(Expr {
|
||||||
kind:
|
kind: ExprKind::Closure(&Closure { kind, body, .. }),
|
||||||
ExprKind::Closure(&Closure {
|
|
||||||
kind:
|
|
||||||
ClosureKind::Coroutine(CoroutineKind::Desugared(
|
|
||||||
CoroutineDesugaring::Async,
|
|
||||||
CoroutineSource::Block,
|
|
||||||
)),
|
|
||||||
body,
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
..
|
||||||
}) = block.expr
|
}) = block.expr
|
||||||
|
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) =
|
||||||
|
kind
|
||||||
{
|
{
|
||||||
return Some(cx.tcx.hir().body(body));
|
return Some(cx.tcx.hir().body(body));
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ declare_clippy_lint! {
|
||||||
///
|
///
|
||||||
/// let hash = s.hash_one(&value);
|
/// let hash = s.hash_one(&value);
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.74.0"]
|
#[clippy::version = "1.75.0"]
|
||||||
pub MANUAL_HASH_ONE,
|
pub MANUAL_HASH_ONE,
|
||||||
complexity,
|
complexity,
|
||||||
"manual implementations of `BuildHasher::hash_one`"
|
"manual implementations of `BuildHasher::hash_one`"
|
||||||
|
|
|
@ -61,7 +61,7 @@ impl<'tcx> QuestionMark {
|
||||||
&& let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
|
&& let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
|
||||||
{
|
{
|
||||||
match if_let_or_match {
|
match if_let_or_match {
|
||||||
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
|
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
|
||||||
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
|
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
|
||||||
&& let Some(if_else) = if_else
|
&& let Some(if_else) = if_else
|
||||||
&& is_never_expr(cx, if_else).is_some()
|
&& is_never_expr(cx, if_else).is_some()
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn check_arm<'tcx>(
|
||||||
let inner_expr = peel_blocks_with_stmt(outer_then_body);
|
let inner_expr = peel_blocks_with_stmt(outer_then_body);
|
||||||
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
|
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
|
||||||
&& let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
|
&& let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
|
||||||
IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)),
|
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())
|
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
|
// if there are more than two arms, collapsing would be non-trivial
|
||||||
// one of the arms must be "wild-like"
|
// one of the arms must be "wild-like"
|
||||||
|
@ -75,7 +75,7 @@ fn check_arm<'tcx>(
|
||||||
)
|
)
|
||||||
// ...or anywhere in the inner expression
|
// ...or anywhere in the inner expression
|
||||||
&& match inner {
|
&& match inner {
|
||||||
IfLetOrMatch::IfLet(_, _, body, els) => {
|
IfLetOrMatch::IfLet(_, _, body, els, _) => {
|
||||||
!is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id))
|
!is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id))
|
||||||
},
|
},
|
||||||
IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),
|
IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),
|
||||||
|
|
|
@ -63,9 +63,7 @@ where
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(some_expr) = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt) else {
|
let some_expr = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt)?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
// These two lints will go back and forth with each other.
|
// These two lints will go back and forth with each other.
|
||||||
if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
|
if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
|
||||||
|
|
|
@ -469,15 +469,15 @@ declare_clippy_lint! {
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Lint for redundant pattern matching over `Result`, `Option`,
|
/// Lint for redundant pattern matching over `Result`, `Option`,
|
||||||
/// `std::task::Poll` or `std::net::IpAddr`
|
/// `std::task::Poll`, `std::net::IpAddr` or `bool`s
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// It's more concise and clear to just use the proper
|
/// It's more concise and clear to just use the proper
|
||||||
/// utility function
|
/// utility function or using the condition directly
|
||||||
///
|
///
|
||||||
/// ### Known problems
|
/// ### Known problems
|
||||||
/// This will change the drop order for the matched type. Both `if let` and
|
/// For suggestions involving bindings in patterns, this will change the drop order for the matched type.
|
||||||
/// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
|
/// Both `if let` and `while let` will drop the value at the end of the block, both `if` and `while` will drop the
|
||||||
/// value before entering the block. For most types this change will not matter, but for a few
|
/// value before entering the block. For most types this change will not matter, but for a few
|
||||||
/// types this will not be an acceptable change (e.g. locks). See the
|
/// types this will not be an acceptable change (e.g. locks). See the
|
||||||
/// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
|
/// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
|
||||||
|
@ -499,6 +499,10 @@ declare_clippy_lint! {
|
||||||
/// Ok(_) => true,
|
/// Ok(_) => true,
|
||||||
/// Err(_) => false,
|
/// Err(_) => false,
|
||||||
/// };
|
/// };
|
||||||
|
///
|
||||||
|
/// let cond = true;
|
||||||
|
/// if let true = cond {}
|
||||||
|
/// matches!(cond, true);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The more idiomatic use would be:
|
/// The more idiomatic use would be:
|
||||||
|
@ -515,6 +519,10 @@ declare_clippy_lint! {
|
||||||
/// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
|
/// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
|
||||||
/// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
|
/// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
|
||||||
/// Ok::<i32, i32>(42).is_ok();
|
/// Ok::<i32, i32>(42).is_ok();
|
||||||
|
///
|
||||||
|
/// let cond = true;
|
||||||
|
/// if cond {}
|
||||||
|
/// cond;
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.31.0"]
|
#[clippy::version = "1.31.0"]
|
||||||
pub REDUNDANT_PATTERN_MATCHING,
|
pub REDUNDANT_PATTERN_MATCHING,
|
||||||
|
@ -1019,8 +1027,11 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||||
let from_expansion = expr.span.from_expansion();
|
let from_expansion = expr.span.from_expansion();
|
||||||
|
|
||||||
if let ExprKind::Match(ex, arms, source) = expr.kind {
|
if let ExprKind::Match(ex, arms, source) = expr.kind {
|
||||||
if is_direct_expn_of(expr.span, "matches").is_some() {
|
if is_direct_expn_of(expr.span, "matches").is_some()
|
||||||
|
&& let [arm, _] = arms
|
||||||
|
{
|
||||||
redundant_pattern_match::check_match(cx, expr, ex, arms);
|
redundant_pattern_match::check_match(cx, expr, ex, arms);
|
||||||
|
redundant_pattern_match::check_matches_true(cx, expr, arm, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
|
if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
|
||||||
|
@ -1104,6 +1115,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
|
||||||
if_let.let_pat,
|
if_let.let_pat,
|
||||||
if_let.let_expr,
|
if_let.let_expr,
|
||||||
if_let.if_else.is_some(),
|
if_let.if_else.is_some(),
|
||||||
|
if_let.let_span,
|
||||||
);
|
);
|
||||||
needless_match::check_if_let(cx, expr, &if_let);
|
needless_match::check_if_let(cx, expr, &if_let);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::REDUNDANT_PATTERN_MATCHING;
|
use super::REDUNDANT_PATTERN_MATCHING;
|
||||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||||
use clippy_utils::source::{snippet, walk_span_to_context};
|
use clippy_utils::source::{snippet, walk_span_to_context};
|
||||||
use clippy_utils::sugg::Sugg;
|
use clippy_utils::sugg::{make_unop, Sugg};
|
||||||
use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
|
use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
|
||||||
use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
|
use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
|
||||||
use clippy_utils::{higher, is_expn_of, is_trait_method};
|
use clippy_utils::{higher, is_expn_of, is_trait_method};
|
||||||
|
@ -12,13 +12,20 @@ use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady,
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
|
use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
use rustc_middle::ty::{self, GenericArgKind, Ty};
|
||||||
use rustc_span::{sym, Symbol};
|
use rustc_span::{sym, Span, Symbol};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
|
if let Some(higher::WhileLet {
|
||||||
find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
|
let_pat,
|
||||||
|
let_expr,
|
||||||
|
let_span,
|
||||||
|
..
|
||||||
|
}) = higher::WhileLet::hir(expr)
|
||||||
|
{
|
||||||
|
find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
|
||||||
|
find_if_let_true(cx, let_pat, let_expr, let_span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +35,73 @@ pub(super) fn check_if_let<'tcx>(
|
||||||
pat: &'tcx Pat<'_>,
|
pat: &'tcx Pat<'_>,
|
||||||
scrutinee: &'tcx Expr<'_>,
|
scrutinee: &'tcx Expr<'_>,
|
||||||
has_else: bool,
|
has_else: bool,
|
||||||
|
let_span: Span,
|
||||||
) {
|
) {
|
||||||
find_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
|
find_if_let_true(cx, pat, scrutinee, let_span);
|
||||||
|
find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Looks for:
|
||||||
|
/// * `matches!(expr, true)`
|
||||||
|
pub fn check_matches_true<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
expr: &'tcx Expr<'_>,
|
||||||
|
arm: &'tcx Arm<'_>,
|
||||||
|
scrutinee: &'tcx Expr<'_>,
|
||||||
|
) {
|
||||||
|
find_match_true(
|
||||||
|
cx,
|
||||||
|
arm.pat,
|
||||||
|
scrutinee,
|
||||||
|
expr.span.source_callsite(),
|
||||||
|
"using `matches!` to pattern match a bool",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Looks for any of:
|
||||||
|
/// * `if let true = ...`
|
||||||
|
/// * `if let false = ...`
|
||||||
|
/// * `while let true = ...`
|
||||||
|
fn find_if_let_true<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, let_span: Span) {
|
||||||
|
find_match_true(cx, pat, scrutinee, let_span, "using `if let` to pattern match a bool");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Common logic between `find_if_let_true` and `check_matches_true`
|
||||||
|
fn find_match_true<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
pat: &'tcx Pat<'_>,
|
||||||
|
scrutinee: &'tcx Expr<'_>,
|
||||||
|
span: Span,
|
||||||
|
message: &str,
|
||||||
|
) {
|
||||||
|
if let PatKind::Lit(lit) = pat.kind
|
||||||
|
&& let ExprKind::Lit(lit) = lit.kind
|
||||||
|
&& let LitKind::Bool(pat_is_true) = lit.node
|
||||||
|
{
|
||||||
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
|
||||||
|
let mut sugg = Sugg::hir_with_context(
|
||||||
|
cx,
|
||||||
|
scrutinee,
|
||||||
|
scrutinee.span.source_callsite().ctxt(),
|
||||||
|
"..",
|
||||||
|
&mut applicability,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !pat_is_true {
|
||||||
|
sugg = make_unop("!", sugg);
|
||||||
|
}
|
||||||
|
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
REDUNDANT_PATTERN_MATCHING,
|
||||||
|
span,
|
||||||
|
message,
|
||||||
|
"consider using the condition directly",
|
||||||
|
sugg.to_string(),
|
||||||
|
applicability,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the generic arguments out of a type
|
// Extract the generic arguments out of a type
|
||||||
|
@ -56,9 +128,7 @@ fn find_method_and_type<'tcx>(
|
||||||
|
|
||||||
if is_wildcard || is_rest {
|
if is_wildcard || is_rest {
|
||||||
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
|
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
|
||||||
let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else {
|
let id = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id))?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let lang_items = cx.tcx.lang_items();
|
let lang_items = cx.tcx.lang_items();
|
||||||
if Some(id) == lang_items.result_ok_variant() {
|
if Some(id) == lang_items.result_ok_variant() {
|
||||||
Some(("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)))
|
Some(("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)))
|
||||||
|
@ -100,7 +170,7 @@ fn find_method_and_type<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_sugg_for_if_let<'tcx>(
|
fn find_method_sugg_for_if_let<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
expr: &'tcx Expr<'_>,
|
expr: &'tcx Expr<'_>,
|
||||||
let_pat: &Pat<'_>,
|
let_pat: &Pat<'_>,
|
||||||
|
@ -341,31 +411,25 @@ fn get_good_method<'tcx>(
|
||||||
path_left: &QPath<'_>,
|
path_left: &QPath<'_>,
|
||||||
) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
|
) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
|
||||||
if let Some(name) = get_ident(path_left) {
|
if let Some(name) = get_ident(path_left) {
|
||||||
return match name.as_str() {
|
let (expected_item_left, should_be_left, should_be_right) = match name.as_str() {
|
||||||
"Ok" => {
|
"Ok" => (Item::Lang(ResultOk), "is_ok()", "is_err()"),
|
||||||
find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultOk), "is_ok()", "is_err()")
|
"Err" => (Item::Lang(ResultErr), "is_err()", "is_ok()"),
|
||||||
},
|
"Some" => (Item::Lang(OptionSome), "is_some()", "is_none()"),
|
||||||
"Err" => {
|
"None" => (Item::Lang(OptionNone), "is_none()", "is_some()"),
|
||||||
find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultErr), "is_err()", "is_ok()")
|
"Ready" => (Item::Lang(PollReady), "is_ready()", "is_pending()"),
|
||||||
},
|
"Pending" => (Item::Lang(PollPending), "is_pending()", "is_ready()"),
|
||||||
"Some" => find_good_method_for_matches_macro(
|
"V4" => (Item::Diag(sym::IpAddr, sym!(V4)), "is_ipv4()", "is_ipv6()"),
|
||||||
cx,
|
"V6" => (Item::Diag(sym::IpAddr, sym!(V6)), "is_ipv6()", "is_ipv4()"),
|
||||||
arms,
|
_ => return None,
|
||||||
path_left,
|
|
||||||
Item::Lang(OptionSome),
|
|
||||||
"is_some()",
|
|
||||||
"is_none()",
|
|
||||||
),
|
|
||||||
"None" => find_good_method_for_matches_macro(
|
|
||||||
cx,
|
|
||||||
arms,
|
|
||||||
path_left,
|
|
||||||
Item::Lang(OptionNone),
|
|
||||||
"is_none()",
|
|
||||||
"is_some()",
|
|
||||||
),
|
|
||||||
_ => None,
|
|
||||||
};
|
};
|
||||||
|
return find_good_method_for_matches_macro(
|
||||||
|
cx,
|
||||||
|
arms,
|
||||||
|
path_left,
|
||||||
|
expected_item_left,
|
||||||
|
should_be_left,
|
||||||
|
should_be_right,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP};
|
use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP};
|
||||||
|
|
||||||
fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
|
fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
|
@ -22,6 +22,7 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
|
||||||
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
|
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
|
||||||
segments.segments.last().unwrap().ident.name == method_name
|
segments.segments.last().unwrap().ident.name == method_name
|
||||||
},
|
},
|
||||||
|
hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
|
||||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||||
let body = cx.tcx.hir().body(body);
|
let body = cx.tcx.hir().body(body);
|
||||||
let closure_expr = peel_blocks(body.value);
|
let closure_expr = peel_blocks(body.value);
|
||||||
|
@ -46,6 +47,9 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
|
||||||
fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
|
fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
|
||||||
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
|
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
|
||||||
}
|
}
|
||||||
|
fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
|
||||||
|
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
enum OffendingFilterExpr<'tcx> {
|
enum OffendingFilterExpr<'tcx> {
|
||||||
|
@ -186,7 +190,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
|
||||||
match higher::IfLetOrMatch::parse(cx, map_body.value) {
|
match higher::IfLetOrMatch::parse(cx, map_body.value) {
|
||||||
// For `if let` we want to check that the variant matching arm references the local created by
|
// For `if let` we want to check that the variant matching arm references the local created by
|
||||||
// its pattern
|
// its pattern
|
||||||
Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
|
Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_), ..))
|
||||||
if let Some((ident, span)) = expr_uses_local(pat, then) =>
|
if let Some((ident, span)) = expr_uses_local(pat, then) =>
|
||||||
{
|
{
|
||||||
(sc, else_, ident, span)
|
(sc, else_, ident, span)
|
||||||
|
@ -273,6 +277,18 @@ fn is_filter_some_map_unwrap(
|
||||||
(iterator || option) && is_option_filter_map(cx, filter_arg, map_arg)
|
(iterator || option) && is_option_filter_map(cx, filter_arg, map_arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// is `filter(|x| x.is_ok()).map(|x| x.unwrap())`
|
||||||
|
fn is_filter_ok_map_unwrap(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
filter_arg: &hir::Expr<'_>,
|
||||||
|
map_arg: &hir::Expr<'_>,
|
||||||
|
) -> bool {
|
||||||
|
// result has no filter, so we only check for iterators
|
||||||
|
let iterator = is_trait_method(cx, expr, sym::Iterator);
|
||||||
|
iterator && is_ok_filter_map(cx, filter_arg, map_arg)
|
||||||
|
}
|
||||||
|
|
||||||
/// lint use of `filter().map()` or `find().map()` for `Iterators`
|
/// lint use of `filter().map()` or `find().map()` for `Iterators`
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(super) fn check(
|
pub(super) fn check(
|
||||||
|
@ -300,30 +316,21 @@ pub(super) fn check(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_trait_method(cx, map_recv, sym::Iterator)
|
if is_filter_ok_map_unwrap(cx, expr, filter_arg, map_arg) {
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
RESULT_FILTER_MAP,
|
||||||
|
filter_span.with_hi(expr.span.hi()),
|
||||||
|
"`filter` for `Ok` followed by `unwrap`",
|
||||||
|
"consider using `flatten` instead",
|
||||||
|
reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
|
||||||
// filter(|x| ...is_some())...
|
return;
|
||||||
&& let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
|
}
|
||||||
&& let filter_body = cx.tcx.hir().body(filter_body_id)
|
|
||||||
&& let [filter_param] = filter_body.params
|
|
||||||
// optional ref pattern: `filter(|&x| ..)`
|
|
||||||
&& let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
|
||||||
(ref_pat, true)
|
|
||||||
} else {
|
|
||||||
(filter_param.pat, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
&& let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind
|
if let Some((map_param_ident, check_result)) = is_find_or_filter(cx, map_recv, filter_arg, map_arg) {
|
||||||
&& let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
|
|
||||||
|
|
||||||
&& let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
|
|
||||||
&& let map_body = cx.tcx.hir().body(map_body_id)
|
|
||||||
&& let [map_param] = map_body.params
|
|
||||||
&& let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind
|
|
||||||
|
|
||||||
&& let Some(check_result) =
|
|
||||||
offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref)
|
|
||||||
{
|
|
||||||
let span = filter_span.with_hi(expr.span.hi());
|
let span = filter_span.with_hi(expr.span.hi());
|
||||||
let (filter_name, lint) = if is_find {
|
let (filter_name, lint) = if is_find {
|
||||||
("find", MANUAL_FIND_MAP)
|
("find", MANUAL_FIND_MAP)
|
||||||
|
@ -395,6 +402,40 @@ pub(super) fn check(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_find_or_filter<'a>(
|
||||||
|
cx: &LateContext<'a>,
|
||||||
|
map_recv: &hir::Expr<'_>,
|
||||||
|
filter_arg: &hir::Expr<'_>,
|
||||||
|
map_arg: &hir::Expr<'_>,
|
||||||
|
) -> Option<(Ident, CheckResult<'a>)> {
|
||||||
|
if is_trait_method(cx, map_recv, sym::Iterator)
|
||||||
|
// filter(|x| ...is_some())...
|
||||||
|
&& let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
|
||||||
|
&& let filter_body = cx.tcx.hir().body(filter_body_id)
|
||||||
|
&& let [filter_param] = filter_body.params
|
||||||
|
// optional ref pattern: `filter(|&x| ..)`
|
||||||
|
&& let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
||||||
|
(ref_pat, true)
|
||||||
|
} else {
|
||||||
|
(filter_param.pat, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
&& let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind
|
||||||
|
&& let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
|
||||||
|
|
||||||
|
&& let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
|
||||||
|
&& let map_body = cx.tcx.hir().body(map_body_id)
|
||||||
|
&& let [map_param] = map_body.params
|
||||||
|
&& let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind
|
||||||
|
|
||||||
|
&& let Some(check_result) =
|
||||||
|
offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref)
|
||||||
|
{
|
||||||
|
return Some((map_param_ident, check_result));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn acceptable_methods(method: &PathSegment<'_>) -> bool {
|
fn acceptable_methods(method: &PathSegment<'_>) -> bool {
|
||||||
let methods: [Symbol; 8] = [
|
let methods: [Symbol; 8] = [
|
||||||
sym::clone,
|
sym::clone,
|
||||||
|
|
87
clippy_lints/src/methods/iter_filter.rs
Normal file
87
clippy_lints/src/methods/iter_filter.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
use rustc_lint::{LateContext, LintContext};
|
||||||
|
|
||||||
|
use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME};
|
||||||
|
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::source::{indent_of, reindent_multiline};
|
||||||
|
use clippy_utils::{is_trait_method, peel_blocks, span_contains_comment};
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::Res;
|
||||||
|
use rustc_hir::QPath;
|
||||||
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
use rustc_span::Span;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
|
||||||
|
match &expr.kind {
|
||||||
|
hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
|
||||||
|
hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
|
||||||
|
segments.segments.last().unwrap().ident.name == method_name
|
||||||
|
},
|
||||||
|
hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
|
||||||
|
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||||
|
let body = cx.tcx.hir().body(body);
|
||||||
|
let closure_expr = peel_blocks(body.value);
|
||||||
|
let arg_id = body.params[0].pat.hir_id;
|
||||||
|
match closure_expr.kind {
|
||||||
|
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
|
||||||
|
if ident.name == method_name
|
||||||
|
&& let hir::ExprKind::Path(path) = &receiver.kind
|
||||||
|
&& let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id)
|
||||||
|
{
|
||||||
|
return arg_id == *local;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||||
|
if let hir::Node::Expr(parent_expr) = cx.tcx.hir().get_parent(expr.hir_id) {
|
||||||
|
is_method(cx, parent_expr, rustc_span::sym::map)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) {
|
||||||
|
let is_iterator = is_trait_method(cx, expr, sym::Iterator);
|
||||||
|
let parent_is_not_map = !parent_is_map(cx, expr);
|
||||||
|
|
||||||
|
if is_iterator
|
||||||
|
&& parent_is_not_map
|
||||||
|
&& is_method(cx, filter_arg, sym!(is_some))
|
||||||
|
&& !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
|
||||||
|
{
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
ITER_FILTER_IS_SOME,
|
||||||
|
filter_span.with_hi(expr.span.hi()),
|
||||||
|
"`filter` for `is_some` on iterator over `Option`",
|
||||||
|
"consider using `flatten` instead",
|
||||||
|
reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if is_iterator
|
||||||
|
&& parent_is_not_map
|
||||||
|
&& is_method(cx, filter_arg, sym!(is_ok))
|
||||||
|
&& !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
|
||||||
|
{
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
ITER_FILTER_IS_OK,
|
||||||
|
filter_span.with_hi(expr.span.hi()),
|
||||||
|
"`filter` for `is_ok` on iterator over `Result`s",
|
||||||
|
"consider using `flatten` instead",
|
||||||
|
reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ mod into_iter_on_ref;
|
||||||
mod is_digit_ascii_radix;
|
mod is_digit_ascii_radix;
|
||||||
mod iter_cloned_collect;
|
mod iter_cloned_collect;
|
||||||
mod iter_count;
|
mod iter_count;
|
||||||
|
mod iter_filter;
|
||||||
mod iter_kv_map;
|
mod iter_kv_map;
|
||||||
mod iter_next_slice;
|
mod iter_next_slice;
|
||||||
mod iter_nth;
|
mod iter_nth;
|
||||||
|
@ -1175,7 +1176,8 @@ declare_clippy_lint! {
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Checks for indirect collection of populated `Option`
|
/// Checks for iterators of `Option`s using `.filter(Option::is_some).map(Option::unwrap)` that may
|
||||||
|
/// be replaced with a `.flatten()` call.
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// `Option` is like a collection of 0-1 things, so `flatten`
|
/// `Option` is like a collection of 0-1 things, so `flatten`
|
||||||
|
@ -3752,6 +3754,81 @@ declare_clippy_lint! {
|
||||||
"using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`"
|
"using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for iterators of `Result`s using `.filter(Result::is_ok).map(Result::unwrap)` that may
|
||||||
|
/// be replaced with a `.flatten()` call.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// `Result` implements `IntoIterator<Item = T>`. This means that `Result` can be flattened
|
||||||
|
/// automatically without suspicious-looking `unwrap` calls.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```no_run
|
||||||
|
/// let _ = std::iter::empty::<Result<i32, ()>>().filter(Result::is_ok).map(Result::unwrap);
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```no_run
|
||||||
|
/// let _ = std::iter::empty::<Result<i32, ()>>().flatten();
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.76.0"]
|
||||||
|
pub RESULT_FILTER_MAP,
|
||||||
|
complexity,
|
||||||
|
"filtering `Result` for `Ok` then force-unwrapping, which can be one type-safe operation"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for usage of `.filter(Option::is_some)` that may be replaced with a `.flatten()` call.
|
||||||
|
/// This lint will require additional changes to the follow-up calls as it appects the type.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// This pattern is often followed by manual unwrapping of the `Option`. The simplification
|
||||||
|
/// results in more readable and succint code without the need for manual unwrapping.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```no_run
|
||||||
|
/// // example code where clippy issues a warning
|
||||||
|
/// vec![Some(1)].into_iter().filter(Option::is_some);
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```no_run
|
||||||
|
/// // example code which does not raise clippy warning
|
||||||
|
/// vec![Some(1)].into_iter().flatten();
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.76.0"]
|
||||||
|
pub ITER_FILTER_IS_SOME,
|
||||||
|
pedantic,
|
||||||
|
"filtering an iterator over `Option`s for `Some` can be achieved with `flatten`"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call.
|
||||||
|
/// This lint will require additional changes to the follow-up calls as it appects the type.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// This pattern is often followed by manual unwrapping of `Result`. The simplification
|
||||||
|
/// results in more readable and succint code without the need for manual unwrapping.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```no_run
|
||||||
|
/// // example code where clippy issues a warning
|
||||||
|
/// vec![Ok::<i32, String>(1)].into_iter().filter(Result::is_ok);
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```no_run
|
||||||
|
/// // example code which does not raise clippy warning
|
||||||
|
/// vec![Ok::<i32, String>(1)].into_iter().flatten();
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.76.0"]
|
||||||
|
pub ITER_FILTER_IS_OK,
|
||||||
|
pedantic,
|
||||||
|
"filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`"
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Methods {
|
pub struct Methods {
|
||||||
avoid_breaking_exported_api: bool,
|
avoid_breaking_exported_api: bool,
|
||||||
msrv: Msrv,
|
msrv: Msrv,
|
||||||
|
@ -3903,6 +3980,9 @@ impl_lint_pass!(Methods => [
|
||||||
UNNECESSARY_FALLIBLE_CONVERSIONS,
|
UNNECESSARY_FALLIBLE_CONVERSIONS,
|
||||||
JOIN_ABSOLUTE_PATHS,
|
JOIN_ABSOLUTE_PATHS,
|
||||||
OPTION_MAP_OR_ERR_OK,
|
OPTION_MAP_OR_ERR_OK,
|
||||||
|
RESULT_FILTER_MAP,
|
||||||
|
ITER_FILTER_IS_SOME,
|
||||||
|
ITER_FILTER_IS_OK,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// Extracts a method call name, args, and `Span` of the method name.
|
/// Extracts a method call name, args, and `Span` of the method name.
|
||||||
|
@ -4232,7 +4312,24 @@ impl Methods {
|
||||||
string_extend_chars::check(cx, expr, recv, arg);
|
string_extend_chars::check(cx, expr, recv, arg);
|
||||||
extend_with_drain::check(cx, expr, recv, arg);
|
extend_with_drain::check(cx, expr, recv, arg);
|
||||||
},
|
},
|
||||||
(name @ ("filter" | "find"), [arg]) => {
|
("filter", [arg]) => {
|
||||||
|
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||||
|
// if `arg` has side-effect, the semantic will change
|
||||||
|
iter_overeager_cloned::check(
|
||||||
|
cx,
|
||||||
|
expr,
|
||||||
|
recv,
|
||||||
|
recv2,
|
||||||
|
iter_overeager_cloned::Op::FixClosure(name, arg),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if self.msrv.meets(msrvs::ITER_FLATTEN) {
|
||||||
|
// use the sourcemap to get the span of the closure
|
||||||
|
iter_filter::check(cx, expr, arg, span);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
("find", [arg]) => {
|
||||||
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||||
// if `arg` has side-effect, the semantic will change
|
// if `arg` has side-effect, the semantic will change
|
||||||
iter_overeager_cloned::check(
|
iter_overeager_cloned::check(
|
||||||
|
|
|
@ -5,7 +5,8 @@ use clippy_utils::ty::implements_trait;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty::{self, GenericArgKind};
|
use rustc_middle::ty;
|
||||||
|
use rustc_middle::ty::GenericArgKind;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid
|
||||||
use clippy_utils::visitors::find_all_ret_expressions;
|
use clippy_utils::visitors::find_all_ret_expressions;
|
||||||
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
|
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node};
|
use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node};
|
||||||
use rustc_hir_typeck::{FnCtxt, Inherited};
|
use rustc_hir_typeck::{FnCtxt, Inherited};
|
||||||
|
@ -37,6 +38,9 @@ pub fn check<'tcx>(
|
||||||
if is_cloned_or_copied(cx, method_name, method_def_id) {
|
if is_cloned_or_copied(cx, method_name, method_def_id) {
|
||||||
unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
|
unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
|
||||||
} else if is_to_owned_like(cx, expr, method_name, method_def_id) {
|
} else if is_to_owned_like(cx, expr, method_name, method_def_id) {
|
||||||
|
if check_split_call_arg(cx, expr, method_name, receiver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// At this point, we know the call is of a `to_owned`-like function. The functions
|
// At this point, we know the call is of a `to_owned`-like function. The functions
|
||||||
// `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
|
// `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
|
||||||
// based on its context, that is, whether it is a referent in an `AddrOf` expression, an
|
// based on its context, that is, whether it is a referent in an `AddrOf` expression, an
|
||||||
|
@ -233,6 +237,58 @@ fn check_into_iter_call_arg(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
|
||||||
|
/// call of a `to_owned`-like function is unnecessary.
|
||||||
|
fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
|
||||||
|
if let Some(parent) = get_parent_expr(cx, expr)
|
||||||
|
&& let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent)
|
||||||
|
&& fn_name.as_str() == "split"
|
||||||
|
&& let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
|
||||||
|
&& let Some(arg_snippet) = snippet_opt(cx, argument_expr.span)
|
||||||
|
{
|
||||||
|
// The next suggestion may be incorrect because the removal of the `to_owned`-like
|
||||||
|
// function could cause the iterator to hold a reference to a resource that is used
|
||||||
|
// mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
UNNECESSARY_TO_OWNED,
|
||||||
|
parent.span,
|
||||||
|
&format!("unnecessary use of `{method_name}`"),
|
||||||
|
"use",
|
||||||
|
format!("{receiver_snippet}.split({arg_snippet})"),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_fn_name_and_arg<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(Symbol, Expr<'tcx>)> {
|
||||||
|
match &expr.kind {
|
||||||
|
ExprKind::MethodCall(path, _, [arg_expr], ..) => Some((path.ident.name, *arg_expr)),
|
||||||
|
ExprKind::Call(
|
||||||
|
Expr {
|
||||||
|
kind: ExprKind::Path(qpath),
|
||||||
|
hir_id: path_hir_id,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
[arg_expr],
|
||||||
|
) => {
|
||||||
|
// Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
|
||||||
|
// deref to fn pointers, dyn Fn, impl Fn - #8850
|
||||||
|
if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, def_id) =
|
||||||
|
cx.typeck_results().qpath_res(qpath, *path_hir_id)
|
||||||
|
&& let Some(fn_name) = cx.tcx.opt_item_name(def_id)
|
||||||
|
{
|
||||||
|
Some((fn_name, *arg_expr))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks whether `expr` is an argument in a function call and, if so, determines whether its call
|
/// Checks whether `expr` is an argument in a function call and, if so, determines whether its call
|
||||||
/// of a `to_owned`-like function is unnecessary.
|
/// of a `to_owned`-like function is unnecessary.
|
||||||
fn check_other_call_arg<'tcx>(
|
fn check_other_call_arg<'tcx>(
|
||||||
|
|
|
@ -96,10 +96,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||||
self.found = true;
|
self.found = true;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
ExprKind::If(..) => {
|
|
||||||
self.found = true;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
ExprKind::Path(_) => {
|
ExprKind::Path(_) => {
|
||||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||||
if adj
|
if adj
|
||||||
|
|
|
@ -340,6 +340,12 @@ fn check_comparison<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
if l_ty.is_bool() && r_ty.is_bool() {
|
if l_ty.is_bool() && r_ty.is_bool() {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
// Eliminate parentheses in `e` by using the lo pos of lhs and hi pos of rhs,
|
||||||
|
// calling `source_callsite` make sure macros are handled correctly, see issue #9907
|
||||||
|
let binop_span = left_side
|
||||||
|
.span
|
||||||
|
.source_callsite()
|
||||||
|
.with_hi(right_side.span.source_callsite().hi());
|
||||||
|
|
||||||
if op.node == BinOpKind::Eq {
|
if op.node == BinOpKind::Eq {
|
||||||
let expression_info = one_side_is_unary_not(left_side, right_side);
|
let expression_info = one_side_is_unary_not(left_side, right_side);
|
||||||
|
@ -347,13 +353,23 @@ fn check_comparison<'a, 'tcx>(
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
BOOL_COMPARISON,
|
BOOL_COMPARISON,
|
||||||
e.span,
|
binop_span,
|
||||||
"this comparison might be written more concisely",
|
"this comparison might be written more concisely",
|
||||||
"try simplifying it as shown",
|
"try simplifying it as shown",
|
||||||
format!(
|
format!(
|
||||||
"{} != {}",
|
"{} != {}",
|
||||||
snippet_with_applicability(cx, expression_info.left_span, "..", &mut applicability),
|
snippet_with_applicability(
|
||||||
snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
|
cx,
|
||||||
|
expression_info.left_span.source_callsite(),
|
||||||
|
"..",
|
||||||
|
&mut applicability
|
||||||
|
),
|
||||||
|
snippet_with_applicability(
|
||||||
|
cx,
|
||||||
|
expression_info.right_span.source_callsite(),
|
||||||
|
"..",
|
||||||
|
&mut applicability
|
||||||
|
)
|
||||||
),
|
),
|
||||||
applicability,
|
applicability,
|
||||||
);
|
);
|
||||||
|
@ -362,16 +378,16 @@ fn check_comparison<'a, 'tcx>(
|
||||||
|
|
||||||
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
|
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
|
||||||
(Some(true), None) => left_true.map_or((), |(h, m)| {
|
(Some(true), None) => left_true.map_or((), |(h, m)| {
|
||||||
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
|
suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
|
||||||
}),
|
}),
|
||||||
(None, Some(true)) => right_true.map_or((), |(h, m)| {
|
(None, Some(true)) => right_true.map_or((), |(h, m)| {
|
||||||
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
|
suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
|
||||||
}),
|
}),
|
||||||
(Some(false), None) => left_false.map_or((), |(h, m)| {
|
(Some(false), None) => left_false.map_or((), |(h, m)| {
|
||||||
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
|
suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
|
||||||
}),
|
}),
|
||||||
(None, Some(false)) => right_false.map_or((), |(h, m)| {
|
(None, Some(false)) => right_false.map_or((), |(h, m)| {
|
||||||
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
|
suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
|
||||||
}),
|
}),
|
||||||
(None, None) => no_literal.map_or((), |(h, m)| {
|
(None, None) => no_literal.map_or((), |(h, m)| {
|
||||||
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
|
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
|
||||||
|
@ -379,7 +395,7 @@ fn check_comparison<'a, 'tcx>(
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
BOOL_COMPARISON,
|
BOOL_COMPARISON,
|
||||||
e.span,
|
binop_span,
|
||||||
m,
|
m,
|
||||||
"try simplifying it as shown",
|
"try simplifying it as shown",
|
||||||
h(left_side, right_side).to_string(),
|
h(left_side, right_side).to_string(),
|
||||||
|
@ -394,17 +410,17 @@ fn check_comparison<'a, 'tcx>(
|
||||||
|
|
||||||
fn suggest_bool_comparison<'a, 'tcx>(
|
fn suggest_bool_comparison<'a, 'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
e: &'tcx Expr<'_>,
|
span: Span,
|
||||||
expr: &Expr<'_>,
|
expr: &Expr<'_>,
|
||||||
mut app: Applicability,
|
mut app: Applicability,
|
||||||
message: &str,
|
message: &str,
|
||||||
conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
|
conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
|
||||||
) {
|
) {
|
||||||
let hint = Sugg::hir_with_context(cx, expr, e.span.ctxt(), "..", &mut app);
|
let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app);
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
BOOL_COMPARISON,
|
BOOL_COMPARISON,
|
||||||
e.span,
|
span,
|
||||||
message,
|
message,
|
||||||
"try simplifying it as shown",
|
"try simplifying it as shown",
|
||||||
conv_hint(hint).to_string(),
|
conv_hint(hint).to_string(),
|
||||||
|
|
|
@ -238,6 +238,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
|
||||||
let_expr,
|
let_expr,
|
||||||
if_then,
|
if_then,
|
||||||
if_else: Some(if_else),
|
if_else: Some(if_else),
|
||||||
|
..
|
||||||
}) = higher::IfLet::hir(cx, expr)
|
}) = higher::IfLet::hir(cx, expr)
|
||||||
&& !cx.typeck_results().expr_ty(expr).is_unit()
|
&& !cx.typeck_results().expr_ty(expr).is_unit()
|
||||||
&& !is_else_clause(cx.tcx, expr)
|
&& !is_else_clause(cx.tcx, expr)
|
||||||
|
|
|
@ -8,7 +8,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use clippy_utils::{
|
use clippy_utils::{
|
||||||
eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
|
eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
|
||||||
is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
|
is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
|
||||||
peel_blocks_with_stmt,
|
peel_blocks_with_stmt, span_contains_comment,
|
||||||
};
|
};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
|
@ -96,6 +96,24 @@ enum IfBlockType<'hir> {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir Expr<'hir>> {
|
||||||
|
if let Block {
|
||||||
|
stmts: &[],
|
||||||
|
expr: Some(els),
|
||||||
|
..
|
||||||
|
} = block
|
||||||
|
{
|
||||||
|
Some(els)
|
||||||
|
} else if let [stmt] = block.stmts
|
||||||
|
&& let StmtKind::Semi(expr) = stmt.kind
|
||||||
|
&& let ExprKind::Ret(..) = expr.kind
|
||||||
|
{
|
||||||
|
Some(expr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
||||||
if let StmtKind::Local(Local {
|
if let StmtKind::Local(Local {
|
||||||
pat,
|
pat,
|
||||||
|
@ -103,12 +121,9 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
||||||
els: Some(els),
|
els: Some(els),
|
||||||
..
|
..
|
||||||
}) = stmt.kind
|
}) = stmt.kind
|
||||||
&& let Block {
|
&& let Some(ret) = find_let_else_ret_expression(els)
|
||||||
stmts: &[],
|
&& let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret)
|
||||||
expr: Some(els),
|
&& !span_contains_comment(cx.tcx.sess.source_map(), els.span)
|
||||||
..
|
|
||||||
} = els
|
|
||||||
&& let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els)
|
|
||||||
{
|
{
|
||||||
let mut applicability = Applicability::MaybeIncorrect;
|
let mut applicability = Applicability::MaybeIncorrect;
|
||||||
let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability);
|
let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability);
|
||||||
|
@ -256,6 +271,7 @@ impl QuestionMark {
|
||||||
let_expr,
|
let_expr,
|
||||||
if_then,
|
if_then,
|
||||||
if_else,
|
if_else,
|
||||||
|
..
|
||||||
}) = higher::IfLet::hir(cx, expr)
|
}) = higher::IfLet::hir(cx, expr)
|
||||||
&& !is_else_clause(cx.tcx, expr)
|
&& !is_else_clause(cx.tcx, expr)
|
||||||
&& let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind
|
&& let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind
|
||||||
|
|
|
@ -3,9 +3,12 @@ use std::ops::ControlFlow;
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
use clippy_utils::peel_blocks;
|
use clippy_utils::peel_blocks;
|
||||||
use clippy_utils::source::{snippet, walk_span_to_context};
|
use clippy_utils::source::{snippet, walk_span_to_context};
|
||||||
|
use clippy_utils::ty::implements_trait;
|
||||||
use clippy_utils::visitors::for_each_expr;
|
use clippy_utils::visitors::for_each_expr;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Closure, ClosureKind, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource};
|
use rustc_hir::{
|
||||||
|
Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource,
|
||||||
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::UpvarCapture;
|
use rustc_middle::ty::UpvarCapture;
|
||||||
|
@ -49,6 +52,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
|
||||||
let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
|
let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
|
||||||
// The await prefix must not come from a macro as its content could change in the future.
|
// The await prefix must not come from a macro as its content could change in the future.
|
||||||
expr.span.eq_ctxt(body_expr.span) &&
|
expr.span.eq_ctxt(body_expr.span) &&
|
||||||
|
// The await prefix must implement Future, as implementing IntoFuture is not enough.
|
||||||
|
let Some(future_trait) = cx.tcx.lang_items().future_trait() &&
|
||||||
|
implements_trait(cx, cx.typeck_results().expr_ty(expr), future_trait, &[]) &&
|
||||||
// An async block does not have immediate side-effects from a `.await` point-of-view.
|
// An async block does not have immediate side-effects from a `.await` point-of-view.
|
||||||
(!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) &&
|
(!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) &&
|
||||||
let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt())
|
let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt())
|
||||||
|
@ -71,7 +77,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
|
||||||
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||||
if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind
|
if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind
|
||||||
&& let body = cx.tcx.hir().body(*body)
|
&& let body = cx.tcx.hir().body(*body)
|
||||||
&& matches!(kind, ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)))
|
&& matches!(
|
||||||
|
kind,
|
||||||
|
ClosureKind::Coroutine(CoroutineKind::Desugared(
|
||||||
|
CoroutineDesugaring::Async,
|
||||||
|
CoroutineSource::Block
|
||||||
|
))
|
||||||
|
)
|
||||||
{
|
{
|
||||||
cx.typeck_results()
|
cx.typeck_results()
|
||||||
.closure_min_captures
|
.closure_min_captures
|
||||||
|
|
|
@ -5,7 +5,7 @@ use clippy_utils::sugg::Sugg;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
|
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
|
||||||
use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node, ClosureKind};
|
use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
|
@ -66,7 +66,8 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor {
|
||||||
fn is_async_closure(body: &hir::Body<'_>) -> bool {
|
fn is_async_closure(body: &hir::Body<'_>) -> bool {
|
||||||
if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
|
if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
|
||||||
// checks whether it is `async || whatever_expression`
|
// checks whether it is `async || whatever_expression`
|
||||||
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind
|
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure))
|
||||||
|
= innermost_closure_generated_by_desugar.kind
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
74
clippy_lints/src/transmute/eager_transmute.rs
Normal file
74
clippy_lints/src/transmute/eager_transmute.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::ty::is_normalizable;
|
||||||
|
use clippy_utils::{path_to_local, path_to_local_id};
|
||||||
|
use rustc_abi::WrappingRange;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{Expr, ExprKind, Node};
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::ty::Ty;
|
||||||
|
|
||||||
|
use super::EAGER_TRANSMUTE;
|
||||||
|
|
||||||
|
fn peel_parent_unsafe_blocks<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
||||||
|
for (_, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
|
||||||
|
match parent {
|
||||||
|
Node::Block(_) => {},
|
||||||
|
Node::Expr(e) if let ExprKind::Block(..) = e.kind => {},
|
||||||
|
Node::Expr(e) => return Some(e),
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn range_fully_contained(from: WrappingRange, to: WrappingRange) -> bool {
|
||||||
|
to.contains(from.start) && to.contains(from.end)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn check<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
expr: &'tcx Expr<'tcx>,
|
||||||
|
transmutable: &'tcx Expr<'tcx>,
|
||||||
|
from_ty: Ty<'tcx>,
|
||||||
|
to_ty: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr)
|
||||||
|
&& let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind
|
||||||
|
&& cx.typeck_results().expr_ty(receiver).is_bool()
|
||||||
|
&& path.ident.name == sym!(then_some)
|
||||||
|
&& let ExprKind::Binary(_, lhs, rhs) = receiver.kind
|
||||||
|
&& let Some(local_id) = path_to_local(transmutable)
|
||||||
|
&& (path_to_local_id(lhs, local_id) || path_to_local_id(rhs, local_id))
|
||||||
|
&& is_normalizable(cx, cx.param_env, from_ty)
|
||||||
|
&& is_normalizable(cx, cx.param_env, to_ty)
|
||||||
|
// we only want to lint if the target type has a niche that is larger than the one of the source type
|
||||||
|
// e.g. `u8` to `NonZeroU8` should lint, but `NonZeroU8` to `u8` should not
|
||||||
|
&& let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from_ty))
|
||||||
|
&& let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to_ty))
|
||||||
|
&& match (from_layout.largest_niche, to_layout.largest_niche) {
|
||||||
|
(Some(from_niche), Some(to_niche)) => !range_fully_contained(from_niche.valid_range, to_niche.valid_range),
|
||||||
|
(None, Some(_)) => true,
|
||||||
|
(_, None) => false,
|
||||||
|
}
|
||||||
|
{
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
EAGER_TRANSMUTE,
|
||||||
|
expr.span,
|
||||||
|
"this transmute is always evaluated eagerly, even if the condition is false",
|
||||||
|
|diag| {
|
||||||
|
diag.multipart_suggestion(
|
||||||
|
"consider using `bool::then` to only transmute if the condition holds",
|
||||||
|
vec![
|
||||||
|
(path.ident.span, "then".into()),
|
||||||
|
(arg.span.shrink_to_lo(), "|| ".into()),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
mod crosspointer_transmute;
|
mod crosspointer_transmute;
|
||||||
|
mod eager_transmute;
|
||||||
mod transmute_float_to_int;
|
mod transmute_float_to_int;
|
||||||
mod transmute_int_to_bool;
|
mod transmute_int_to_bool;
|
||||||
mod transmute_int_to_char;
|
mod transmute_int_to_char;
|
||||||
|
@ -463,6 +464,62 @@ declare_clippy_lint! {
|
||||||
"transmute results in a null function pointer, which is undefined behavior"
|
"transmute results in a null function pointer, which is undefined behavior"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for integer validity checks, followed by a transmute that is (incorrectly) evaluated
|
||||||
|
/// eagerly (e.g. using `bool::then_some`).
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Eager evaluation means that the `transmute` call is executed regardless of whether the condition is true or false.
|
||||||
|
/// This can introduce unsoundness and other subtle bugs.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// Consider the following function which is meant to convert an unsigned integer to its enum equivalent via transmute.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// #[repr(u8)]
|
||||||
|
/// enum Opcode {
|
||||||
|
/// Add = 0,
|
||||||
|
/// Sub = 1,
|
||||||
|
/// Mul = 2,
|
||||||
|
/// Div = 3
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn int_to_opcode(op: u8) -> Option<Opcode> {
|
||||||
|
/// (op < 4).then_some(unsafe { std::mem::transmute(op) })
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// This may appear fine at first given that it checks that the `u8` is within the validity range of the enum,
|
||||||
|
/// *however* the transmute is evaluated eagerly, meaning that it executes even if `op >= 4`!
|
||||||
|
///
|
||||||
|
/// This makes the function unsound, because it is possible for the caller to cause undefined behavior
|
||||||
|
/// (creating an enum with an invalid bitpattern) entirely in safe code only by passing an incorrect value,
|
||||||
|
/// which is normally only a bug that is possible in unsafe code.
|
||||||
|
///
|
||||||
|
/// One possible way in which this can go wrong practically is that the compiler sees it as:
|
||||||
|
/// ```rust,ignore (illustrative)
|
||||||
|
/// let temp: Foo = unsafe { std::mem::transmute(op) };
|
||||||
|
/// (0 < 4).then_some(temp)
|
||||||
|
/// ```
|
||||||
|
/// and optimizes away the `(0 < 4)` check based on the assumption that since a `Foo` was created from `op` with the validity range `0..3`,
|
||||||
|
/// it is **impossible** for this condition to be false.
|
||||||
|
///
|
||||||
|
/// In short, it is possible for this function to be optimized in a way that makes it [never return `None`](https://godbolt.org/z/ocrcenevq),
|
||||||
|
/// even if passed the value `4`.
|
||||||
|
///
|
||||||
|
/// This can be avoided by instead using lazy evaluation. For the example above, this should be written:
|
||||||
|
/// ```rust,ignore (illustrative)
|
||||||
|
/// fn int_to_opcode(op: u8) -> Option<Opcode> {
|
||||||
|
/// (op < 4).then(|| unsafe { std::mem::transmute(op) })
|
||||||
|
/// ^^^^ ^^ `bool::then` only executes the closure if the condition is true!
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.76.0"]
|
||||||
|
pub EAGER_TRANSMUTE,
|
||||||
|
correctness,
|
||||||
|
"eager evaluation of `transmute`"
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Transmute {
|
pub struct Transmute {
|
||||||
msrv: Msrv,
|
msrv: Msrv,
|
||||||
}
|
}
|
||||||
|
@ -484,6 +541,7 @@ impl_lint_pass!(Transmute => [
|
||||||
TRANSMUTE_UNDEFINED_REPR,
|
TRANSMUTE_UNDEFINED_REPR,
|
||||||
TRANSMUTING_NULL,
|
TRANSMUTING_NULL,
|
||||||
TRANSMUTE_NULL_TO_FN,
|
TRANSMUTE_NULL_TO_FN,
|
||||||
|
EAGER_TRANSMUTE,
|
||||||
]);
|
]);
|
||||||
impl Transmute {
|
impl Transmute {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -530,7 +588,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
|
||||||
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
|
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||||
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
|
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||||
| (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
|
| (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
|
||||||
|| transmute_undefined_repr::check(cx, e, from_ty, to_ty));
|
|| transmute_undefined_repr::check(cx, e, from_ty, to_ty))
|
||||||
|
| (eager_transmute::check(cx, e, arg, from_ty, to_ty));
|
||||||
|
|
||||||
if !linted {
|
if !linted {
|
||||||
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
|
transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
|
||||||
|
|
134
clippy_lints/src/unconditional_recursion.rs
Normal file
134
clippy_lints/src/unconditional_recursion.rs
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use clippy_utils::{get_trait_def_id, path_res};
|
||||||
|
use rustc_ast::BinOpKind;
|
||||||
|
use rustc_hir::def::Res;
|
||||||
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
use rustc_hir::intravisit::FnKind;
|
||||||
|
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Item, ItemKind, Node};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
use rustc_session::declare_lint_pass;
|
||||||
|
use rustc_span::{sym, Span};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks that there isn't an infinite recursion in `PartialEq` trait
|
||||||
|
/// implementation.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// This is a hard to find infinite recursion which will crashing any code
|
||||||
|
/// using it.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```no_run
|
||||||
|
/// enum Foo {
|
||||||
|
/// A,
|
||||||
|
/// B,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl PartialEq for Foo {
|
||||||
|
/// fn eq(&self, other: &Self) -> bool {
|
||||||
|
/// self == other // bad!
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
///
|
||||||
|
/// In such cases, either use `#[derive(PartialEq)]` or don't implement it.
|
||||||
|
#[clippy::version = "1.76.0"]
|
||||||
|
pub UNCONDITIONAL_RECURSION,
|
||||||
|
suspicious,
|
||||||
|
"detect unconditional recursion in some traits implementation"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(UnconditionalRecursion => [UNCONDITIONAL_RECURSION]);
|
||||||
|
|
||||||
|
fn get_ty_def_id(ty: Ty<'_>) -> Option<DefId> {
|
||||||
|
match ty.peel_refs().kind() {
|
||||||
|
ty::Adt(adt, _) => Some(adt.did()),
|
||||||
|
ty::Foreign(def_id) => Some(*def_id),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_local(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
|
matches!(path_res(cx, expr), Res::Local(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
|
||||||
|
#[allow(clippy::unnecessary_def_path)]
|
||||||
|
fn check_fn(
|
||||||
|
&mut self,
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
kind: FnKind<'tcx>,
|
||||||
|
_decl: &'tcx FnDecl<'tcx>,
|
||||||
|
body: &'tcx Body<'tcx>,
|
||||||
|
method_span: Span,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
) {
|
||||||
|
// If the function is a method...
|
||||||
|
if let FnKind::Method(name, _) = kind
|
||||||
|
// That has two arguments.
|
||||||
|
&& let [self_arg, other_arg] = cx
|
||||||
|
.tcx
|
||||||
|
.instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder())
|
||||||
|
.inputs()
|
||||||
|
&& let Some(self_arg) = get_ty_def_id(*self_arg)
|
||||||
|
&& let Some(other_arg) = get_ty_def_id(*other_arg)
|
||||||
|
// The two arguments are of the same type.
|
||||||
|
&& self_arg == other_arg
|
||||||
|
&& let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
|
||||||
|
&& let Some((
|
||||||
|
_,
|
||||||
|
Node::Item(Item {
|
||||||
|
kind: ItemKind::Impl(impl_),
|
||||||
|
owner_id,
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
)) = cx.tcx.hir().parent_iter(hir_id).next()
|
||||||
|
// We exclude `impl` blocks generated from rustc's proc macros.
|
||||||
|
&& !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
|
||||||
|
// It is a implementation of a trait.
|
||||||
|
&& let Some(trait_) = impl_.of_trait
|
||||||
|
&& let Some(trait_def_id) = trait_.trait_def_id()
|
||||||
|
// The trait is `PartialEq`.
|
||||||
|
&& Some(trait_def_id) == get_trait_def_id(cx, &["core", "cmp", "PartialEq"])
|
||||||
|
{
|
||||||
|
let to_check_op = if name.name == sym::eq {
|
||||||
|
BinOpKind::Eq
|
||||||
|
} else {
|
||||||
|
BinOpKind::Ne
|
||||||
|
};
|
||||||
|
let expr = body.value.peel_blocks();
|
||||||
|
let is_bad = match expr.kind {
|
||||||
|
ExprKind::Binary(op, left, right) if op.node == to_check_op => {
|
||||||
|
is_local(cx, left) && is_local(cx, right)
|
||||||
|
},
|
||||||
|
ExprKind::MethodCall(segment, receiver, &[arg], _) if segment.ident.name == name.name => {
|
||||||
|
if is_local(cx, receiver)
|
||||||
|
&& is_local(cx, &arg)
|
||||||
|
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||||
|
&& let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
|
||||||
|
&& trait_id == trait_def_id
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if is_bad {
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
UNCONDITIONAL_RECURSION,
|
||||||
|
method_span,
|
||||||
|
"function cannot return without recursing",
|
||||||
|
|diag| {
|
||||||
|
diag.span_note(expr.span, "recursive call site");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -680,9 +680,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos
|
||||||
})
|
})
|
||||||
.filter(|(_, text)| !text.is_empty());
|
.filter(|(_, text)| !text.is_empty());
|
||||||
|
|
||||||
let Some((line_start, line)) = lines.next() else {
|
let (line_start, line) = lines.next()?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
// Check for a sequence of line comments.
|
// Check for a sequence of line comments.
|
||||||
if line.starts_with("//") {
|
if line.starts_with("//") {
|
||||||
let (mut line, mut line_start) = (line, line_start);
|
let (mut line, mut line_start) = (line, line_start);
|
||||||
|
|
|
@ -32,7 +32,7 @@ declare_clippy_lint! {
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "1.76.0"]
|
#[clippy::version = "1.76.0"]
|
||||||
pub UNINHABITED_REFERENCES,
|
pub UNINHABITED_REFERENCES,
|
||||||
suspicious,
|
nursery,
|
||||||
"reference to uninhabited type"
|
"reference to uninhabited type"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -351,6 +351,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||||
let_pat,
|
let_pat,
|
||||||
let_expr,
|
let_expr,
|
||||||
if_then,
|
if_then,
|
||||||
|
..
|
||||||
}) = higher::WhileLet::hir(expr.value)
|
}) = higher::WhileLet::hir(expr.value)
|
||||||
{
|
{
|
||||||
bind!(self, let_pat, let_expr, if_then);
|
bind!(self, let_pat, let_expr, if_then);
|
||||||
|
|
|
@ -134,6 +134,7 @@ pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)] // Just a big match statement
|
||||||
pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||||
use ExprKind::*;
|
use ExprKind::*;
|
||||||
if !over(&l.attrs, &r.attrs, eq_attr) {
|
if !over(&l.attrs, &r.attrs, eq_attr) {
|
||||||
|
|
|
@ -76,12 +76,14 @@ pub fn get_attr<'a>(
|
||||||
})
|
})
|
||||||
.map_or_else(
|
.map_or_else(
|
||||||
|| {
|
|| {
|
||||||
sess.dcx().span_err(attr_segments[1].ident.span, "usage of unknown attribute");
|
sess.dcx()
|
||||||
|
.span_err(attr_segments[1].ident.span, "usage of unknown attribute");
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
|deprecation_status| {
|
|deprecation_status| {
|
||||||
let mut diag =
|
let mut diag = sess
|
||||||
sess.dcx().struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
|
.dcx()
|
||||||
|
.struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
|
||||||
match *deprecation_status {
|
match *deprecation_status {
|
||||||
DeprecationStatus::Deprecated => {
|
DeprecationStatus::Deprecated => {
|
||||||
diag.emit();
|
diag.emit();
|
||||||
|
@ -132,7 +134,8 @@ pub fn get_unique_attr<'a>(
|
||||||
let mut unique_attr: Option<&ast::Attribute> = None;
|
let mut unique_attr: Option<&ast::Attribute> = None;
|
||||||
for attr in get_attr(sess, attrs, name) {
|
for attr in get_attr(sess, attrs, name) {
|
||||||
if let Some(duplicate) = unique_attr {
|
if let Some(duplicate) = unique_attr {
|
||||||
sess.dcx().struct_span_err(attr.span, format!("`{name}` is defined multiple times"))
|
sess.dcx()
|
||||||
|
.struct_span_err(attr.span, format!("`{name}` is defined multiple times"))
|
||||||
.span_note(duplicate.span, "first definition found here")
|
.span_note(duplicate.span, "first definition found here")
|
||||||
.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -84,9 +84,9 @@ pub fn span_lint_and_help<T: LintContext>(
|
||||||
cx.struct_span_lint(lint, span, msg.to_string(), |diag| {
|
cx.struct_span_lint(lint, span, msg.to_string(), |diag| {
|
||||||
let help = help.to_string();
|
let help = help.to_string();
|
||||||
if let Some(help_span) = help_span {
|
if let Some(help_span) = help_span {
|
||||||
diag.span_help(help_span, help.to_string());
|
diag.span_help(help_span, help);
|
||||||
} else {
|
} else {
|
||||||
diag.help(help.to_string());
|
diag.help(help);
|
||||||
}
|
}
|
||||||
docs_link(diag, lint);
|
docs_link(diag, lint);
|
||||||
});
|
});
|
||||||
|
|
|
@ -91,6 +91,9 @@ pub struct IfLet<'hir> {
|
||||||
pub if_then: &'hir Expr<'hir>,
|
pub if_then: &'hir Expr<'hir>,
|
||||||
/// `if let` else expression
|
/// `if let` else expression
|
||||||
pub if_else: Option<&'hir Expr<'hir>>,
|
pub if_else: Option<&'hir Expr<'hir>>,
|
||||||
|
/// `if let PAT = EXPR`
|
||||||
|
/// ^^^^^^^^^^^^^^
|
||||||
|
pub let_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'hir> IfLet<'hir> {
|
impl<'hir> IfLet<'hir> {
|
||||||
|
@ -99,9 +102,10 @@ impl<'hir> IfLet<'hir> {
|
||||||
if let ExprKind::If(
|
if let ExprKind::If(
|
||||||
Expr {
|
Expr {
|
||||||
kind:
|
kind:
|
||||||
ExprKind::Let(hir::Let {
|
ExprKind::Let(&hir::Let {
|
||||||
pat: let_pat,
|
pat: let_pat,
|
||||||
init: let_expr,
|
init: let_expr,
|
||||||
|
span: let_span,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
|
@ -129,6 +133,7 @@ impl<'hir> IfLet<'hir> {
|
||||||
let_expr,
|
let_expr,
|
||||||
if_then,
|
if_then,
|
||||||
if_else,
|
if_else,
|
||||||
|
let_span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -146,6 +151,9 @@ pub enum IfLetOrMatch<'hir> {
|
||||||
&'hir Pat<'hir>,
|
&'hir Pat<'hir>,
|
||||||
&'hir Expr<'hir>,
|
&'hir Expr<'hir>,
|
||||||
Option<&'hir Expr<'hir>>,
|
Option<&'hir Expr<'hir>>,
|
||||||
|
/// `if let PAT = EXPR`
|
||||||
|
/// ^^^^^^^^^^^^^^
|
||||||
|
Span,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +168,8 @@ impl<'hir> IfLetOrMatch<'hir> {
|
||||||
let_pat,
|
let_pat,
|
||||||
if_then,
|
if_then,
|
||||||
if_else,
|
if_else,
|
||||||
}| { Self::IfLet(let_expr, let_pat, if_then, if_else) },
|
let_span,
|
||||||
|
}| { Self::IfLet(let_expr, let_pat, if_then, if_else, let_span) },
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,6 +362,9 @@ pub struct WhileLet<'hir> {
|
||||||
pub let_expr: &'hir Expr<'hir>,
|
pub let_expr: &'hir Expr<'hir>,
|
||||||
/// `while let` loop body
|
/// `while let` loop body
|
||||||
pub if_then: &'hir Expr<'hir>,
|
pub if_then: &'hir Expr<'hir>,
|
||||||
|
/// `while let PAT = EXPR`
|
||||||
|
/// ^^^^^^^^^^^^^^
|
||||||
|
pub let_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'hir> WhileLet<'hir> {
|
impl<'hir> WhileLet<'hir> {
|
||||||
|
@ -367,9 +379,10 @@ impl<'hir> WhileLet<'hir> {
|
||||||
ExprKind::If(
|
ExprKind::If(
|
||||||
Expr {
|
Expr {
|
||||||
kind:
|
kind:
|
||||||
ExprKind::Let(hir::Let {
|
ExprKind::Let(&hir::Let {
|
||||||
pat: let_pat,
|
pat: let_pat,
|
||||||
init: let_expr,
|
init: let_expr,
|
||||||
|
span: let_span,
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
|
@ -390,6 +403,7 @@ impl<'hir> WhileLet<'hir> {
|
||||||
let_pat,
|
let_pat,
|
||||||
let_expr,
|
let_expr,
|
||||||
if_then,
|
if_then,
|
||||||
|
let_span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
|
||||||
use rustc_lint::{LateContext, LintContext};
|
use rustc_lint::{LateContext, LintContext};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::{original_sp, SourceMap};
|
use rustc_span::source_map::{original_sp, SourceMap};
|
||||||
use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
|
use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
|
|
@ -316,10 +316,7 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
|
||||||
is_const: bool,
|
is_const: bool,
|
||||||
}
|
}
|
||||||
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
||||||
type NestedFilter = nested_filter::OnlyBodies;
|
type NestedFilter = rustc_hir::intravisit::nested_filter::None;
|
||||||
fn nested_visit_map(&mut self) -> Self::Map {
|
|
||||||
self.cx.tcx.hir()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||||
if !self.is_const {
|
if !self.is_const {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_lint::{Lint, LintContext};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
|
||||||
pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||||
cx.struct_span_lint(lint, span, msg, |b| b);
|
cx.struct_span_lint(lint, span, msg, |_| {});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn b(
|
pub fn b(
|
||||||
|
@ -21,7 +21,7 @@ pub fn b(
|
||||||
span: impl Into<MultiSpan>,
|
span: impl Into<MultiSpan>,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
) {
|
) {
|
||||||
tcx.struct_span_lint_hir(lint, hir_id, span, msg, |b| b);
|
tcx.struct_span_lint_hir(lint, hir_id, span, msg, |_| {});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: use of a disallowed method `rustc_lint::context::LintContext::struct_span_lint`
|
error: use of a disallowed method `rustc_lint::context::LintContext::struct_span_lint`
|
||||||
--> $DIR/disallow_struct_span_lint.rs:14:5
|
--> $DIR/disallow_struct_span_lint.rs:14:5
|
||||||
|
|
|
|
||||||
LL | cx.struct_span_lint(lint, span, msg, |b| b);
|
LL | cx.struct_span_lint(lint, span, msg, |_| {});
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::disallowed-methods` implied by `-D warnings`
|
= note: `-D clippy::disallowed-methods` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
|
= help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
|
||||||
|
@ -10,8 +10,8 @@ LL | cx.struct_span_lint(lint, span, msg, |b| b);
|
||||||
error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::struct_span_lint_hir`
|
error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::struct_span_lint_hir`
|
||||||
--> $DIR/disallow_struct_span_lint.rs:24:5
|
--> $DIR/disallow_struct_span_lint.rs:24:5
|
||||||
|
|
|
|
||||||
LL | tcx.struct_span_lint_hir(lint, hir_id, span, msg, |b| b);
|
LL | tcx.struct_span_lint_hir(lint, hir_id, span, msg, |_| {});
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
|
||||||
error: hardcoded path to a diagnostic item
|
error: hardcoded path to a diagnostic item
|
||||||
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
||||||
|
|
|
|
||||||
LL | const OPS_MOD: [&str; 5] = ["core", "ops"];
|
LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: convert all references to use `sym::deref_method`
|
= help: convert all references to use `sym::deref_method`
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
unconditional_panic,
|
unconditional_panic,
|
||||||
clippy::no_effect,
|
clippy::no_effect,
|
||||||
clippy::unnecessary_operation,
|
clippy::unnecessary_operation,
|
||||||
clippy::useless_vec
|
clippy::useless_vec,
|
||||||
|
clippy::out_of_bounds_indexing
|
||||||
)]
|
)]
|
||||||
|
|
||||||
const ARR: [i32; 2] = [1, 2];
|
const ARR: [i32; 2] = [1, 2];
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
error[E0080]: evaluation of `main::{constant#3}` failed
|
error[E0080]: evaluation of `main::{constant#3}` failed
|
||||||
--> $DIR/test.rs:37:14
|
--> $DIR/test.rs:38:14
|
||||||
|
|
|
|
||||||
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
||||||
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
||||||
|
|
||||||
note: erroneous constant encountered
|
note: erroneous constant encountered
|
||||||
--> $DIR/test.rs:37:5
|
--> $DIR/test.rs:38:5
|
||||||
|
|
|
|
||||||
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/test.rs:28:5
|
--> $DIR/test.rs:29:5
|
||||||
|
|
|
|
||||||
LL | x[index];
|
LL | x[index];
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -21,7 +21,7 @@ LL | x[index];
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
|
= help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/test.rs:46:5
|
--> $DIR/test.rs:47:5
|
||||||
|
|
|
|
||||||
LL | v[0];
|
LL | v[0];
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -29,7 +29,7 @@ LL | v[0];
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/test.rs:47:5
|
--> $DIR/test.rs:48:5
|
||||||
|
|
|
|
||||||
LL | v[10];
|
LL | v[10];
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
@ -37,7 +37,7 @@ LL | v[10];
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/test.rs:48:5
|
--> $DIR/test.rs:49:5
|
||||||
|
|
|
|
||||||
LL | v[1 << 3];
|
LL | v[1 << 3];
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -45,7 +45,7 @@ LL | v[1 << 3];
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/test.rs:54:5
|
--> $DIR/test.rs:55:5
|
||||||
|
|
|
|
||||||
LL | v[N];
|
LL | v[N];
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -53,7 +53,7 @@ LL | v[N];
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/test.rs:55:5
|
--> $DIR/test.rs:56:5
|
||||||
|
|
|
|
||||||
LL | v[M];
|
LL | v[M];
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
@ -61,7 +61,7 @@ LL | v[M];
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> $DIR/test.rs:15:24
|
--> $DIR/test.rs:16:24
|
||||||
|
|
|
|
||||||
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
||||||
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
||||||
|
|
|
@ -45,4 +45,11 @@ fn main() {
|
||||||
|
|
||||||
const CFG_FLAG: &bool = &cfg!(feature = "hey");
|
const CFG_FLAG: &bool = &cfg!(feature = "hey");
|
||||||
assert!(!CFG_FLAG);
|
assert!(!CFG_FLAG);
|
||||||
|
|
||||||
|
const _: () = assert!(true);
|
||||||
|
//~^ ERROR: `assert!(true)` will be optimized out by the compiler
|
||||||
|
|
||||||
|
// Don't lint if the value is dependent on a defined constant:
|
||||||
|
const N: usize = 1024;
|
||||||
|
const _: () = assert!(N.is_power_of_two());
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,5 +72,13 @@ LL | debug_assert!(true);
|
||||||
|
|
|
|
||||||
= help: remove it
|
= help: remove it
|
||||||
|
|
||||||
error: aborting due to 9 previous errors
|
error: `assert!(true)` will be optimized out by the compiler
|
||||||
|
--> $DIR/assertions_on_constants.rs:49:19
|
||||||
|
|
|
||||||
|
LL | const _: () = assert!(true);
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: remove it
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![allow(clippy::never_loop, clippy::while_immutable_condition)]
|
#![allow(
|
||||||
|
clippy::never_loop,
|
||||||
|
clippy::while_immutable_condition,
|
||||||
|
clippy::redundant_pattern_matching
|
||||||
|
)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[clippy::author]
|
#[clippy::author]
|
||||||
|
|
|
@ -165,3 +165,12 @@ fn issue3973() {
|
||||||
if is_debug == m!(func) {}
|
if is_debug == m!(func) {}
|
||||||
if m!(func) == is_debug {}
|
if m!(func) == is_debug {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_cast)]
|
||||||
|
fn issue9907() {
|
||||||
|
let _ = (1 >= 2) as usize;
|
||||||
|
let _ = (!m!(func)) as usize;
|
||||||
|
// This is not part of the issue, but an unexpected found when fixing the issue,
|
||||||
|
// the provided span was inside of macro rather than the macro callsite.
|
||||||
|
let _ = ((1 < 2) != m!(func)) as usize;
|
||||||
|
}
|
||||||
|
|
|
@ -165,3 +165,12 @@ fn issue3973() {
|
||||||
if is_debug == m!(func) {}
|
if is_debug == m!(func) {}
|
||||||
if m!(func) == is_debug {}
|
if m!(func) == is_debug {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_cast)]
|
||||||
|
fn issue9907() {
|
||||||
|
let _ = ((1 < 2) == false) as usize;
|
||||||
|
let _ = (false == m!(func)) as usize;
|
||||||
|
// This is not part of the issue, but an unexpected found when fixing the issue,
|
||||||
|
// the provided span was inside of macro rather than the macro callsite.
|
||||||
|
let _ = ((1 < 2) == !m!(func)) as usize;
|
||||||
|
}
|
||||||
|
|
|
@ -133,5 +133,23 @@ error: equality checks against true are unnecessary
|
||||||
LL | if m!(func) == true {}
|
LL | if m!(func) == true {}
|
||||||
| ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
|
| ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
|
||||||
|
|
||||||
error: aborting due to 22 previous errors
|
error: equality checks against false can be replaced by a negation
|
||||||
|
--> $DIR/bool_comparison.rs:171:14
|
||||||
|
|
|
||||||
|
LL | let _ = ((1 < 2) == false) as usize;
|
||||||
|
| ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `1 >= 2`
|
||||||
|
|
||||||
|
error: equality checks against false can be replaced by a negation
|
||||||
|
--> $DIR/bool_comparison.rs:172:14
|
||||||
|
|
|
||||||
|
LL | let _ = (false == m!(func)) as usize;
|
||||||
|
| ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
|
||||||
|
|
||||||
|
error: this comparison might be written more concisely
|
||||||
|
--> $DIR/bool_comparison.rs:175:14
|
||||||
|
|
|
||||||
|
LL | let _ = ((1 < 2) == !m!(func)) as usize;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `(1 < 2) != m!(func)`
|
||||||
|
|
||||||
|
error: aborting due to 25 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
|
#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
|
||||||
#![allow(dead_code)]
|
#![allow(
|
||||||
#![allow(clippy::equatable_if_let, clippy::uninlined_format_args)]
|
clippy::equatable_if_let,
|
||||||
|
clippy::uninlined_format_args,
|
||||||
|
clippy::redundant_pattern_matching,
|
||||||
|
dead_code
|
||||||
|
)]
|
||||||
//@no-rustfix
|
//@no-rustfix
|
||||||
// This tests the branches_sharing_code lint at the end of blocks
|
// This tests the branches_sharing_code lint at the end of blocks
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:31:5
|
--> $DIR/shared_at_bottom.rs:35:5
|
||||||
|
|
|
|
||||||
LL | / let result = false;
|
LL | / let result = false;
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -26,7 +26,7 @@ LL ~ result;
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:51:5
|
--> $DIR/shared_at_bottom.rs:55:5
|
||||||
|
|
|
|
||||||
LL | / println!("Same end of block");
|
LL | / println!("Same end of block");
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -40,7 +40,7 @@ LL + println!("Same end of block");
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:69:5
|
--> $DIR/shared_at_bottom.rs:73:5
|
||||||
|
|
|
|
||||||
LL | / println!(
|
LL | / println!(
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -61,7 +61,7 @@ LL + );
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:82:9
|
--> $DIR/shared_at_bottom.rs:86:9
|
||||||
|
|
|
|
||||||
LL | / println!("Hello World");
|
LL | / println!("Hello World");
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -75,7 +75,7 @@ LL + println!("Hello World");
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:99:5
|
--> $DIR/shared_at_bottom.rs:103:5
|
||||||
|
|
|
|
||||||
LL | / let later_used_value = "A string value";
|
LL | / let later_used_value = "A string value";
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -94,7 +94,7 @@ LL + println!("{}", later_used_value);
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:113:5
|
--> $DIR/shared_at_bottom.rs:117:5
|
||||||
|
|
|
|
||||||
LL | / let simple_examples = "I now identify as a &str :)";
|
LL | / let simple_examples = "I now identify as a &str :)";
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -112,7 +112,7 @@ LL + println!("This is the new simple_example: {}", simple_examples);
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:179:5
|
--> $DIR/shared_at_bottom.rs:183:5
|
||||||
|
|
|
|
||||||
LL | / x << 2
|
LL | / x << 2
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -128,7 +128,7 @@ LL ~ x << 2;
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:188:5
|
--> $DIR/shared_at_bottom.rs:192:5
|
||||||
|
|
|
|
||||||
LL | / x * 4
|
LL | / x * 4
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -144,7 +144,7 @@ LL + x * 4
|
||||||
|
|
|
|
||||||
|
|
||||||
error: all if blocks contain the same code at the end
|
error: all if blocks contain the same code at the end
|
||||||
--> $DIR/shared_at_bottom.rs:202:44
|
--> $DIR/shared_at_bottom.rs:206:44
|
||||||
|
|
|
|
||||||
LL | if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
|
LL | if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
clippy::equatable_if_let,
|
clippy::equatable_if_let,
|
||||||
clippy::needless_if,
|
clippy::needless_if,
|
||||||
clippy::nonminimal_bool,
|
clippy::nonminimal_bool,
|
||||||
clippy::eq_op
|
clippy::eq_op,
|
||||||
|
clippy::redundant_pattern_matching
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
clippy::equatable_if_let,
|
clippy::equatable_if_let,
|
||||||
clippy::needless_if,
|
clippy::needless_if,
|
||||||
clippy::nonminimal_bool,
|
clippy::nonminimal_bool,
|
||||||
clippy::eq_op
|
clippy::eq_op,
|
||||||
|
clippy::redundant_pattern_matching
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:14:5
|
--> $DIR/collapsible_if.rs:15:5
|
||||||
|
|
|
|
||||||
LL | / if x == "hello" {
|
LL | / if x == "hello" {
|
||||||
LL | | if y == "world" {
|
LL | | if y == "world" {
|
||||||
|
@ -18,7 +18,7 @@ LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:20:5
|
--> $DIR/collapsible_if.rs:21:5
|
||||||
|
|
|
|
||||||
LL | / if x == "hello" || x == "world" {
|
LL | / if x == "hello" || x == "world" {
|
||||||
LL | | if y == "world" || y == "hello" {
|
LL | | if y == "world" || y == "hello" {
|
||||||
|
@ -35,7 +35,7 @@ LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:26:5
|
--> $DIR/collapsible_if.rs:27:5
|
||||||
|
|
|
|
||||||
LL | / if x == "hello" && x == "world" {
|
LL | / if x == "hello" && x == "world" {
|
||||||
LL | | if y == "world" || y == "hello" {
|
LL | | if y == "world" || y == "hello" {
|
||||||
|
@ -52,7 +52,7 @@ LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:32:5
|
--> $DIR/collapsible_if.rs:33:5
|
||||||
|
|
|
|
||||||
LL | / if x == "hello" || x == "world" {
|
LL | / if x == "hello" || x == "world" {
|
||||||
LL | | if y == "world" && y == "hello" {
|
LL | | if y == "world" && y == "hello" {
|
||||||
|
@ -69,7 +69,7 @@ LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:38:5
|
--> $DIR/collapsible_if.rs:39:5
|
||||||
|
|
|
|
||||||
LL | / if x == "hello" && x == "world" {
|
LL | / if x == "hello" && x == "world" {
|
||||||
LL | | if y == "world" && y == "hello" {
|
LL | | if y == "world" && y == "hello" {
|
||||||
|
@ -86,7 +86,7 @@ LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:44:5
|
--> $DIR/collapsible_if.rs:45:5
|
||||||
|
|
|
|
||||||
LL | / if 42 == 1337 {
|
LL | / if 42 == 1337 {
|
||||||
LL | | if 'a' != 'A' {
|
LL | | if 'a' != 'A' {
|
||||||
|
@ -103,7 +103,7 @@ LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:100:5
|
--> $DIR/collapsible_if.rs:101:5
|
||||||
|
|
|
|
||||||
LL | / if x == "hello" {
|
LL | / if x == "hello" {
|
||||||
LL | | if y == "world" { // Collapsible
|
LL | | if y == "world" { // Collapsible
|
||||||
|
@ -120,7 +120,7 @@ LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:159:5
|
--> $DIR/collapsible_if.rs:160:5
|
||||||
|
|
|
|
||||||
LL | / if matches!(true, true) {
|
LL | / if matches!(true, true) {
|
||||||
LL | | if matches!(true, true) {}
|
LL | | if matches!(true, true) {}
|
||||||
|
@ -128,7 +128,7 @@ LL | | }
|
||||||
| |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
|
| |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
|
||||||
|
|
||||||
error: this `if` statement can be collapsed
|
error: this `if` statement can be collapsed
|
||||||
--> $DIR/collapsible_if.rs:164:5
|
--> $DIR/collapsible_if.rs:165:5
|
||||||
|
|
|
|
||||||
LL | / if matches!(true, true) && truth() {
|
LL | / if matches!(true, true) && truth() {
|
||||||
LL | | if matches!(true, true) {}
|
LL | | if matches!(true, true) {}
|
||||||
|
|
14
tests/ui/crashes/ice-11939.rs
Normal file
14
tests/ui/crashes/ice-11939.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#![allow(clippy::unit_arg, clippy::no_effect)]
|
||||||
|
|
||||||
|
const fn v(_: ()) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if true {
|
||||||
|
v({
|
||||||
|
[0; 1 + 1];
|
||||||
|
});
|
||||||
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
// reduced from rustc issue-69020-assoc-const-arith-overflow.rs
|
// reduced from rustc issue-69020-assoc-const-arith-overflow.rs
|
||||||
|
#![allow(clippy::out_of_bounds_indexing)]
|
||||||
|
|
||||||
pub fn main() {}
|
pub fn main() {}
|
||||||
|
|
||||||
pub trait Foo {
|
pub trait Foo {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: this operation will panic at runtime
|
error: this operation will panic at runtime
|
||||||
--> $DIR/ice-5497.rs:9:22
|
--> $DIR/ice-5497.rs:11:22
|
||||||
|
|
|
|
||||||
LL | const OOB: i32 = [1][1] + T::OOB;
|
LL | const OOB: i32 = [1][1] + T::OOB;
|
||||||
| ^^^^^^ index out of bounds: the length is 1 but the index is 1
|
| ^^^^^^ index out of bounds: the length is 1 but the index is 1
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
|
#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
|
||||||
#![warn(clippy::expl_impl_clone_on_copy)]
|
#![warn(clippy::expl_impl_clone_on_copy)]
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
struct Qux;
|
struct Qux;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:8:1
|
--> $DIR/derive.rs:7:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for Qux {
|
LL | / impl Clone for Qux {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -10,7 +10,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:8:1
|
--> $DIR/derive.rs:7:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for Qux {
|
LL | / impl Clone for Qux {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -23,7 +23,7 @@ LL | | }
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
|
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:33:1
|
--> $DIR/derive.rs:32:1
|
||||||
|
|
|
|
||||||
LL | / impl<'a> Clone for Lt<'a> {
|
LL | / impl<'a> Clone for Lt<'a> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -34,7 +34,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:33:1
|
--> $DIR/derive.rs:32:1
|
||||||
|
|
|
|
||||||
LL | / impl<'a> Clone for Lt<'a> {
|
LL | / impl<'a> Clone for Lt<'a> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -45,7 +45,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:45:1
|
--> $DIR/derive.rs:44:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for BigArray {
|
LL | / impl Clone for BigArray {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -56,7 +56,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:45:1
|
--> $DIR/derive.rs:44:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for BigArray {
|
LL | / impl Clone for BigArray {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -67,7 +67,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:57:1
|
--> $DIR/derive.rs:56:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for FnPtr {
|
LL | / impl Clone for FnPtr {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -78,7 +78,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:57:1
|
--> $DIR/derive.rs:56:1
|
||||||
|
|
|
|
||||||
LL | / impl Clone for FnPtr {
|
LL | / impl Clone for FnPtr {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -89,7 +89,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: you are implementing `Clone` explicitly on a `Copy` type
|
error: you are implementing `Clone` explicitly on a `Copy` type
|
||||||
--> $DIR/derive.rs:78:1
|
--> $DIR/derive.rs:77:1
|
||||||
|
|
|
|
||||||
LL | / impl<T: Clone> Clone for Generic2<T> {
|
LL | / impl<T: Clone> Clone for Generic2<T> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -100,7 +100,7 @@ LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
note: consider deriving `Clone` or removing `Copy`
|
note: consider deriving `Clone` or removing `Copy`
|
||||||
--> $DIR/derive.rs:78:1
|
--> $DIR/derive.rs:77:1
|
||||||
|
|
|
|
||||||
LL | / impl<T: Clone> Clone for Generic2<T> {
|
LL | / impl<T: Clone> Clone for Generic2<T> {
|
||||||
LL | |
|
LL | |
|
||||||
|
|
|
@ -65,7 +65,7 @@ fn test_units() {
|
||||||
/// OAuth GraphQL
|
/// OAuth GraphQL
|
||||||
/// OCaml
|
/// OCaml
|
||||||
/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
|
/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
|
||||||
/// WebGL
|
/// WebGL WebGL2 WebGPU
|
||||||
/// TensorFlow
|
/// TensorFlow
|
||||||
/// TrueType
|
/// TrueType
|
||||||
/// iOS macOS FreeBSD
|
/// iOS macOS FreeBSD
|
||||||
|
|
|
@ -65,7 +65,7 @@ fn test_units() {
|
||||||
/// OAuth GraphQL
|
/// OAuth GraphQL
|
||||||
/// OCaml
|
/// OCaml
|
||||||
/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
|
/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
|
||||||
/// WebGL
|
/// WebGL WebGL2 WebGPU
|
||||||
/// TensorFlow
|
/// TensorFlow
|
||||||
/// TrueType
|
/// TrueType
|
||||||
/// iOS macOS FreeBSD
|
/// iOS macOS FreeBSD
|
||||||
|
|
72
tests/ui/eager_transmute.fixed
Normal file
72
tests/ui/eager_transmute.fixed
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![warn(clippy::eager_transmute)]
|
||||||
|
#![allow(clippy::transmute_int_to_non_zero)]
|
||||||
|
|
||||||
|
use std::num::NonZeroU8;
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Opcode {
|
||||||
|
Add = 0,
|
||||||
|
Sub = 1,
|
||||||
|
Mul = 2,
|
||||||
|
Div = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_to_opcode(op: u8) -> Option<Opcode> {
|
||||||
|
(op < 4).then(|| unsafe { std::mem::transmute(op) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(op: u8, unrelated: u8) {
|
||||||
|
true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn f2(op: u8) {
|
||||||
|
(op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_layout_scalar_valid_range_end(254)]
|
||||||
|
struct NonMaxU8(u8);
|
||||||
|
#[rustc_layout_scalar_valid_range_end(254)]
|
||||||
|
#[rustc_layout_scalar_valid_range_start(1)]
|
||||||
|
struct NonZeroNonMaxU8(u8);
|
||||||
|
|
||||||
|
macro_rules! impls {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
impl PartialEq<u8> for $t {
|
||||||
|
fn eq(&self, other: &u8) -> bool {
|
||||||
|
self.0 == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialOrd<u8> for $t {
|
||||||
|
fn partial_cmp(&self, other: &u8) -> Option<std::cmp::Ordering> {
|
||||||
|
self.0.partial_cmp(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
impls!(NonMaxU8, NonZeroNonMaxU8);
|
||||||
|
|
||||||
|
fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) {
|
||||||
|
// u8 -> NonZeroU8, do lint
|
||||||
|
let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
|
||||||
|
|
||||||
|
// NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range
|
||||||
|
let _: Option<u8> = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
|
||||||
|
// NonZeroU8 -> NonMaxU8, do lint, different niche
|
||||||
|
let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
|
||||||
|
|
||||||
|
// NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity
|
||||||
|
let _: Option<NonMaxU8> = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
|
||||||
|
// NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity
|
||||||
|
let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
72
tests/ui/eager_transmute.rs
Normal file
72
tests/ui/eager_transmute.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![warn(clippy::eager_transmute)]
|
||||||
|
#![allow(clippy::transmute_int_to_non_zero)]
|
||||||
|
|
||||||
|
use std::num::NonZeroU8;
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Opcode {
|
||||||
|
Add = 0,
|
||||||
|
Sub = 1,
|
||||||
|
Mul = 2,
|
||||||
|
Div = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int_to_opcode(op: u8) -> Option<Opcode> {
|
||||||
|
(op < 4).then_some(unsafe { std::mem::transmute(op) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(op: u8, unrelated: u8) {
|
||||||
|
true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
(op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn f2(op: u8) {
|
||||||
|
(op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_layout_scalar_valid_range_end(254)]
|
||||||
|
struct NonMaxU8(u8);
|
||||||
|
#[rustc_layout_scalar_valid_range_end(254)]
|
||||||
|
#[rustc_layout_scalar_valid_range_start(1)]
|
||||||
|
struct NonZeroNonMaxU8(u8);
|
||||||
|
|
||||||
|
macro_rules! impls {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
impl PartialEq<u8> for $t {
|
||||||
|
fn eq(&self, other: &u8) -> bool {
|
||||||
|
self.0 == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialOrd<u8> for $t {
|
||||||
|
fn partial_cmp(&self, other: &u8) -> Option<std::cmp::Ordering> {
|
||||||
|
self.0.partial_cmp(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
impls!(NonMaxU8, NonZeroNonMaxU8);
|
||||||
|
|
||||||
|
fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) {
|
||||||
|
// u8 -> NonZeroU8, do lint
|
||||||
|
let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
|
||||||
|
|
||||||
|
// NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range
|
||||||
|
let _: Option<u8> = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
|
||||||
|
// NonZeroU8 -> NonMaxU8, do lint, different niche
|
||||||
|
let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
|
||||||
|
// NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity
|
||||||
|
let _: Option<NonMaxU8> = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
|
||||||
|
// NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity
|
||||||
|
let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
92
tests/ui/eager_transmute.stderr
Normal file
92
tests/ui/eager_transmute.stderr
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:16:33
|
||||||
|
|
|
||||||
|
LL | (op < 4).then_some(unsafe { std::mem::transmute(op) })
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::eager-transmute` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::eager_transmute)]`
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | (op < 4).then(|| unsafe { std::mem::transmute(op) })
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:22:33
|
||||||
|
|
|
||||||
|
LL | (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:23:33
|
||||||
|
|
|
||||||
|
LL | (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:24:34
|
||||||
|
|
|
||||||
|
LL | (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:28:24
|
||||||
|
|
|
||||||
|
LL | (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:57:60
|
||||||
|
|
|
||||||
|
LL | let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:63:86
|
||||||
|
|
|
||||||
|
LL | let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: this transmute is always evaluated eagerly, even if the condition is false
|
||||||
|
--> $DIR/eager_transmute.rs:69:93
|
||||||
|
|
|
||||||
|
LL | let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider using `bool::then` to only transmute if the condition holds
|
||||||
|
|
|
||||||
|
LL | let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
|
||||||
|
| ~~~~ ++
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
|
@ -22,9 +22,9 @@ mod rustc_ok {
|
||||||
|
|
||||||
#[expect(illegal_floating_point_literal_pattern)]
|
#[expect(illegal_floating_point_literal_pattern)]
|
||||||
match x {
|
match x {
|
||||||
5.0 => {}
|
5.0 => {},
|
||||||
6.0 => {}
|
6.0 => {},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,9 @@ mod rustc_warn {
|
||||||
#[expect(illegal_floating_point_literal_pattern)]
|
#[expect(illegal_floating_point_literal_pattern)]
|
||||||
//~^ ERROR: this lint expectation is unfulfilled
|
//~^ ERROR: this lint expectation is unfulfilled
|
||||||
match x {
|
match x {
|
||||||
5 => {}
|
5 => {},
|
||||||
6 => {}
|
6 => {},
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
unused_mut,
|
unused_mut,
|
||||||
clippy::from_iter_instead_of_collect,
|
clippy::from_iter_instead_of_collect,
|
||||||
clippy::get_first,
|
clippy::get_first,
|
||||||
clippy::useless_vec
|
clippy::useless_vec,
|
||||||
|
clippy::out_of_bounds_indexing
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::unwrap_used)]
|
#![warn(clippy::unwrap_used)]
|
||||||
#![deny(clippy::get_unwrap)]
|
#![deny(clippy::get_unwrap)]
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
unused_mut,
|
unused_mut,
|
||||||
clippy::from_iter_instead_of_collect,
|
clippy::from_iter_instead_of_collect,
|
||||||
clippy::get_first,
|
clippy::get_first,
|
||||||
clippy::useless_vec
|
clippy::useless_vec,
|
||||||
|
clippy::out_of_bounds_indexing
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::unwrap_used)]
|
#![warn(clippy::unwrap_used)]
|
||||||
#![deny(clippy::get_unwrap)]
|
#![deny(clippy::get_unwrap)]
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:36:17
|
--> $DIR/get_unwrap.rs:37:17
|
||||||
|
|
|
|
||||||
LL | let _ = boxed_slice.get(1).unwrap();
|
LL | let _ = boxed_slice.get(1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/get_unwrap.rs:8:9
|
--> $DIR/get_unwrap.rs:9:9
|
||||||
|
|
|
|
||||||
LL | #![deny(clippy::get_unwrap)]
|
LL | #![deny(clippy::get_unwrap)]
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:36:17
|
--> $DIR/get_unwrap.rs:37:17
|
||||||
|
|
|
|
||||||
LL | let _ = boxed_slice.get(1).unwrap();
|
LL | let _ = boxed_slice.get(1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -22,13 +22,13 @@ LL | let _ = boxed_slice.get(1).unwrap();
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
|
= help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:37:17
|
--> $DIR/get_unwrap.rs:38:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_slice.get(0).unwrap();
|
LL | let _ = some_slice.get(0).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:37:17
|
--> $DIR/get_unwrap.rs:38:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_slice.get(0).unwrap();
|
LL | let _ = some_slice.get(0).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -37,13 +37,13 @@ LL | let _ = some_slice.get(0).unwrap();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:38:17
|
--> $DIR/get_unwrap.rs:39:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vec.get(0).unwrap();
|
LL | let _ = some_vec.get(0).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:38:17
|
--> $DIR/get_unwrap.rs:39:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vec.get(0).unwrap();
|
LL | let _ = some_vec.get(0).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -52,13 +52,13 @@ LL | let _ = some_vec.get(0).unwrap();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:39:17
|
--> $DIR/get_unwrap.rs:40:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vecdeque.get(0).unwrap();
|
LL | let _ = some_vecdeque.get(0).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:39:17
|
--> $DIR/get_unwrap.rs:40:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vecdeque.get(0).unwrap();
|
LL | let _ = some_vecdeque.get(0).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -67,13 +67,13 @@ LL | let _ = some_vecdeque.get(0).unwrap();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:40:17
|
--> $DIR/get_unwrap.rs:41:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_hashmap.get(&1).unwrap();
|
LL | let _ = some_hashmap.get(&1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:40:17
|
--> $DIR/get_unwrap.rs:41:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_hashmap.get(&1).unwrap();
|
LL | let _ = some_hashmap.get(&1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -82,13 +82,13 @@ LL | let _ = some_hashmap.get(&1).unwrap();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:41:17
|
--> $DIR/get_unwrap.rs:42:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_btreemap.get(&1).unwrap();
|
LL | let _ = some_btreemap.get(&1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:41:17
|
--> $DIR/get_unwrap.rs:42:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_btreemap.get(&1).unwrap();
|
LL | let _ = some_btreemap.get(&1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -97,13 +97,13 @@ LL | let _ = some_btreemap.get(&1).unwrap();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:45:21
|
--> $DIR/get_unwrap.rs:46:21
|
||||||
|
|
|
|
||||||
LL | let _: u8 = *boxed_slice.get(1).unwrap();
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:45:22
|
--> $DIR/get_unwrap.rs:46:22
|
||||||
|
|
|
|
||||||
LL | let _: u8 = *boxed_slice.get(1).unwrap();
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -112,13 +112,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:50:9
|
--> $DIR/get_unwrap.rs:51:9
|
||||||
|
|
|
|
||||||
LL | *boxed_slice.get_mut(0).unwrap() = 1;
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:50:10
|
--> $DIR/get_unwrap.rs:51:10
|
||||||
|
|
|
|
||||||
LL | *boxed_slice.get_mut(0).unwrap() = 1;
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -127,13 +127,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1;
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:51:9
|
--> $DIR/get_unwrap.rs:52:9
|
||||||
|
|
|
|
||||||
LL | *some_slice.get_mut(0).unwrap() = 1;
|
LL | *some_slice.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:51:10
|
--> $DIR/get_unwrap.rs:52:10
|
||||||
|
|
|
|
||||||
LL | *some_slice.get_mut(0).unwrap() = 1;
|
LL | *some_slice.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -142,13 +142,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1;
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:52:9
|
--> $DIR/get_unwrap.rs:53:9
|
||||||
|
|
|
|
||||||
LL | *some_vec.get_mut(0).unwrap() = 1;
|
LL | *some_vec.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:52:10
|
--> $DIR/get_unwrap.rs:53:10
|
||||||
|
|
|
|
||||||
LL | *some_vec.get_mut(0).unwrap() = 1;
|
LL | *some_vec.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -157,13 +157,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1;
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
|
error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:53:9
|
--> $DIR/get_unwrap.rs:54:9
|
||||||
|
|
|
|
||||||
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:53:10
|
--> $DIR/get_unwrap.rs:54:10
|
||||||
|
|
|
|
||||||
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -172,13 +172,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1;
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:65:17
|
--> $DIR/get_unwrap.rs:66:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:65:17
|
--> $DIR/get_unwrap.rs:66:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -187,13 +187,13 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:66:17
|
--> $DIR/get_unwrap.rs:67:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
|
||||||
|
|
||||||
error: used `unwrap()` on an `Option` value
|
error: used `unwrap()` on an `Option` value
|
||||||
--> $DIR/get_unwrap.rs:66:17
|
--> $DIR/get_unwrap.rs:67:17
|
||||||
|
|
|
|
||||||
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -202,25 +202,25 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
|
||||||
= help: consider using `expect()` to provide a better panic message
|
= help: consider using `expect()` to provide a better panic message
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:76:24
|
--> $DIR/get_unwrap.rs:77:24
|
||||||
|
|
|
|
||||||
LL | let _x: &i32 = f.get(1 + 2).unwrap();
|
LL | let _x: &i32 = f.get(1 + 2).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
|
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:79:18
|
--> $DIR/get_unwrap.rs:80:18
|
||||||
|
|
|
|
||||||
LL | let _x = f.get(1 + 2).unwrap().to_string();
|
LL | let _x = f.get(1 + 2).unwrap().to_string();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
|
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
|
||||||
|
|
||||||
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:82:18
|
--> $DIR/get_unwrap.rs:83:18
|
||||||
|
|
|
|
||||||
LL | let _x = f.get(1 + 2).unwrap().abs();
|
LL | let _x = f.get(1 + 2).unwrap().abs();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
|
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
|
||||||
|
|
||||||
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
|
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
|
||||||
--> $DIR/get_unwrap.rs:99:33
|
--> $DIR/get_unwrap.rs:100:33
|
||||||
|
|
|
|
||||||
LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
|
LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#![warn(clippy::if_then_some_else_none)]
|
#![warn(clippy::if_then_some_else_none)]
|
||||||
|
#![allow(clippy::redundant_pattern_matching)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Should issue an error.
|
// Should issue an error.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: this could be simplified with `bool::then`
|
error: this could be simplified with `bool::then`
|
||||||
--> $DIR/if_then_some_else_none.rs:5:13
|
--> $DIR/if_then_some_else_none.rs:6:13
|
||||||
|
|
|
|
||||||
LL | let _ = if foo() {
|
LL | let _ = if foo() {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -16,7 +16,7 @@ LL | | };
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
|
= help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
|
||||||
|
|
||||||
error: this could be simplified with `bool::then`
|
error: this could be simplified with `bool::then`
|
||||||
--> $DIR/if_then_some_else_none.rs:14:13
|
--> $DIR/if_then_some_else_none.rs:15:13
|
||||||
|
|
|
|
||||||
LL | let _ = if matches!(true, true) {
|
LL | let _ = if matches!(true, true) {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -31,7 +31,7 @@ LL | | };
|
||||||
= help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
|
= help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
|
||||||
|
|
||||||
error: this could be simplified with `bool::then_some`
|
error: this could be simplified with `bool::then_some`
|
||||||
--> $DIR/if_then_some_else_none.rs:24:28
|
--> $DIR/if_then_some_else_none.rs:25:28
|
||||||
|
|
|
|
||||||
LL | let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
|
LL | let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -39,7 +39,7 @@ LL | let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
|
||||||
= help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
|
= help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
|
||||||
|
|
||||||
error: this could be simplified with `bool::then_some`
|
error: this could be simplified with `bool::then_some`
|
||||||
--> $DIR/if_then_some_else_none.rs:29:13
|
--> $DIR/if_then_some_else_none.rs:30:13
|
||||||
|
|
|
|
||||||
LL | let _ = if !x { Some(0) } else { None };
|
LL | let _ = if !x { Some(0) } else { None };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -47,7 +47,7 @@ LL | let _ = if !x { Some(0) } else { None };
|
||||||
= help: consider using `bool::then_some` like: `(!x).then_some(0)`
|
= help: consider using `bool::then_some` like: `(!x).then_some(0)`
|
||||||
|
|
||||||
error: this could be simplified with `bool::then`
|
error: this could be simplified with `bool::then`
|
||||||
--> $DIR/if_then_some_else_none.rs:85:13
|
--> $DIR/if_then_some_else_none.rs:86:13
|
||||||
|
|
|
|
||||||
LL | let _ = if foo() {
|
LL | let _ = if foo() {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
|
|
@ -74,4 +74,7 @@ fn main() {
|
||||||
//~^ ERROR: indexing may panic
|
//~^ ERROR: indexing may panic
|
||||||
v[M];
|
v[M];
|
||||||
//~^ ERROR: indexing may panic
|
//~^ ERROR: indexing may panic
|
||||||
|
|
||||||
|
let slice = &x;
|
||||||
|
let _ = x[4];
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,21 @@ LL | x[index];
|
||||||
|
|
|
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
|
error: index is out of bounds
|
||||||
|
--> $DIR/indexing_slicing_index.rs:32:5
|
||||||
|
|
|
||||||
|
LL | x[4];
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]`
|
||||||
|
|
||||||
|
error: index is out of bounds
|
||||||
|
--> $DIR/indexing_slicing_index.rs:34:5
|
||||||
|
|
|
||||||
|
LL | x[1 << 3];
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/indexing_slicing_index.rs:45:14
|
--> $DIR/indexing_slicing_index.rs:45:14
|
||||||
|
|
|
|
||||||
|
@ -56,6 +71,12 @@ LL | const { &ARR[idx4()] };
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
= note: the suggestion might not be applicable in constant blocks
|
= note: the suggestion might not be applicable in constant blocks
|
||||||
|
|
||||||
|
error: index is out of bounds
|
||||||
|
--> $DIR/indexing_slicing_index.rs:55:5
|
||||||
|
|
|
||||||
|
LL | y[4];
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/indexing_slicing_index.rs:58:5
|
--> $DIR/indexing_slicing_index.rs:58:5
|
||||||
|
|
|
|
||||||
|
@ -80,6 +101,12 @@ LL | v[1 << 3];
|
||||||
|
|
|
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
|
error: index is out of bounds
|
||||||
|
--> $DIR/indexing_slicing_index.rs:70:5
|
||||||
|
|
|
||||||
|
LL | x[N];
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
error: indexing may panic
|
error: indexing may panic
|
||||||
--> $DIR/indexing_slicing_index.rs:73:5
|
--> $DIR/indexing_slicing_index.rs:73:5
|
||||||
|
|
|
|
||||||
|
@ -96,12 +123,18 @@ LL | v[M];
|
||||||
|
|
|
|
||||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||||
|
|
||||||
|
error: index is out of bounds
|
||||||
|
--> $DIR/indexing_slicing_index.rs:79:13
|
||||||
|
|
|
||||||
|
LL | let _ = x[4];
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
error[E0080]: evaluation of constant value failed
|
error[E0080]: evaluation of constant value failed
|
||||||
--> $DIR/indexing_slicing_index.rs:16:24
|
--> $DIR/indexing_slicing_index.rs:16:24
|
||||||
|
|
|
|
||||||
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
||||||
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error: aborting due to 17 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
|
|
@ -9,7 +9,7 @@ LL | | }
|
||||||
|
|
|
|
||||||
= note: `-D clippy::infinite-loop` implied by `-D warnings`
|
= note: `-D clippy::infinite-loop` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::infinite_loop)]`
|
= help: to override `-D warnings` add `#[allow(clippy::infinite_loop)]`
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn no_break() -> ! {
|
LL | fn no_break() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -26,7 +26,7 @@ LL | | do_something();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn all_inf() -> ! {
|
LL | fn all_inf() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -43,7 +43,7 @@ LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn all_inf() -> ! {
|
LL | fn all_inf() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -57,7 +57,7 @@ LL | | do_something();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____________^
|
| |_____________^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn all_inf() -> ! {
|
LL | fn all_inf() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -84,7 +84,7 @@ LL | | do_something();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn no_break_never_ret_noise() -> ! {
|
LL | fn no_break_never_ret_noise() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -101,7 +101,7 @@ LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn break_inner_but_not_outer_1(cond: bool) -> ! {
|
LL | fn break_inner_but_not_outer_1(cond: bool) -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -118,7 +118,7 @@ LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn break_inner_but_not_outer_2(cond: bool) -> ! {
|
LL | fn break_inner_but_not_outer_2(cond: bool) -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -132,7 +132,7 @@ LL | | do_something();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn break_outer_but_not_inner() -> ! {
|
LL | fn break_outer_but_not_inner() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -149,7 +149,7 @@ LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn break_wrong_loop(cond: bool) -> ! {
|
LL | fn break_wrong_loop(cond: bool) -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -166,7 +166,7 @@ LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn match_like() -> ! {
|
LL | fn match_like() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -180,7 +180,7 @@ LL | | let _x = matches!(result, Ok(v) if v != 0).then_some(0);
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn match_like() -> ! {
|
LL | fn match_like() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -197,7 +197,7 @@ LL | | });
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn match_like() -> ! {
|
LL | fn match_like() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -211,7 +211,7 @@ LL | | do_something();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn problematic_trait_method() -> ! {
|
LL | fn problematic_trait_method() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -225,7 +225,7 @@ LL | | do_something();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | fn could_be_problematic() -> ! {
|
LL | fn could_be_problematic() -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
@ -239,7 +239,7 @@ LL | | do_something();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: if this is intentional, consider specifing `!` as function return
|
help: if this is intentional, consider specifying `!` as function return
|
||||||
|
|
|
|
||||||
LL | let _loop_forever = || -> ! {
|
LL | let _loop_forever = || -> ! {
|
||||||
| ++++
|
| ++++
|
||||||
|
|
26
tests/ui/iter_filter_is_ok.fixed
Normal file
26
tests/ui/iter_filter_is_ok.fixed
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#![warn(clippy::iter_filter_is_ok)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let _ = vec![Ok(1), Err(2)].into_iter().flatten();
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
// Don't lint below
|
||||||
|
let mut counter = 0;
|
||||||
|
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
|
||||||
|
counter += 1;
|
||||||
|
o.is_ok()
|
||||||
|
});
|
||||||
|
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
|
||||||
|
// Roses are red,
|
||||||
|
// Violets are blue,
|
||||||
|
// `Err` is not an `Option`,
|
||||||
|
// and this doesn't ryme
|
||||||
|
o.is_ok()
|
||||||
|
});
|
||||||
|
}
|
26
tests/ui/iter_filter_is_ok.rs
Normal file
26
tests/ui/iter_filter_is_ok.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#![warn(clippy::iter_filter_is_ok)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
// Don't lint below
|
||||||
|
let mut counter = 0;
|
||||||
|
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
|
||||||
|
counter += 1;
|
||||||
|
o.is_ok()
|
||||||
|
});
|
||||||
|
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
|
||||||
|
// Roses are red,
|
||||||
|
// Violets are blue,
|
||||||
|
// `Err` is not an `Option`,
|
||||||
|
// and this doesn't ryme
|
||||||
|
o.is_ok()
|
||||||
|
});
|
||||||
|
}
|
23
tests/ui/iter_filter_is_ok.stderr
Normal file
23
tests/ui/iter_filter_is_ok.stderr
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
error: `filter` for `is_ok` on iterator over `Result`s
|
||||||
|
--> $DIR/iter_filter_is_ok.rs:4:52
|
||||||
|
|
|
||||||
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::iter-filter-is-ok` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_ok)]`
|
||||||
|
|
||||||
|
error: `filter` for `is_ok` on iterator over `Result`s
|
||||||
|
--> $DIR/iter_filter_is_ok.rs:6:52
|
||||||
|
|
|
||||||
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||||
|
|
||||||
|
error: `filter` for `is_ok` on iterator over `Result`s
|
||||||
|
--> $DIR/iter_filter_is_ok.rs:10:45
|
||||||
|
|
|
||||||
|
LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
27
tests/ui/iter_filter_is_some.fixed
Normal file
27
tests/ui/iter_filter_is_some.fixed
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#![warn(clippy::iter_filter_is_some)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = vec![Some(1)].into_iter().flatten();
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
let _ = vec![Some(1)].into_iter().flatten();
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let _ = vec![Some(1)].into_iter().flatten();
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
// Don't lint below
|
||||||
|
let mut counter = 0;
|
||||||
|
let _ = vec![Some(1)].into_iter().filter(|o| {
|
||||||
|
counter += 1;
|
||||||
|
o.is_some()
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = vec![Some(1)].into_iter().filter(|o| {
|
||||||
|
// Roses are red,
|
||||||
|
// Violets are blue,
|
||||||
|
// `Err` is not an `Option`,
|
||||||
|
// and this doesn't ryme
|
||||||
|
o.is_some()
|
||||||
|
});
|
||||||
|
}
|
27
tests/ui/iter_filter_is_some.rs
Normal file
27
tests/ui/iter_filter_is_some.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#![warn(clippy::iter_filter_is_some)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = vec![Some(1)].into_iter().filter(Option::is_some);
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
|
||||||
|
//~^ HELP: consider using `flatten` instead
|
||||||
|
|
||||||
|
// Don't lint below
|
||||||
|
let mut counter = 0;
|
||||||
|
let _ = vec![Some(1)].into_iter().filter(|o| {
|
||||||
|
counter += 1;
|
||||||
|
o.is_some()
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = vec![Some(1)].into_iter().filter(|o| {
|
||||||
|
// Roses are red,
|
||||||
|
// Violets are blue,
|
||||||
|
// `Err` is not an `Option`,
|
||||||
|
// and this doesn't ryme
|
||||||
|
o.is_some()
|
||||||
|
});
|
||||||
|
}
|
23
tests/ui/iter_filter_is_some.stderr
Normal file
23
tests/ui/iter_filter_is_some.stderr
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
error: `filter` for `is_some` on iterator over `Option`
|
||||||
|
--> $DIR/iter_filter_is_some.rs:4:39
|
||||||
|
|
|
||||||
|
LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::iter-filter-is-some` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_some)]`
|
||||||
|
|
||||||
|
error: `filter` for `is_some` on iterator over `Option`
|
||||||
|
--> $DIR/iter_filter_is_some.rs:6:39
|
||||||
|
|
|
||||||
|
LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||||
|
|
||||||
|
error: `filter` for `is_some` on iterator over `Option`
|
||||||
|
--> $DIR/iter_filter_is_some.rs:10:39
|
||||||
|
|
|
||||||
|
LL | let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -60,3 +60,24 @@ fn foo() -> Option<()> {
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lint not just `return None`, but also `return None;` (note the semicolon)
|
||||||
|
fn issue11993(y: Option<i32>) -> Option<i32> {
|
||||||
|
let x = y?;
|
||||||
|
|
||||||
|
// don't lint: more than one statement in the else body
|
||||||
|
let Some(x) = y else {
|
||||||
|
todo!();
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(x) = y else {
|
||||||
|
// Roses are red,
|
||||||
|
// violets are blue,
|
||||||
|
// please keep this comment,
|
||||||
|
// it's art, you know?
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
@ -65,3 +65,26 @@ fn foo() -> Option<()> {
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lint not just `return None`, but also `return None;` (note the semicolon)
|
||||||
|
fn issue11993(y: Option<i32>) -> Option<i32> {
|
||||||
|
let Some(x) = y else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
// don't lint: more than one statement in the else body
|
||||||
|
let Some(x) = y else {
|
||||||
|
todo!();
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(x) = y else {
|
||||||
|
// Roses are red,
|
||||||
|
// violets are blue,
|
||||||
|
// please keep this comment,
|
||||||
|
// it's art, you know?
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
@ -53,5 +53,13 @@ error: this could be rewritten as `let...else`
|
||||||
LL | let v = if let Some(v_some) = g() { v_some } else { return None };
|
LL | let v = if let Some(v_some) = g() { v_some } else { return None };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return None };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return None };`
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: this `let...else` may be rewritten with the `?` operator
|
||||||
|
--> $DIR/manual_let_else_question_mark.rs:71:5
|
||||||
|
|
|
||||||
|
LL | / let Some(x) = y else {
|
||||||
|
LL | | return None;
|
||||||
|
LL | | };
|
||||||
|
| |______^ help: replace it with: `let x = y?;`
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// With an explicit return type it should lint too
|
/// With an explicit return type it should lint too
|
||||||
/// ```edition2015
|
/// ```edition2015
|
||||||
/// fn main() -> () {
|
/// fn main() -> () {
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This should, too.
|
/// This should, too.
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
/// unimplemented!();
|
/// unimplemented!();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This one too.
|
/// This one too.
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// // the fn is not always the first line
|
/// // the fn is not always the first line
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
clippy::nonminimal_bool,
|
clippy::nonminimal_bool,
|
||||||
clippy::short_circuit_statement,
|
clippy::short_circuit_statement,
|
||||||
clippy::unnecessary_operation,
|
clippy::unnecessary_operation,
|
||||||
|
clippy::redundant_pattern_matching,
|
||||||
unused
|
unused
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::needless_if)]
|
#![warn(clippy::needless_if)]
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
clippy::nonminimal_bool,
|
clippy::nonminimal_bool,
|
||||||
clippy::short_circuit_statement,
|
clippy::short_circuit_statement,
|
||||||
clippy::unnecessary_operation,
|
clippy::unnecessary_operation,
|
||||||
|
clippy::redundant_pattern_matching,
|
||||||
unused
|
unused
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::needless_if)]
|
#![warn(clippy::needless_if)]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: this `if` branch is empty
|
error: this `if` branch is empty
|
||||||
--> $DIR/needless_if.rs:26:5
|
--> $DIR/needless_if.rs:27:5
|
||||||
|
|
|
|
||||||
LL | if (true) {}
|
LL | if (true) {}
|
||||||
| ^^^^^^^^^^^^ help: you can remove it
|
| ^^^^^^^^^^^^ help: you can remove it
|
||||||
|
@ -8,13 +8,13 @@ LL | if (true) {}
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::needless_if)]`
|
= help: to override `-D warnings` add `#[allow(clippy::needless_if)]`
|
||||||
|
|
||||||
error: this `if` branch is empty
|
error: this `if` branch is empty
|
||||||
--> $DIR/needless_if.rs:28:5
|
--> $DIR/needless_if.rs:29:5
|
||||||
|
|
|
|
||||||
LL | if maybe_side_effect() {}
|
LL | if maybe_side_effect() {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();`
|
||||||
|
|
||||||
error: this `if` branch is empty
|
error: this `if` branch is empty
|
||||||
--> $DIR/needless_if.rs:33:5
|
--> $DIR/needless_if.rs:34:5
|
||||||
|
|
|
|
||||||
LL | / if {
|
LL | / if {
|
||||||
LL | | return;
|
LL | | return;
|
||||||
|
@ -29,7 +29,7 @@ LL + });
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` branch is empty
|
error: this `if` branch is empty
|
||||||
--> $DIR/needless_if.rs:49:5
|
--> $DIR/needless_if.rs:50:5
|
||||||
|
|
|
|
||||||
LL | / if {
|
LL | / if {
|
||||||
LL | | if let true = true
|
LL | | if let true = true
|
||||||
|
@ -54,19 +54,19 @@ LL + } && true);
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this `if` branch is empty
|
error: this `if` branch is empty
|
||||||
--> $DIR/needless_if.rs:93:5
|
--> $DIR/needless_if.rs:94:5
|
||||||
|
|
|
|
||||||
LL | if { maybe_side_effect() } {}
|
LL | if { maybe_side_effect() } {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
|
||||||
|
|
||||||
error: this `if` branch is empty
|
error: this `if` branch is empty
|
||||||
--> $DIR/needless_if.rs:95:5
|
--> $DIR/needless_if.rs:96:5
|
||||||
|
|
|
|
||||||
LL | if { maybe_side_effect() } && true {}
|
LL | if { maybe_side_effect() } && true {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
|
||||||
|
|
||||||
error: this `if` branch is empty
|
error: this `if` branch is empty
|
||||||
--> $DIR/needless_if.rs:99:5
|
--> $DIR/needless_if.rs:100:5
|
||||||
|
|
|
|
||||||
LL | if true {}
|
LL | if true {}
|
||||||
| ^^^^^^^^^^ help: you can remove it: `true;`
|
| ^^^^^^^^^^ help: you can remove it: `true;`
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
//@no-rustfix: overlapping suggestions
|
//@no-rustfix: overlapping suggestions
|
||||||
#![feature(lint_reasons)]
|
#![feature(lint_reasons)]
|
||||||
#![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)]
|
#![allow(
|
||||||
|
unused,
|
||||||
|
clippy::diverging_sub_expression,
|
||||||
|
clippy::needless_if,
|
||||||
|
clippy::redundant_pattern_matching
|
||||||
|
)]
|
||||||
#![warn(clippy::nonminimal_bool)]
|
#![warn(clippy::nonminimal_bool)]
|
||||||
#![allow(clippy::useless_vec)]
|
#![allow(clippy::useless_vec)]
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:13:13
|
--> $DIR/nonminimal_bool.rs:18:13
|
||||||
|
|
|
|
||||||
LL | let _ = !true;
|
LL | let _ = !true;
|
||||||
| ^^^^^ help: try: `false`
|
| ^^^^^ help: try: `false`
|
||||||
|
@ -8,43 +8,43 @@ LL | let _ = !true;
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
|
= help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:16:13
|
--> $DIR/nonminimal_bool.rs:21:13
|
||||||
|
|
|
|
||||||
LL | let _ = !false;
|
LL | let _ = !false;
|
||||||
| ^^^^^^ help: try: `true`
|
| ^^^^^^ help: try: `true`
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:18:13
|
--> $DIR/nonminimal_bool.rs:23:13
|
||||||
|
|
|
|
||||||
LL | let _ = !!a;
|
LL | let _ = !!a;
|
||||||
| ^^^ help: try: `a`
|
| ^^^ help: try: `a`
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:20:13
|
--> $DIR/nonminimal_bool.rs:25:13
|
||||||
|
|
|
|
||||||
LL | let _ = false || a;
|
LL | let _ = false || a;
|
||||||
| ^^^^^^^^^^ help: try: `a`
|
| ^^^^^^^^^^ help: try: `a`
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:25:13
|
--> $DIR/nonminimal_bool.rs:30:13
|
||||||
|
|
|
|
||||||
LL | let _ = !(!a && b);
|
LL | let _ = !(!a && b);
|
||||||
| ^^^^^^^^^^ help: try: `a || !b`
|
| ^^^^^^^^^^ help: try: `a || !b`
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:27:13
|
--> $DIR/nonminimal_bool.rs:32:13
|
||||||
|
|
|
|
||||||
LL | let _ = !(!a || b);
|
LL | let _ = !(!a || b);
|
||||||
| ^^^^^^^^^^ help: try: `a && !b`
|
| ^^^^^^^^^^ help: try: `a && !b`
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:29:13
|
--> $DIR/nonminimal_bool.rs:34:13
|
||||||
|
|
|
|
||||||
LL | let _ = !a && !(b && c);
|
LL | let _ = !a && !(b && c);
|
||||||
| ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)`
|
| ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)`
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:38:13
|
--> $DIR/nonminimal_bool.rs:43:13
|
||||||
|
|
|
|
||||||
LL | let _ = a == b && c == 5 && a == b;
|
LL | let _ = a == b && c == 5 && a == b;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -57,7 +57,7 @@ LL | let _ = a == b && c == 5;
|
||||||
| ~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:40:13
|
--> $DIR/nonminimal_bool.rs:45:13
|
||||||
|
|
|
|
||||||
LL | let _ = a == b || c == 5 || a == b;
|
LL | let _ = a == b || c == 5 || a == b;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -70,7 +70,7 @@ LL | let _ = a == b || c == 5;
|
||||||
| ~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:42:13
|
--> $DIR/nonminimal_bool.rs:47:13
|
||||||
|
|
|
|
||||||
LL | let _ = a == b && c == 5 && b == a;
|
LL | let _ = a == b && c == 5 && b == a;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -83,7 +83,7 @@ LL | let _ = a == b && c == 5;
|
||||||
| ~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:44:13
|
--> $DIR/nonminimal_bool.rs:49:13
|
||||||
|
|
|
|
||||||
LL | let _ = a != b || !(a != b || c == d);
|
LL | let _ = a != b || !(a != b || c == d);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -96,7 +96,7 @@ LL | let _ = a != b || c != d;
|
||||||
| ~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:46:13
|
--> $DIR/nonminimal_bool.rs:51:13
|
||||||
|
|
|
|
||||||
LL | let _ = a != b && !(a != b && c == d);
|
LL | let _ = a != b && !(a != b && c == d);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -109,7 +109,7 @@ LL | let _ = a != b && c != d;
|
||||||
| ~~~~~~~~~~~~~~~~
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: this boolean expression can be simplified
|
error: this boolean expression can be simplified
|
||||||
--> $DIR/nonminimal_bool.rs:77:8
|
--> $DIR/nonminimal_bool.rs:82:8
|
||||||
|
|
|
|
||||||
LL | if matches!(true, true) && true {
|
LL | if matches!(true, true) && true {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)`
|
||||||
|
|
|
@ -3,12 +3,18 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = Some(Some(1)).flatten();
|
let _ = Some(Some(1)).flatten();
|
||||||
|
//~^ ERROR: `filter` for `Some` followed by `unwrap`
|
||||||
let _ = Some(Some(1)).flatten();
|
let _ = Some(Some(1)).flatten();
|
||||||
|
//~^ ERROR: `filter` for `Some` followed by `unwrap`
|
||||||
let _ = Some(1).map(odds_out).flatten();
|
let _ = Some(1).map(odds_out).flatten();
|
||||||
|
//~^ ERROR: `filter` for `Some` followed by `unwrap`
|
||||||
let _ = Some(1).map(odds_out).flatten();
|
let _ = Some(1).map(odds_out).flatten();
|
||||||
|
//~^ ERROR: `filter` for `Some` followed by `unwrap`
|
||||||
|
|
||||||
let _ = vec![Some(1)].into_iter().flatten();
|
let _ = vec![Some(1)].into_iter().flatten();
|
||||||
|
//~^ ERROR: `filter` for `Some` followed by `unwrap`
|
||||||
let _ = vec![Some(1)].into_iter().flatten();
|
let _ = vec![Some(1)].into_iter().flatten();
|
||||||
|
//~^ ERROR: `filter` for `Some` followed by `unwrap`
|
||||||
let _ = vec![1]
|
let _ = vec![1]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(odds_out)
|
.map(odds_out)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue