mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 17:24:06 +00:00
Auto merge of #79228 - flip1995:clippyup, r=oli-obk
Update Clippy Biweekly Clippy update r? `@Manishearth`
This commit is contained in:
commit
53ce1dd719
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,8 +1,8 @@
|
||||
Thank you for making Clippy better!
|
||||
|
||||
We're collecting our changelog from pull request descriptions.
|
||||
If your PR only updates to the latest nightly, you can leave the
|
||||
`changelog` entry as `none`. Otherwise, please write a short comment
|
||||
If your PR only includes internal changes, you can just write
|
||||
`changelog: none`. Otherwise, please write a short comment
|
||||
explaining your change.
|
||||
|
||||
If your PR fixes an issue, you can add "fixes #issue_number" into this
|
||||
@ -28,5 +28,5 @@ Delete this line and everything above before opening your PR.
|
||||
|
||||
---
|
||||
|
||||
*Please keep the line below*
|
||||
changelog: none
|
||||
*Please write a short comment explaining your change (or "none" for internal only changes)*
|
||||
changelog:
|
||||
|
127
CHANGELOG.md
127
CHANGELOG.md
@ -6,11 +6,117 @@ document.
|
||||
|
||||
## Unreleased / In Rust Nightly
|
||||
|
||||
[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master)
|
||||
[b20d4c1...master](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...master)
|
||||
|
||||
## Rust 1.49
|
||||
|
||||
Current beta, release 2020-12-31
|
||||
|
||||
[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
|
||||
|
||||
### New Lints
|
||||
|
||||
* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
|
||||
* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
|
||||
* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
|
||||
* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
|
||||
* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
|
||||
* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
|
||||
* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103)
|
||||
* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109)
|
||||
* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123)
|
||||
* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135)
|
||||
* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157)
|
||||
* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165)
|
||||
* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177)
|
||||
* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183)
|
||||
* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226)
|
||||
* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227)
|
||||
* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Rename `single_char_push_str` to [`single_char_add_str`]
|
||||
[#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
|
||||
* Rename `zero_width_space` to [`invisible_characters`]
|
||||
[#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
|
||||
* Deprecate [`drop_bounds`] (uplifted)
|
||||
[#6111](https://github.com/rust-lang/rust-clippy/pull/6111)
|
||||
* Move [`string_lit_as_bytes`] to `nursery`
|
||||
[#6117](https://github.com/rust-lang/rust-clippy/pull/6117)
|
||||
* Move [`rc_buffer`] to `restriction`
|
||||
[#6128](https://github.com/rust-lang/rust-clippy/pull/6128)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`manual_memcpy`]: Also lint when there are loop counters (and produce a
|
||||
reliable suggestion)
|
||||
[#5727](https://github.com/rust-lang/rust-clippy/pull/5727)
|
||||
* [`single_char_add_str`]: Also lint on `String::insert_str`
|
||||
[#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
|
||||
* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}`
|
||||
[#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
|
||||
* [`eq_op`]: Also lint on the `assert_*!` macro family
|
||||
[#6167](https://github.com/rust-lang/rust-clippy/pull/6167)
|
||||
* [`items_after_statements`]: Also lint in local macro expansions
|
||||
[#6176](https://github.com/rust-lang/rust-clippy/pull/6176)
|
||||
* [`unnecessary_cast`]: Also lint casts on integer and float literals
|
||||
[#6187](https://github.com/rust-lang/rust-clippy/pull/6187)
|
||||
* [`manual_unwrap_or`]: Also lint `Result::unwrap_or`
|
||||
[#6190](https://github.com/rust-lang/rust-clippy/pull/6190)
|
||||
* [`match_like_matches_macro`]: Also lint when `match` has more than two arms
|
||||
[#6216](https://github.com/rust-lang/rust-clippy/pull/6216)
|
||||
* [`integer_arithmetic`]: Better handle `/` an `%` operators
|
||||
[#6229](https://github.com/rust-lang/rust-clippy/pull/6229)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the
|
||||
lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978)
|
||||
* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it
|
||||
is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076)
|
||||
* [`or_fun_call`]: Revert changes addressing the handling of `const fn`
|
||||
[#6077](https://github.com/rust-lang/rust-clippy/pull/6077)
|
||||
* [`needless_range_loop`]: No longer lints, when the iterable is used in the
|
||||
range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102)
|
||||
* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent
|
||||
[#6104](https://github.com/rust-lang/rust-clippy/pull/6104)
|
||||
* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a
|
||||
float (e.g. `713.32_64`)
|
||||
[#6114](https://github.com/rust-lang/rust-clippy/pull/6114)
|
||||
* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex`
|
||||
[#6132](https://github.com/rust-lang/rust-clippy/pull/6132)
|
||||
* [`boxed_local`]: No longer lints on `extern fn` arguments
|
||||
[#6133](https://github.com/rust-lang/rust-clippy/pull/6133)
|
||||
* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where`
|
||||
clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter
|
||||
[#6078](https://github.com/rust-lang/rust-clippy/pull/6078)
|
||||
* [`needless_arbitrary_self_type`]: Correctly handle expanded code
|
||||
[#6093](https://github.com/rust-lang/rust-clippy/pull/6093)
|
||||
* [`useless_format`]: Preserve raw strings in suggestion
|
||||
[#6151](https://github.com/rust-lang/rust-clippy/pull/6151)
|
||||
* [`empty_loop`]: Suggest alternatives
|
||||
[#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
|
||||
* [`borrowed_box`]: Correctly add parentheses in suggestion
|
||||
[#6200](https://github.com/rust-lang/rust-clippy/pull/6200)
|
||||
* [`unused_unit`]: Improve suggestion formatting
|
||||
[#6247](https://github.com/rust-lang/rust-clippy/pull/6247)
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
* Some doc improvements:
|
||||
* [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
|
||||
* [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
|
||||
* [`doc_markdown`]: Document problematic link text style
|
||||
[#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
|
||||
|
||||
## Rust 1.48
|
||||
|
||||
Current beta, release 2020-11-19
|
||||
Current stable, released 2020-11-19
|
||||
|
||||
[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
|
||||
|
||||
@ -56,7 +162,7 @@ Current beta, release 2020-11-19
|
||||
|
||||
* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
|
||||
[#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
|
||||
* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
|
||||
* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
|
||||
[#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
|
||||
* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
|
||||
[#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
|
||||
@ -64,7 +170,7 @@ Current beta, release 2020-11-19
|
||||
[#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
|
||||
* [`doc_markdown`]: allow using "GraphQL" without backticks
|
||||
[#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
|
||||
* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
|
||||
* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
|
||||
[#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
|
||||
* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
|
||||
[#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
|
||||
@ -85,19 +191,19 @@ Current beta, release 2020-11-19
|
||||
[#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
|
||||
* [`useless_conversion`]: show the type in the error message
|
||||
[#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
|
||||
* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
|
||||
* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
|
||||
[#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
|
||||
* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
|
||||
[#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
|
||||
* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
|
||||
[#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
|
||||
* [`collapsible_if`]: don't use expanded code in the suggestion
|
||||
* [`collapsible_if`]: don't use expanded code in the suggestion
|
||||
[#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
|
||||
* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
|
||||
[#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
|
||||
* [`unit_arg`]: improve the readability of the suggestion
|
||||
[#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
|
||||
* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
|
||||
* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
|
||||
[#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
|
||||
* Show line count and max lines in [`too_many_lines`] lint message
|
||||
[#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
|
||||
@ -105,7 +211,7 @@ Current beta, release 2020-11-19
|
||||
[#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
|
||||
* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
|
||||
[#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
|
||||
* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
|
||||
* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
|
||||
[#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
|
||||
* Make lint messages adhere to rustc dev guide conventions
|
||||
[#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
|
||||
@ -128,7 +234,7 @@ Current beta, release 2020-11-19
|
||||
|
||||
## Rust 1.47
|
||||
|
||||
Current stable, released 2020-10-08
|
||||
Released 2020-10-08
|
||||
|
||||
[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
|
||||
|
||||
@ -1787,6 +1893,7 @@ Released 2018-09-13
|
||||
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
|
||||
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
|
||||
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
|
||||
[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
|
||||
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
|
||||
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
|
||||
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
|
||||
@ -1956,6 +2063,7 @@ Released 2018-09-13
|
||||
[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
|
||||
[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
|
||||
[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
|
||||
[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
|
||||
[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
|
||||
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
|
||||
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
|
||||
@ -2006,6 +2114,7 @@ Released 2018-09-13
|
||||
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
|
||||
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
|
||||
[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
|
||||
[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
|
||||
[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
|
||||
[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
|
||||
[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
|
||||
|
30
README.md
30
README.md
@ -7,28 +7,22 @@ A collection of lints to catch common mistakes and improve your [Rust](https://g
|
||||
|
||||
[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||
|
||||
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
|
||||
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
|
||||
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
|
||||
|
||||
* `clippy::all` (everything that is on by default: all the categories below except for `nursery`, `pedantic`, and `cargo`)
|
||||
* `clippy::correctness` (code that is just **outright wrong** or **very very useless**, causes hard errors by default)
|
||||
* `clippy::style` (code that should be written in a more idiomatic way)
|
||||
* `clippy::complexity` (code that does something simple but in a complex way)
|
||||
* `clippy::perf` (code that can be written in a faster way)
|
||||
* `clippy::pedantic` (lints which are rather strict, off by default)
|
||||
* `clippy::nursery` (new lints that aren't quite ready yet, off by default)
|
||||
* `clippy::cargo` (checks against the cargo manifest, off by default)
|
||||
Category | Description | Default level
|
||||
-- | -- | --
|
||||
`clippy::all` | all lints that are on by default (correctness, style, complexity, perf) | **warn/deny**
|
||||
`clippy::correctness` | code that is outright wrong or very useless | **deny**
|
||||
`clippy::style` | code that should be written in a more idiomatic way | **warn**
|
||||
`clippy::complexity` | code that does something simple but in a complex way | **warn**
|
||||
`clippy::perf` | code that can be written to run faster | **warn**
|
||||
`clippy::pedantic` | lints which are rather strict or might have false positives | allow
|
||||
`clippy::nursery` | new lints that are still under development | allow
|
||||
`clippy::cargo` | lints for the cargo manifest | allow
|
||||
|
||||
More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
|
||||
|
||||
Only the following of those categories are enabled by default:
|
||||
|
||||
* `clippy::style`
|
||||
* `clippy::correctness`
|
||||
* `clippy::complexity`
|
||||
* `clippy::perf`
|
||||
|
||||
Other categories need to be enabled in order for their lints to be executed.
|
||||
|
||||
The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are
|
||||
for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used
|
||||
very selectively, if at all.
|
||||
|
@ -129,7 +129,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
|
||||
if let ExprKind::Block(ref block, _) = arms[0].body.kind;
|
||||
if block.stmts.is_empty();
|
||||
if let Some(block_expr) = &block.expr;
|
||||
// inner block is optional. unwarp it if it exists, or use the expression as is otherwise.
|
||||
// inner block is optional. unwrap it if it exists, or use the expression as is otherwise.
|
||||
if let Some(begin_panic_call) = match block_expr.kind {
|
||||
ExprKind::Block(ref inner_block, _) => &inner_block.expr,
|
||||
_ => &block.expr,
|
||||
|
@ -45,7 +45,7 @@ declare_clippy_lint! {
|
||||
/// }
|
||||
/// ```
|
||||
pub AWAIT_HOLDING_LOCK,
|
||||
correctness,
|
||||
pedantic,
|
||||
"Inside an async function, holding a MutexGuard while calling await"
|
||||
}
|
||||
|
||||
@ -65,8 +65,8 @@ declare_clippy_lint! {
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// async fn foo(x: &RefCell<u32>) {
|
||||
/// let b = x.borrow_mut()();
|
||||
/// *ref += 1;
|
||||
/// let mut y = x.borrow_mut();
|
||||
/// *y += 1;
|
||||
/// bar.await;
|
||||
/// }
|
||||
/// ```
|
||||
@ -77,14 +77,14 @@ declare_clippy_lint! {
|
||||
///
|
||||
/// async fn foo(x: &RefCell<u32>) {
|
||||
/// {
|
||||
/// let b = x.borrow_mut();
|
||||
/// *ref += 1;
|
||||
/// let mut y = x.borrow_mut();
|
||||
/// *y += 1;
|
||||
/// }
|
||||
/// bar.await;
|
||||
/// }
|
||||
/// ```
|
||||
pub AWAIT_HOLDING_REFCELL_REF,
|
||||
correctness,
|
||||
pedantic,
|
||||
"Inside an async function, holding a RefCell ref while calling await"
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,21 @@ declare_clippy_lint! {
|
||||
/// [package]
|
||||
/// name = "clippy"
|
||||
/// version = "0.0.212"
|
||||
/// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
/// repository = "https://github.com/rust-lang/rust-clippy"
|
||||
/// readme = "README.md"
|
||||
/// license = "MIT OR Apache-2.0"
|
||||
/// keywords = ["clippy", "lint", "plugin"]
|
||||
/// categories = ["development-tools", "development-tools::cargo-plugins"]
|
||||
/// ```
|
||||
///
|
||||
/// Should include an authors field like:
|
||||
///
|
||||
/// ```toml
|
||||
/// # This `Cargo.toml` includes all common metadata
|
||||
/// [package]
|
||||
/// name = "clippy"
|
||||
/// version = "0.0.212"
|
||||
/// authors = ["Someone <someone@rust-lang.org>"]
|
||||
/// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
/// repository = "https://github.com/rust-lang/rust-clippy"
|
||||
|
@ -181,3 +181,8 @@ declare_deprecated_lint! {
|
||||
pub TEMPORARY_CSTRING_AS_PTR,
|
||||
"this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`"
|
||||
}
|
||||
|
||||
declare_deprecated_lint! {
|
||||
pub PANIC_PARAMS,
|
||||
"this lint has been uplifted to rustc and is now called `panic_fmt`"
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ declare_clippy_lint! {
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for comparing to an empty slice such as "" or [],`
|
||||
/// **What it does:** Checks for comparing to an empty slice such as `""` or `[]`,
|
||||
/// and suggests using `.is_empty()` where applicable.
|
||||
///
|
||||
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
|
||||
|
@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
|
||||
use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `let _ = <expr>`
|
||||
@ -58,7 +58,48 @@ declare_clippy_lint! {
|
||||
"non-binding let on a synchronization lock"
|
||||
}
|
||||
|
||||
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]);
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `let _ = <expr>`
|
||||
/// where expr has a type that implements `Drop`
|
||||
///
|
||||
/// **Why is this bad?** This statement immediately drops the initializer
|
||||
/// expression instead of extending its lifetime to the end of the scope, which
|
||||
/// is often not intended. To extend the expression's lifetime to the end of the
|
||||
/// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
|
||||
/// explicitly drop the expression, `std::mem::drop` conveys your intention
|
||||
/// better and is less error-prone.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// Bad:
|
||||
/// ```rust,ignore
|
||||
/// struct Droppable;
|
||||
/// impl Drop for Droppable {
|
||||
/// fn drop(&mut self) {}
|
||||
/// }
|
||||
/// {
|
||||
/// let _ = Droppable;
|
||||
/// // ^ dropped here
|
||||
/// /* more code */
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Good:
|
||||
/// ```rust,ignore
|
||||
/// {
|
||||
/// let _droppable = Droppable;
|
||||
/// /* more code */
|
||||
/// // dropped at end of scope
|
||||
/// }
|
||||
/// ```
|
||||
pub LET_UNDERSCORE_DROP,
|
||||
pedantic,
|
||||
"non-binding let on a type that implements `Drop`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
|
||||
|
||||
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
|
||||
&paths::MUTEX_GUARD,
|
||||
@ -84,6 +125,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
||||
|
||||
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
|
||||
});
|
||||
let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait|
|
||||
init_ty.walk().any(|inner| match inner.unpack() {
|
||||
GenericArgKind::Type(inner_ty) => {
|
||||
implements_trait(cx, inner_ty, drop_trait, &[])
|
||||
},
|
||||
|
||||
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
|
||||
})
|
||||
);
|
||||
if contains_sync_guard {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
@ -94,6 +144,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
||||
"consider using an underscore-prefixed named \
|
||||
binding or dropping explicitly with `std::mem::drop`"
|
||||
)
|
||||
} else if implements_drop {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LET_UNDERSCORE_DROP,
|
||||
local.span,
|
||||
"non-binding `let` on a type that implements `Drop`",
|
||||
None,
|
||||
"consider using an underscore-prefixed named \
|
||||
binding or dropping explicitly with `std::mem::drop`"
|
||||
)
|
||||
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
@ -323,6 +323,7 @@ mod unicode;
|
||||
mod unit_return_expecting_ord;
|
||||
mod unnamed_address;
|
||||
mod unnecessary_sort_by;
|
||||
mod unnecessary_wraps;
|
||||
mod unnested_or_patterns;
|
||||
mod unsafe_removed_from_name;
|
||||
mod unused_io_amount;
|
||||
@ -495,6 +496,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
"clippy::temporary_cstring_as_ptr",
|
||||
"this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`",
|
||||
);
|
||||
store.register_removed(
|
||||
"clippy::panic_params",
|
||||
"this lint has been uplifted to rustc and is now called `panic_fmt`",
|
||||
);
|
||||
// end deprecated lints, do not remove this comment, it’s used in `update_lints`
|
||||
|
||||
// begin register lints, do not remove this comment, it’s used in `update_lints`
|
||||
@ -622,6 +627,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&len_zero::LEN_WITHOUT_IS_EMPTY,
|
||||
&len_zero::LEN_ZERO,
|
||||
&let_if_seq::USELESS_LET_IF_SEQ,
|
||||
&let_underscore::LET_UNDERSCORE_DROP,
|
||||
&let_underscore::LET_UNDERSCORE_LOCK,
|
||||
&let_underscore::LET_UNDERSCORE_MUST_USE,
|
||||
&lifetimes::EXTRA_UNUSED_LIFETIMES,
|
||||
@ -831,6 +837,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&stable_sort_primitive::STABLE_SORT_PRIMITIVE,
|
||||
&strings::STRING_ADD,
|
||||
&strings::STRING_ADD_ASSIGN,
|
||||
&strings::STRING_FROM_UTF8_AS_BYTES,
|
||||
&strings::STRING_LIT_AS_BYTES,
|
||||
&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
|
||||
&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
|
||||
@ -889,6 +896,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&unnamed_address::FN_ADDRESS_COMPARISONS,
|
||||
&unnamed_address::VTABLE_ADDRESS_COMPARISONS,
|
||||
&unnecessary_sort_by::UNNECESSARY_SORT_BY,
|
||||
&unnecessary_wraps::UNNECESSARY_WRAPS,
|
||||
&unnested_or_patterns::UNNESTED_OR_PATTERNS,
|
||||
&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
|
||||
&unused_io_amount::UNUSED_IO_AMOUNT,
|
||||
@ -1061,6 +1069,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|| box redundant_clone::RedundantClone);
|
||||
store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
|
||||
store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
|
||||
store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
|
||||
store.register_late_pass(|| box types::RefToMut);
|
||||
store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
|
||||
store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn);
|
||||
@ -1215,6 +1224,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
|
||||
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
|
||||
LintId::of(&attrs::INLINE_ALWAYS),
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||
LintId::of(&bit_mask::VERBOSE_BIT_MASK),
|
||||
LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
|
||||
LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
|
||||
@ -1238,6 +1249,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
|
||||
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
|
||||
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
|
||||
LintId::of(&let_underscore::LET_UNDERSCORE_DROP),
|
||||
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
|
||||
LintId::of(&literal_representation::UNREADABLE_LITERAL),
|
||||
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
|
||||
@ -1317,8 +1329,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&attrs::MISMATCHED_TARGET_OS),
|
||||
LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
|
||||
LintId::of(&attrs::USELESS_ATTRIBUTE),
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||
LintId::of(&bit_mask::BAD_BIT_MASK),
|
||||
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
|
||||
LintId::of(&blacklisted_name::BLACKLISTED_NAME),
|
||||
@ -1525,6 +1535,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
|
||||
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
|
||||
LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
|
||||
LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES),
|
||||
LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
|
||||
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
|
||||
LintId::of(&swap::ALMOST_SWAPPED),
|
||||
@ -1565,6 +1576,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
|
||||
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
|
||||
LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
|
||||
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
||||
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
|
||||
LintId::of(&unused_unit::UNUSED_UNIT),
|
||||
@ -1749,6 +1761,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&reference::DEREF_ADDROF),
|
||||
LintId::of(&reference::REF_IN_DEREF),
|
||||
LintId::of(&repeat_once::REPEAT_ONCE),
|
||||
LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES),
|
||||
LintId::of(&swap::MANUAL_SWAP),
|
||||
LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
|
||||
LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),
|
||||
@ -1767,6 +1780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&types::UNNECESSARY_CAST),
|
||||
LintId::of(&types::VEC_BOX),
|
||||
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
|
||||
LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
|
||||
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
|
||||
LintId::of(&useless_conversion::USELESS_CONVERSION),
|
||||
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
|
||||
@ -1779,8 +1793,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&attrs::DEPRECATED_SEMVER),
|
||||
LintId::of(&attrs::MISMATCHED_TARGET_OS),
|
||||
LintId::of(&attrs::USELESS_ATTRIBUTE),
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||
LintId::of(&bit_mask::BAD_BIT_MASK),
|
||||
LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK),
|
||||
LintId::of(&booleans::LOGIC_BUG),
|
||||
|
@ -4,10 +4,10 @@ use crate::utils::sugg::Sugg;
|
||||
use crate::utils::usage::{is_unused, mutated_variables};
|
||||
use crate::utils::{
|
||||
contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
|
||||
indent_of, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment,
|
||||
match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet,
|
||||
snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
|
||||
span_lint_and_then, sugg, SpanlessEq,
|
||||
indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item,
|
||||
last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path,
|
||||
snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help,
|
||||
span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
@ -543,17 +543,15 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
// (also matches an explicit "match" instead of "if let")
|
||||
// (even if the "match" or "if let" is used for declaration)
|
||||
if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind {
|
||||
// also check for empty `loop {}` statements
|
||||
// TODO(issue #6161): Enable for no_std crates (outside of #[panic_handler])
|
||||
if block.stmts.is_empty() && block.expr.is_none() && !is_no_std_crate(cx.tcx.hir().krate()) {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
EMPTY_LOOP,
|
||||
expr.span,
|
||||
"empty `loop {}` wastes CPU cycles",
|
||||
None,
|
||||
"You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.",
|
||||
);
|
||||
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
|
||||
if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
|
||||
let msg = "empty `loop {}` wastes CPU cycles";
|
||||
let help = if is_no_std_crate(cx.tcx.hir().krate()) {
|
||||
"you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body"
|
||||
} else {
|
||||
"you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body"
|
||||
};
|
||||
span_lint_and_help(cx, EMPTY_LOOP, expr.span, msg, None, help);
|
||||
}
|
||||
|
||||
// extract the expression from the first statement (if any) in a block
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::utils::paths::FUTURE_FROM_GENERATOR;
|
||||
use crate::utils::{match_function_call, snippet_block, snippet_opt, span_lint_and_then};
|
||||
use crate::utils::{match_function_call, position_before_rarrow, snippet_block, snippet_opt, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
|
||||
|diag| {
|
||||
if_chain! {
|
||||
if let Some(header_snip) = snippet_opt(cx, header_span);
|
||||
if let Some(ret_pos) = header_snip.rfind("->");
|
||||
if let Some(ret_pos) = position_before_rarrow(header_snip.clone());
|
||||
if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
|
||||
then {
|
||||
let help = format!("make the function `async` and {}", ret_sugg);
|
||||
@ -194,7 +194,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str,
|
||||
},
|
||||
_ => {
|
||||
let sugg = "return the output of the future directly";
|
||||
snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip)))
|
||||
snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,15 @@ use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
|
||||
/// `iterator.cloned()` instead
|
||||
/// **What it does:** Checks for usage of `map(|x| x.clone())` or
|
||||
/// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
|
||||
/// and suggests `cloned()` or `copied()` instead
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely
|
||||
///
|
||||
@ -75,14 +77,19 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
|
||||
}
|
||||
}
|
||||
},
|
||||
hir::ExprKind::MethodCall(ref method, _, ref obj, _) => {
|
||||
if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone"
|
||||
&& match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
|
||||
|
||||
let obj_ty = cx.typeck_results().expr_ty(&obj[0]);
|
||||
if let ty::Ref(_, ty, _) = obj_ty.kind() {
|
||||
let copy = is_copy(cx, ty);
|
||||
lint(cx, e.span, args[0].span, copy);
|
||||
hir::ExprKind::MethodCall(ref method, _, [obj], _) => if_chain! {
|
||||
if ident_eq(name, obj) && method.ident.name == sym::clone;
|
||||
if match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT);
|
||||
// no autoderefs
|
||||
if !cx.typeck_results().expr_adjustments(obj).iter()
|
||||
.any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
|
||||
then {
|
||||
let obj_ty = cx.typeck_results().expr_ty(obj);
|
||||
if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
|
||||
if matches!(mutability, Mutability::Not) {
|
||||
let copy = is_copy(cx, ty);
|
||||
lint(cx, e.span, args[0].span, copy);
|
||||
}
|
||||
} else {
|
||||
lint_needless_cloning(cx, e.span, args[0].span);
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
use super::{contains_return, BIND_INSTEAD_OF_MAP};
|
||||
use crate::utils::{
|
||||
in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet,
|
||||
snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then,
|
||||
snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_span::Span;
|
||||
|
||||
pub(crate) struct OptionAndThenSome;
|
||||
@ -193,124 +191,3 @@ pub(crate) trait BindInsteadOfMap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// returns `true` if expr contains match expr desugared from try
|
||||
fn contains_try(expr: &hir::Expr<'_>) -> bool {
|
||||
struct TryFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl<'hir> intravisit::Visitor<'hir> for TryFinder {
|
||||
type Map = Map<'hir>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
|
||||
if self.found {
|
||||
return;
|
||||
}
|
||||
match expr.kind {
|
||||
hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true,
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = TryFinder { found: false };
|
||||
visitor.visit_expr(expr);
|
||||
visitor.found
|
||||
}
|
||||
|
||||
fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
|
||||
where
|
||||
F: FnMut(&'hir hir::Expr<'hir>) -> bool,
|
||||
{
|
||||
struct RetFinder<F> {
|
||||
in_stmt: bool,
|
||||
failed: bool,
|
||||
cb: F,
|
||||
}
|
||||
|
||||
struct WithStmtGuarg<'a, F> {
|
||||
val: &'a mut RetFinder<F>,
|
||||
prev_in_stmt: bool,
|
||||
}
|
||||
|
||||
impl<F> RetFinder<F> {
|
||||
fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
|
||||
let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
|
||||
WithStmtGuarg {
|
||||
val: self,
|
||||
prev_in_stmt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
|
||||
type Target = RetFinder<F>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Drop for WithStmtGuarg<'_, F> {
|
||||
fn drop(&mut self) {
|
||||
self.val.in_stmt = self.prev_in_stmt;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
|
||||
type Map = Map<'hir>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
|
||||
intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
|
||||
if self.failed {
|
||||
return;
|
||||
}
|
||||
if self.in_stmt {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
} else {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Match(cond, arms, _) => {
|
||||
self.inside_stmt(true).visit_expr(cond);
|
||||
for arm in arms {
|
||||
self.visit_expr(arm.body);
|
||||
}
|
||||
},
|
||||
hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr),
|
||||
hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
|
||||
_ => self.failed |= !(self.cb)(expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
!contains_try(expr) && {
|
||||
let mut ret_finder = RetFinder {
|
||||
in_stmt: false,
|
||||
failed: false,
|
||||
cb: callback,
|
||||
};
|
||||
ret_finder.visit_expr(expr);
|
||||
!ret_finder.failed
|
||||
}
|
||||
}
|
||||
|
@ -515,11 +515,11 @@ declare_clippy_lint! {
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for an iterator search (such as `find()`,
|
||||
/// **What it does:** Checks for an iterator or string search (such as `find()`,
|
||||
/// `position()`, or `rposition()`) followed by a call to `is_some()`.
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as
|
||||
/// `_.any(_)`.
|
||||
/// `_.any(_)` or `_.contains(_)`.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
@ -535,7 +535,7 @@ declare_clippy_lint! {
|
||||
/// ```
|
||||
pub SEARCH_IS_SOME,
|
||||
complexity,
|
||||
"using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
|
||||
"using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -1351,7 +1351,7 @@ declare_clippy_lint! {
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.map(_).collect::<Result<(),_>()`.
|
||||
/// **What it does:** Checks for usage of `_.map(_).collect::<Result<(), _>()`.
|
||||
///
|
||||
/// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic.
|
||||
///
|
||||
@ -1797,12 +1797,20 @@ fn lint_or_fun_call<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
name: &str,
|
||||
method_span: Span,
|
||||
fun_span: Span,
|
||||
self_expr: &hir::Expr<'_>,
|
||||
arg: &'tcx hir::Expr<'_>,
|
||||
or_has_args: bool,
|
||||
span: Span,
|
||||
// None if lambda is required
|
||||
fun_span: Option<Span>,
|
||||
) {
|
||||
// (path, fn_has_argument, methods, suffix)
|
||||
static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
|
||||
(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
|
||||
(&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
|
||||
(&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
|
||||
(&paths::RESULT, true, &["or", "unwrap_or"], "else"),
|
||||
];
|
||||
|
||||
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
|
||||
if path.ident.as_str() == "len" {
|
||||
let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
|
||||
@ -1818,16 +1826,8 @@ fn lint_or_fun_call<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
// (path, fn_has_argument, methods, suffix)
|
||||
let know_types: &[(&[_], _, &[_], _)] = &[
|
||||
(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
|
||||
(&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
|
||||
(&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
|
||||
(&paths::RESULT, true, &["or", "unwrap_or"], "else"),
|
||||
];
|
||||
|
||||
if_chain! {
|
||||
if know_types.iter().any(|k| k.2.contains(&name));
|
||||
if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
|
||||
|
||||
if is_lazyness_candidate(cx, arg);
|
||||
if !contains_return(&arg);
|
||||
@ -1835,15 +1835,23 @@ fn lint_or_fun_call<'tcx>(
|
||||
let self_ty = cx.typeck_results().expr_ty(self_expr);
|
||||
|
||||
if let Some(&(_, fn_has_arguments, poss, suffix)) =
|
||||
know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
|
||||
KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0));
|
||||
|
||||
if poss.contains(&name);
|
||||
|
||||
then {
|
||||
let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
|
||||
(true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
|
||||
(false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
|
||||
(false, true) => snippet_with_macro_callsite(cx, fun_span, ".."),
|
||||
let sugg: Cow<'_, str> = {
|
||||
let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
|
||||
(false, Some(fun_span)) => (fun_span, false),
|
||||
_ => (arg.span, true),
|
||||
};
|
||||
let snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
|
||||
if use_lambda {
|
||||
let l_arg = if fn_has_arguments { "_" } else { "" };
|
||||
format!("|{}| {}", l_arg, snippet).into()
|
||||
} else {
|
||||
snippet
|
||||
}
|
||||
};
|
||||
let span_replace_word = method_span.with_hi(span.hi());
|
||||
span_lint_and_sugg(
|
||||
@ -1864,28 +1872,13 @@ fn lint_or_fun_call<'tcx>(
|
||||
hir::ExprKind::Call(ref fun, ref or_args) => {
|
||||
let or_has_args = !or_args.is_empty();
|
||||
if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
|
||||
check_general_case(
|
||||
cx,
|
||||
name,
|
||||
method_span,
|
||||
fun.span,
|
||||
&args[0],
|
||||
&args[1],
|
||||
or_has_args,
|
||||
expr.span,
|
||||
);
|
||||
let fun_span = if or_has_args { None } else { Some(fun.span) };
|
||||
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span);
|
||||
}
|
||||
},
|
||||
hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case(
|
||||
cx,
|
||||
name,
|
||||
method_span,
|
||||
span,
|
||||
&args[0],
|
||||
&args[1],
|
||||
!or_args.is_empty(),
|
||||
expr.span,
|
||||
),
|
||||
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
|
||||
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
@ -3048,6 +3041,7 @@ fn lint_flat_map_identity<'tcx>(
|
||||
}
|
||||
|
||||
/// lint searching an Iterator followed by `is_some()`
|
||||
/// or calling `find()` on a string followed by `is_some()`
|
||||
fn lint_search_is_some<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
@ -3059,10 +3053,10 @@ fn lint_search_is_some<'tcx>(
|
||||
// lint if caller of search is an Iterator
|
||||
if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
|
||||
let msg = format!(
|
||||
"called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
|
||||
expressed by calling `any()`.",
|
||||
"called `is_some()` after searching an `Iterator` with `{}`",
|
||||
search_method
|
||||
);
|
||||
let hint = "this is more succinctly expressed by calling `any()`";
|
||||
let search_snippet = snippet(cx, search_args[1].span, "..");
|
||||
if search_snippet.lines().count() <= 1 {
|
||||
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
|
||||
@ -3090,7 +3084,7 @@ fn lint_search_is_some<'tcx>(
|
||||
SEARCH_IS_SOME,
|
||||
method_span.with_hi(expr.span.hi()),
|
||||
&msg,
|
||||
"try this",
|
||||
"use `any()` instead",
|
||||
format!(
|
||||
"any({})",
|
||||
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
|
||||
@ -3098,7 +3092,36 @@ fn lint_search_is_some<'tcx>(
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
|
||||
span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint);
|
||||
}
|
||||
}
|
||||
// lint if `find()` is called by `String` or `&str`
|
||||
else if search_method == "find" {
|
||||
let is_string_or_str_slice = |e| {
|
||||
let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
|
||||
if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
|
||||
true
|
||||
} else {
|
||||
*self_ty.kind() == ty::Str
|
||||
}
|
||||
};
|
||||
if_chain! {
|
||||
if is_string_or_str_slice(&search_args[0]);
|
||||
if is_string_or_str_slice(&search_args[1]);
|
||||
then {
|
||||
let msg = "called `is_some()` after calling `find()` on a string";
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
SEARCH_IS_SOME,
|
||||
method_span.with_hi(expr.span.hi()),
|
||||
msg,
|
||||
"use `contains()` instead",
|
||||
format!("contains({})", find_arg),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3901,21 +3924,24 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
|
||||
|
||||
let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap();
|
||||
let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap();
|
||||
if_chain! {
|
||||
if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR);
|
||||
if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR);
|
||||
|
||||
if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) {
|
||||
// `expr` implements `FromIterator` trait
|
||||
let iter_expr = snippet(cx, args[0].span, "..");
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
FROM_ITER_INSTEAD_OF_COLLECT,
|
||||
expr.span,
|
||||
"usage of `FromIterator::from_iter`",
|
||||
"use `.collect()` instead of `::from_iter()`",
|
||||
format!("{}.collect()", iter_expr),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]);
|
||||
then {
|
||||
// `expr` implements `FromIterator` trait
|
||||
let iter_expr = snippet(cx, args[0].span, "..");
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
FROM_ITER_INSTEAD_OF_COLLECT,
|
||||
expr.span,
|
||||
"usage of `FromIterator::from_iter`",
|
||||
"use `.collect()` instead of `::from_iter()`",
|
||||
format!("{}.collect()", iter_expr),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,17 @@ pub(super) fn lint<'tcx>(
|
||||
} else {
|
||||
"unnecessary closure used to substitute value for `Result::Err`"
|
||||
};
|
||||
let applicability = if body
|
||||
.params
|
||||
.iter()
|
||||
// bindings are checked to be unused above
|
||||
.all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild))
|
||||
{
|
||||
Applicability::MachineApplicable
|
||||
} else {
|
||||
// replacing the lambda may break type inference
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
@ -46,7 +57,7 @@ pub(super) fn lint<'tcx>(
|
||||
simplify_using,
|
||||
snippet(cx, body_expr.span, ".."),
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -89,11 +89,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::
|
||||
for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) {
|
||||
check_ty(cx, hir_ty.span, ty);
|
||||
}
|
||||
check_ty(
|
||||
cx,
|
||||
decl.output.span(),
|
||||
cx.tcx.erase_late_bound_regions(fn_sig.output()),
|
||||
);
|
||||
check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
|
||||
}
|
||||
|
||||
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
|
||||
|
@ -5,11 +5,15 @@
|
||||
use std::ptr;
|
||||
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{
|
||||
BodyId, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
|
||||
};
|
||||
use rustc_infer::traits::specialization_graph;
|
||||
use rustc_lint::{LateContext, LateLintPass, Lint};
|
||||
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_middle::ty::{AssocKind, Ty};
|
||||
use rustc_middle::ty::{self, AssocKind, Const, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{InnerSpan, Span, DUMMY_SP};
|
||||
use rustc_typeck::hir_ty_to_ty;
|
||||
@ -36,14 +40,17 @@ declare_clippy_lint! {
|
||||
/// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
|
||||
/// and this lint should be suppressed.
|
||||
///
|
||||
/// When an enum has variants with interior mutability, use of its non interior mutable
|
||||
/// variants can generate false positives. See issue
|
||||
/// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
|
||||
/// Even though the lint avoids triggering on a constant whose type has enums that have variants
|
||||
/// with interior mutability, and its value uses non interior mutable variants (see
|
||||
/// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
|
||||
/// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
|
||||
/// it complains about associated constants without default values only based on its types;
|
||||
/// which might not be preferable.
|
||||
/// There're other enums plus associated constants cases that the lint cannot handle.
|
||||
///
|
||||
/// Types that have underlying or potential interior mutability trigger the lint whether
|
||||
/// the interior mutable field is used or not. See issues
|
||||
/// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
|
||||
/// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
@ -105,6 +112,79 @@ declare_clippy_lint! {
|
||||
"referencing `const` with interior mutability"
|
||||
}
|
||||
|
||||
fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
// Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
|
||||
// making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
|
||||
// 'unfrozen'. However, this code causes a false negative in which
|
||||
// a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell<T>`.
|
||||
// Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
|
||||
// since it works when a pointer indirection involves (`Cell<*const T>`).
|
||||
// Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
|
||||
// but I'm not sure whether it's a decent way, if possible.
|
||||
cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
|
||||
}
|
||||
|
||||
fn is_value_unfrozen_raw<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
result: Result<ConstValue<'tcx>, ErrorHandled>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool {
|
||||
match val.ty.kind() {
|
||||
// the fact that we have to dig into every structs to search enums
|
||||
// leads us to the point checking `UnsafeCell` directly is the only option.
|
||||
ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true,
|
||||
ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
|
||||
let val = cx.tcx.destructure_const(cx.param_env.and(val));
|
||||
val.fields.iter().any(|field| inner(cx, field))
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
result.map_or_else(
|
||||
|err| {
|
||||
// Consider `TooGeneric` cases as being unfrozen.
|
||||
// This causes a false positive where an assoc const whose type is unfrozen
|
||||
// have a value that is a frozen variant with a generic param (an example is
|
||||
// `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
|
||||
// However, it prevents a number of false negatives that is, I think, important:
|
||||
// 1. assoc consts in trait defs referring to consts of themselves
|
||||
// (an example is `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
|
||||
// 2. a path expr referring to assoc consts whose type is doesn't have
|
||||
// any frozen variants in trait defs (i.e. without substitute for `Self`).
|
||||
// (e.g. borrowing `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
|
||||
// 3. similar to the false positive above;
|
||||
// but the value is an unfrozen variant, or the type has no enums. (An example is
|
||||
// `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT`
|
||||
// and `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
|
||||
// One might be able to prevent these FNs correctly, and replace this with `false`;
|
||||
// e.g. implementing `has_frozen_variant` described above, and not running this function
|
||||
// when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
|
||||
// case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
|
||||
// similar to 2., but with the a frozen variant) (e.g. borrowing
|
||||
// `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
|
||||
// I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
|
||||
err == ErrorHandled::TooGeneric
|
||||
},
|
||||
|val| inner(cx, Const::from_value(cx.tcx, val, ty)),
|
||||
)
|
||||
}
|
||||
|
||||
fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
|
||||
let result = cx.tcx.const_eval_poly(body_id.hir_id.owner.to_def_id());
|
||||
is_value_unfrozen_raw(cx, result, ty)
|
||||
}
|
||||
|
||||
fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
|
||||
let substs = cx.typeck_results().node_substs(hir_id);
|
||||
|
||||
let result = cx
|
||||
.tcx
|
||||
.const_eval_resolve(cx.param_env, ty::WithOptConstParam::unknown(def_id), substs, None, None);
|
||||
is_value_unfrozen_raw(cx, result, ty)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Source {
|
||||
Item { item: Span },
|
||||
@ -130,19 +210,7 @@ impl Source {
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) {
|
||||
// Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
|
||||
// making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
|
||||
// 'unfrozen'. However, this code causes a false negative in which
|
||||
// a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell<T>`.
|
||||
// Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
|
||||
// since it works when a pointer indirection involves (`Cell<*const T>`).
|
||||
// Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
|
||||
// but I'm not sure whether it's a decent way, if possible.
|
||||
if cx.tcx.layout_of(cx.param_env.and(ty)).is_err() || ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) {
|
||||
return;
|
||||
}
|
||||
|
||||
fn lint(cx: &LateContext<'_>, source: Source) {
|
||||
let (lint, msg, span) = source.lint();
|
||||
span_lint_and_then(cx, lint, span, msg, |diag| {
|
||||
if span.from_expansion() {
|
||||
@ -165,24 +233,44 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
|
||||
if let ItemKind::Const(hir_ty, ..) = &it.kind {
|
||||
if let ItemKind::Const(hir_ty, body_id) = it.kind {
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||
verify_ty_bound(cx, ty, Source::Item { item: it.span });
|
||||
|
||||
if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) {
|
||||
lint(cx, Source::Item { item: it.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
|
||||
if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind {
|
||||
if let TraitItemKind::Const(hir_ty, body_id_opt) = &trait_item.kind {
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||
|
||||
// Normalize assoc types because ones originated from generic params
|
||||
// bounded other traits could have their bound.
|
||||
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
|
||||
verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span });
|
||||
if is_unfrozen(cx, normalized)
|
||||
// When there's no default value, lint it only according to its type;
|
||||
// in other words, lint consts whose value *could* be unfrozen, not definitely is.
|
||||
// This feels inconsistent with how the lint treats generic types,
|
||||
// which avoids linting types which potentially become unfrozen.
|
||||
// One could check whether a unfrozen type have a *frozen variant*
|
||||
// (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`),
|
||||
// and do the same as the case of generic types at impl items.
|
||||
// Note that it isn't sufficient to check if it has an enum
|
||||
// since all of that enum's variants can be unfrozen:
|
||||
// i.e. having an enum doesn't necessary mean a type has a frozen variant.
|
||||
// And, implementing it isn't a trivial task; it'll probably end up
|
||||
// re-implementing the trait predicate evaluation specific to `Freeze`.
|
||||
&& body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized))
|
||||
{
|
||||
lint(cx, Source::Assoc { item: trait_item.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
|
||||
if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind {
|
||||
if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
|
||||
let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id);
|
||||
let item = cx.tcx.hir().expect_item(item_hir_id);
|
||||
|
||||
@ -209,16 +297,23 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
||||
),
|
||||
))
|
||||
.is_err();
|
||||
// If there were a function like `has_frozen_variant` described above,
|
||||
// we should use here as a frozen variant is a potential to be frozen
|
||||
// similar to unknown layouts.
|
||||
// e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
|
||||
then {
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
|
||||
verify_ty_bound(
|
||||
cx,
|
||||
normalized,
|
||||
Source::Assoc {
|
||||
item: impl_item.span,
|
||||
},
|
||||
);
|
||||
if is_unfrozen(cx, normalized)
|
||||
&& is_value_unfrozen_poly(cx, *body_id, normalized)
|
||||
{
|
||||
lint(
|
||||
cx,
|
||||
Source::Assoc {
|
||||
item: impl_item.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -226,7 +321,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||
// Normalize assoc types originated from generic params.
|
||||
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
|
||||
verify_ty_bound(cx, normalized, Source::Assoc { item: impl_item.span });
|
||||
|
||||
if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) {
|
||||
lint(cx, Source::Assoc { item: impl_item.span });
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
@ -241,8 +339,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
||||
}
|
||||
|
||||
// Make sure it is a const item.
|
||||
match qpath_res(cx, qpath, expr.hir_id) {
|
||||
Res::Def(DefKind::Const | DefKind::AssocConst, _) => {},
|
||||
let item_def_id = match qpath_res(cx, qpath, expr.hir_id) {
|
||||
Res::Def(DefKind::Const | DefKind::AssocConst, did) => did,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
@ -319,7 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
||||
cx.typeck_results().expr_ty(dereferenced_expr)
|
||||
};
|
||||
|
||||
verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
|
||||
if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) {
|
||||
lint(cx, Source::Expr { expr: expr.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
use crate::utils::{span_lint, span_lint_and_then};
|
||||
use rustc_ast::ast::{
|
||||
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
|
||||
};
|
||||
use rustc_ast::ast::{Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind};
|
||||
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
@ -73,7 +73,7 @@ declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANI
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let Some(_) = match_panic_call(cx, expr) {
|
||||
if match_panic_call(cx, expr).is_some() {
|
||||
let span = get_outer_span(expr);
|
||||
if is_expn_of(expr.span, "unimplemented").is_some() {
|
||||
span_lint(
|
||||
|
@ -222,13 +222,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
|
||||
let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
|
||||
let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
|
||||
let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
|
||||
let space = if lo.ends_with('.') { " " } else { "" };
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_RANGE_CONTAINS,
|
||||
span,
|
||||
&format!("manual `{}::contains` implementation", range_type),
|
||||
"use",
|
||||
format!("({}{}{}).contains(&{})", lo, range_op, hi, name),
|
||||
format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
|
||||
applicability,
|
||||
);
|
||||
} else if !combine_and && ord == Some(lord) {
|
||||
@ -251,13 +252,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
|
||||
let name = snippet_with_applicability(cx, name_span, "_", &mut applicability);
|
||||
let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
|
||||
let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
|
||||
let space = if lo.ends_with('.') { " " } else { "" };
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_RANGE_CONTAINS,
|
||||
span,
|
||||
&format!("manual `!{}::contains` implementation", range_type),
|
||||
"use",
|
||||
format!("!({}{}{}).contains(&{})", lo, range_op, hi, name),
|
||||
format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
@ -320,11 +320,11 @@ fn find_stmt_assigns_to<'tcx>(
|
||||
|
||||
match (by_ref, &*rvalue) {
|
||||
(true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => {
|
||||
base_local_and_movability(cx, mir, *place)
|
||||
Some(base_local_and_movability(cx, mir, *place))
|
||||
},
|
||||
(false, mir::Rvalue::Ref(_, _, place)) => {
|
||||
if let [mir::ProjectionElem::Deref] = place.as_ref().projection {
|
||||
base_local_and_movability(cx, mir, *place)
|
||||
Some(base_local_and_movability(cx, mir, *place))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -341,7 +341,7 @@ fn base_local_and_movability<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
mir: &mir::Body<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
) -> Option<(mir::Local, CannotMoveOut)> {
|
||||
) -> (mir::Local, CannotMoveOut) {
|
||||
use rustc_middle::mir::PlaceRef;
|
||||
|
||||
// Dereference. You cannot move things out from a borrowed value.
|
||||
@ -362,7 +362,7 @@ fn base_local_and_movability<'tcx>(
|
||||
&& !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
|
||||
}
|
||||
|
||||
Some((local, deref || field || slice))
|
||||
(local, deref || field || slice)
|
||||
}
|
||||
|
||||
struct LocalUseVisitor {
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
|
||||
use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Expr, ExprKind, UnOp};
|
||||
use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::BytePos;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `*&` and `*&mut` in expressions.
|
||||
@ -42,19 +43,55 @@ impl EarlyLintPass for DerefAddrOf {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
|
||||
if_chain! {
|
||||
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
|
||||
if let ExprKind::AddrOf(_, _, ref addrof_target) = without_parens(deref_target).kind;
|
||||
if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
|
||||
if !in_macro(addrof_target.span);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DEREF_ADDROF,
|
||||
e.span,
|
||||
"immediately dereferencing a reference",
|
||||
"try this",
|
||||
format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)),
|
||||
applicability,
|
||||
);
|
||||
let sugg = if e.span.from_expansion() {
|
||||
if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) {
|
||||
// Remove leading whitespace from the given span
|
||||
// e.g: ` $visitor` turns into `$visitor`
|
||||
let trim_leading_whitespaces = |span| {
|
||||
snippet_opt(cx, span).and_then(|snip| {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
snip.find(|c: char| !c.is_whitespace()).map(|pos| {
|
||||
span.lo() + BytePos(pos as u32)
|
||||
})
|
||||
}).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace))
|
||||
};
|
||||
|
||||
let mut generate_snippet = |pattern: &str| {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
macro_source.rfind(pattern).map(|pattern_pos| {
|
||||
let rpos = pattern_pos + pattern.len();
|
||||
let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
|
||||
let span = trim_leading_whitespaces(span_after_ref);
|
||||
snippet_with_applicability(cx, span, "_", &mut applicability)
|
||||
})
|
||||
};
|
||||
|
||||
if *mutability == Mutability::Mut {
|
||||
generate_snippet("mut")
|
||||
} else {
|
||||
generate_snippet("&")
|
||||
}
|
||||
} else {
|
||||
Some(snippet_with_applicability(cx, e.span, "_", &mut applicability))
|
||||
}
|
||||
} else {
|
||||
Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability))
|
||||
};
|
||||
if let Some(sugg) = sugg {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DEREF_ADDROF,
|
||||
e.span,
|
||||
"immediately dereferencing a reference",
|
||||
"try this",
|
||||
sugg.to_string(),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use std::convert::TryFrom;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks [regex](https://crates.io/crates/regex) creation
|
||||
/// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct
|
||||
/// (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct
|
||||
/// regex syntax.
|
||||
///
|
||||
/// **Why is this bad?** This will lead to a runtime panic.
|
||||
@ -29,7 +29,7 @@ declare_clippy_lint! {
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex)
|
||||
/// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`).
|
||||
/// creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`).
|
||||
///
|
||||
/// **Why is this bad?** Matching the regex can likely be replaced by `==` or
|
||||
/// `str::starts_with`, `str::ends_with` or `std::contains` or other `str`
|
||||
|
@ -1,5 +1,5 @@
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -9,7 +9,10 @@ use rustc_span::sym;
|
||||
use if_chain::if_chain;
|
||||
|
||||
use crate::utils::SpanlessEq;
|
||||
use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg};
|
||||
use crate::utils::{
|
||||
get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint,
|
||||
span_lint_and_sugg,
|
||||
};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for string appends of the form `x = x + y` (without
|
||||
@ -174,16 +177,75 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Check if the string is transformed to byte array and casted back to string.
|
||||
///
|
||||
/// **Why is this bad?** It's unnecessary, the string can be used directly.
|
||||
///
|
||||
/// **Known problems:** None
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
|
||||
/// ```
|
||||
/// could be written as
|
||||
/// ```rust
|
||||
/// let _ = &"Hello World!"[6..11];
|
||||
/// ```
|
||||
pub STRING_FROM_UTF8_AS_BYTES,
|
||||
complexity,
|
||||
"casting string slices to byte slices and back"
|
||||
}
|
||||
|
||||
// Max length a b"foo" string can take
|
||||
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;
|
||||
|
||||
declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);
|
||||
declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
use crate::utils::{snippet, snippet_with_applicability};
|
||||
use rustc_ast::LitKind;
|
||||
|
||||
if_chain! {
|
||||
// Find std::str::converts::from_utf8
|
||||
if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8);
|
||||
|
||||
// Find string::as_bytes
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref args) = args[0].kind;
|
||||
if let ExprKind::Index(ref left, ref right) = args.kind;
|
||||
let (method_names, expressions, _) = method_calls(left, 1);
|
||||
if method_names.len() == 1;
|
||||
if expressions.len() == 1;
|
||||
if expressions[0].len() == 1;
|
||||
if method_names[0] == sym!(as_bytes);
|
||||
|
||||
// Check for slicer
|
||||
if let ExprKind::Struct(ref path, _, _) = right.kind;
|
||||
if let QPath::LangItem(LangItem::Range, _) = path;
|
||||
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let string_expression = &expressions[0][0];
|
||||
|
||||
let snippet_app = snippet_with_applicability(
|
||||
cx,
|
||||
string_expression.span, "..",
|
||||
&mut applicability,
|
||||
);
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_FROM_UTF8_AS_BYTES,
|
||||
e.span,
|
||||
"calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
|
||||
"try",
|
||||
format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")),
|
||||
applicability
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(path, _, args, _) = &e.kind;
|
||||
if path.ident.name == sym!(as_bytes);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::utils::{
|
||||
is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
|
||||
span_lint_and_sugg,
|
||||
differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet,
|
||||
snippet_with_macro_callsite, span_lint_and_sugg,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
@ -92,8 +92,11 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
|
||||
};
|
||||
|
||||
let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
|
||||
let differing_contexts = differing_macro_contexts(expr.span, err_arg.span);
|
||||
|
||||
let origin_snippet = if err_arg.span.from_expansion() {
|
||||
let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts {
|
||||
snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_")
|
||||
} else if err_arg.span.from_expansion() && !in_macro(expr.span) {
|
||||
snippet_with_macro_callsite(cx, err_arg.span, "_")
|
||||
} else {
|
||||
snippet(cx, err_arg.span, "_")
|
||||
|
@ -553,7 +553,7 @@ impl Types {
|
||||
hir_ty.span,
|
||||
"`Vec<T>` is already on the heap, the boxing is unnecessary.",
|
||||
"try",
|
||||
format!("Vec<{}>", ty_ty),
|
||||
format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return; // don't recurse into the type
|
||||
|
@ -24,7 +24,7 @@ declare_clippy_lint! {
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// let mut twins = vec!((1,1), (2,2));
|
||||
/// let mut twins = vec!((1, 1), (2, 2));
|
||||
/// twins.sort_by_key(|x| { x.1; });
|
||||
/// ```
|
||||
pub UNIT_RETURN_EXPECTING_ORD,
|
||||
|
143
clippy_lints/src/unnecessary_wraps.rs
Normal file
143
clippy_lints/src/unnecessary_wraps.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use crate::utils::{
|
||||
in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
|
||||
visitors::find_all_ret_expressions,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for private functions that only return `Ok` or `Some`.
|
||||
///
|
||||
/// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
|
||||
///
|
||||
/// **Known problems:** Since this lint changes function type signature, you may need to
|
||||
/// adjust some code at callee side.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
|
||||
/// if a && b {
|
||||
/// return Some(50);
|
||||
/// }
|
||||
/// if a {
|
||||
/// Some(0)
|
||||
/// } else {
|
||||
/// Some(10)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// fn get_cool_number(a: bool, b: bool) -> i32 {
|
||||
/// if a && b {
|
||||
/// return 50;
|
||||
/// }
|
||||
/// if a {
|
||||
/// 0
|
||||
/// } else {
|
||||
/// 10
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub UNNECESSARY_WRAPS,
|
||||
complexity,
|
||||
"functions that only return `Ok` or `Some`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
fn_kind: FnKind<'tcx>,
|
||||
fn_decl: &FnDecl<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
span: Span,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
match fn_kind {
|
||||
FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
|
||||
if visibility.node.is_pub() {
|
||||
return;
|
||||
}
|
||||
},
|
||||
FnKind::Closure(..) => return,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
|
||||
if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
|
||||
("Option", &paths::OPTION_SOME)
|
||||
} else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
|
||||
("Result", &paths::RESULT_OK)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut suggs = Vec::new();
|
||||
let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
|
||||
if_chain! {
|
||||
if !in_macro(ret_expr.span);
|
||||
if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
|
||||
if let ExprKind::Path(ref qpath) = func.kind;
|
||||
if match_qpath(qpath, path);
|
||||
if args.len() == 1;
|
||||
then {
|
||||
suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if can_sugg && !suggs.is_empty() {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNNECESSARY_WRAPS,
|
||||
span,
|
||||
format!(
|
||||
"this function's return value is unnecessarily wrapped by `{}`",
|
||||
return_type
|
||||
)
|
||||
.as_str(),
|
||||
|diag| {
|
||||
let inner_ty = return_ty(cx, hir_id)
|
||||
.walk()
|
||||
.skip(1) // skip `std::option::Option` or `std::result::Result`
|
||||
.take(1) // take the first outermost inner type
|
||||
.filter_map(|inner| match inner.unpack() {
|
||||
GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
|
||||
_ => None,
|
||||
});
|
||||
inner_ty.for_each(|inner_ty| {
|
||||
diag.span_suggestion(
|
||||
fn_decl.output.span(),
|
||||
format!("remove `{}` from the return type...", return_type).as_str(),
|
||||
inner_ty,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
});
|
||||
diag.multipart_suggestion(
|
||||
"...and change the returning expressions",
|
||||
suggs,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::BytePos;
|
||||
|
||||
use crate::utils::span_lint_and_sugg;
|
||||
use crate::utils::{position_before_rarrow, span_lint_and_sugg};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for unit (`()`) expressions that can be removed.
|
||||
@ -120,26 +120,13 @@ fn is_unit_expr(expr: &ast::Expr) -> bool {
|
||||
|
||||
fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
|
||||
let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
|
||||
fn_source
|
||||
.rfind("->")
|
||||
.map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
let mut rpos = rpos;
|
||||
let chars: Vec<char> = fn_source.chars().collect();
|
||||
while rpos > 1 {
|
||||
if let Some(c) = chars.get(rpos - 1) {
|
||||
if c.is_whitespace() {
|
||||
rpos -= 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
(
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
})
|
||||
position_before_rarrow(fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
(
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
(ty.span, Applicability::MaybeIncorrect)
|
||||
};
|
||||
|
@ -12,8 +12,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls
|
||||
/// that useless converts to the same type as caller.
|
||||
/// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls
|
||||
/// which uselessly convert to the same type.
|
||||
///
|
||||
/// **Why is this bad?** Redundant code.
|
||||
///
|
||||
@ -31,7 +31,7 @@ declare_clippy_lint! {
|
||||
/// ```
|
||||
pub USELESS_CONVERSION,
|
||||
complexity,
|
||||
"calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type"
|
||||
"calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -110,8 +110,7 @@ pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
|
||||
pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
|
||||
match (l, r) {
|
||||
(StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb),
|
||||
(StructRest::Rest(_), StructRest::Rest(_)) => true,
|
||||
(StructRest::None, StructRest::None) => true,
|
||||
(StructRest::Rest(_), StructRest::Rest(_)) | (StructRest::None, StructRest::None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
//! - or-fun-call
|
||||
//! - option-if-let-else
|
||||
|
||||
use crate::utils::is_ctor_or_promotable_const_function;
|
||||
use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
||||
use rustc_hir::intravisit;
|
||||
@ -96,6 +96,11 @@ fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, ex
|
||||
let call_found = match &expr.kind {
|
||||
// ignore enum and struct constructors
|
||||
ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
|
||||
ExprKind::Index(obj, _) => {
|
||||
let ty = self.cx.typeck_results().expr_ty(obj);
|
||||
is_type_diagnostic_item(self.cx, ty, sym!(hashmap_type))
|
||||
|| match_type(self.cx, ty, &paths::BTREEMAP)
|
||||
},
|
||||
ExprKind::MethodCall(..) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
@ -21,6 +21,7 @@ pub mod ptr;
|
||||
pub mod qualify_min_const_fn;
|
||||
pub mod sugg;
|
||||
pub mod usage;
|
||||
pub mod visitors;
|
||||
|
||||
pub use self::attrs::*;
|
||||
pub use self::diagnostics::*;
|
||||
@ -364,6 +365,9 @@ pub fn implements_trait<'tcx>(
|
||||
return false;
|
||||
}
|
||||
let ty = cx.tcx.erase_regions(ty);
|
||||
if ty.has_escaping_bound_vars() {
|
||||
return false;
|
||||
}
|
||||
let ty_params = cx.tcx.mk_substs(ty_params.iter());
|
||||
cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
|
||||
}
|
||||
@ -468,6 +472,13 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
|
||||
.map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
|
||||
}
|
||||
|
||||
/// Returns `true` if the expression is in the program's `#[panic_handler]`.
|
||||
pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
let parent = cx.tcx.hir().get_parent_item(e.hir_id);
|
||||
let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
|
||||
Some(def_id) == cx.tcx.lang_items().panic_impl()
|
||||
}
|
||||
|
||||
/// Gets the name of the item the expression is in, if available.
|
||||
pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
|
||||
let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
|
||||
@ -659,6 +670,35 @@ pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
|
||||
snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
|
||||
}
|
||||
|
||||
/// Returns the positon just before rarrow
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// fn into(self) -> () {}
|
||||
/// ^
|
||||
/// // in case of unformatted code
|
||||
/// fn into2(self)-> () {}
|
||||
/// ^
|
||||
/// fn into3(self) -> () {}
|
||||
/// ^
|
||||
/// ```
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn position_before_rarrow(s: String) -> Option<usize> {
|
||||
s.rfind("->").map(|rpos| {
|
||||
let mut rpos = rpos;
|
||||
let chars: Vec<char> = s.chars().collect();
|
||||
while rpos > 1 {
|
||||
if let Some(c) = chars.get(rpos - 1) {
|
||||
if c.is_whitespace() {
|
||||
rpos -= 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
rpos
|
||||
})
|
||||
}
|
||||
|
||||
/// Extends the span to the beginning of the spans line, incl. whitespaces.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
|
@ -126,6 +126,7 @@ pub const STRING: [&str; 3] = ["alloc", "string", "String"];
|
||||
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
|
||||
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
|
||||
pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
|
||||
pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"];
|
||||
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
|
||||
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
|
||||
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
|
||||
|
125
clippy_lints/src/utils/visitors.rs
Normal file
125
clippy_lints/src/utils/visitors.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::hir::map::Map;
|
||||
|
||||
/// returns `true` if expr contains match expr desugared from try
|
||||
fn contains_try(expr: &hir::Expr<'_>) -> bool {
|
||||
struct TryFinder {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl<'hir> intravisit::Visitor<'hir> for TryFinder {
|
||||
type Map = Map<'hir>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
|
||||
if self.found {
|
||||
return;
|
||||
}
|
||||
match expr.kind {
|
||||
hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true,
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = TryFinder { found: false };
|
||||
visitor.visit_expr(expr);
|
||||
visitor.found
|
||||
}
|
||||
|
||||
pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
|
||||
where
|
||||
F: FnMut(&'hir hir::Expr<'hir>) -> bool,
|
||||
{
|
||||
struct RetFinder<F> {
|
||||
in_stmt: bool,
|
||||
failed: bool,
|
||||
cb: F,
|
||||
}
|
||||
|
||||
struct WithStmtGuarg<'a, F> {
|
||||
val: &'a mut RetFinder<F>,
|
||||
prev_in_stmt: bool,
|
||||
}
|
||||
|
||||
impl<F> RetFinder<F> {
|
||||
fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
|
||||
let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
|
||||
WithStmtGuarg {
|
||||
val: self,
|
||||
prev_in_stmt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
|
||||
type Target = RetFinder<F>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.val
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Drop for WithStmtGuarg<'_, F> {
|
||||
fn drop(&mut self) {
|
||||
self.val.in_stmt = self.prev_in_stmt;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
|
||||
type Map = Map<'hir>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
|
||||
intravisit::NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
|
||||
intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
|
||||
if self.failed {
|
||||
return;
|
||||
}
|
||||
if self.in_stmt {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
} else {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Match(cond, arms, _) => {
|
||||
self.inside_stmt(true).visit_expr(cond);
|
||||
for arm in arms {
|
||||
self.visit_expr(arm.body);
|
||||
}
|
||||
},
|
||||
hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr),
|
||||
hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
|
||||
_ => self.failed |= !(self.cb)(expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
!contains_try(expr) && {
|
||||
let mut ret_finder = RetFinder {
|
||||
in_stmt: false,
|
||||
failed: false,
|
||||
cb: callback,
|
||||
};
|
||||
ret_finder.visit_expr(expr);
|
||||
!ret_finder.failed
|
||||
}
|
||||
}
|
@ -29,8 +29,11 @@ bullet points might be helpful:
|
||||
* When writing the release notes for the **upcoming beta release**, you need to check
|
||||
out the Clippy commit of the current Rust `master`. [Link][rust_master_tools]
|
||||
* When writing the (forgotten) release notes for a **past stable release**, you
|
||||
need to select the Rust release tag from the dropdown and then check the
|
||||
commit of the Clippy directory:
|
||||
need to check out the Rust release tag of the stable release.
|
||||
[Link][rust_stable_tools]
|
||||
|
||||
Usually you want to wirte the changelog of the **upcoming stable release**. Make
|
||||
sure though, that `beta` was already branched in the Rust repository.
|
||||
|
||||
To find the commit hash, issue the following command when in a `rust-lang/rust` checkout:
|
||||
```
|
||||
@ -71,6 +74,19 @@ The order should roughly be:
|
||||
7. Documentation improvements
|
||||
8. Others
|
||||
|
||||
As section headers, we use:
|
||||
|
||||
```
|
||||
### New Lints
|
||||
### Moves and Deprecations
|
||||
### Enhancements
|
||||
### False Positive Fixes
|
||||
### Suggestion Fixes/Improvements
|
||||
### ICE Fixes
|
||||
### Documentation Improvements
|
||||
### Others
|
||||
```
|
||||
|
||||
Please also be sure to update the Beta/Unreleased sections at the top with the
|
||||
relevant commit ranges.
|
||||
|
||||
@ -78,3 +94,4 @@ relevant commit ranges.
|
||||
[forge]: https://forge.rust-lang.org/
|
||||
[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy
|
||||
[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy
|
||||
[rust_stable_tools]: https://github.com/rust-lang/rust/releases
|
||||
|
@ -62,14 +62,14 @@ vec![
|
||||
},
|
||||
Lint {
|
||||
name: "await_holding_lock",
|
||||
group: "correctness",
|
||||
group: "pedantic",
|
||||
desc: "Inside an async function, holding a MutexGuard while calling await",
|
||||
deprecation: None,
|
||||
module: "await_holding_invalid",
|
||||
},
|
||||
Lint {
|
||||
name: "await_holding_refcell_ref",
|
||||
group: "correctness",
|
||||
group: "pedantic",
|
||||
desc: "Inside an async function, holding a RefCell ref while calling await",
|
||||
deprecation: None,
|
||||
module: "await_holding_invalid",
|
||||
@ -1117,6 +1117,13 @@ vec![
|
||||
deprecation: None,
|
||||
module: "returns",
|
||||
},
|
||||
Lint {
|
||||
name: "let_underscore_drop",
|
||||
group: "pedantic",
|
||||
desc: "non-binding let on a type that implements `Drop`",
|
||||
deprecation: None,
|
||||
module: "let_underscore",
|
||||
},
|
||||
Lint {
|
||||
name: "let_underscore_lock",
|
||||
group: "correctness",
|
||||
@ -1831,13 +1838,6 @@ vec![
|
||||
deprecation: None,
|
||||
module: "panic_in_result_fn",
|
||||
},
|
||||
Lint {
|
||||
name: "panic_params",
|
||||
group: "style",
|
||||
desc: "missing parameters in `panic!` calls",
|
||||
deprecation: None,
|
||||
module: "panic_unimplemented",
|
||||
},
|
||||
Lint {
|
||||
name: "panicking_unwrap",
|
||||
group: "correctness",
|
||||
@ -2114,7 +2114,7 @@ vec![
|
||||
Lint {
|
||||
name: "search_is_some",
|
||||
group: "complexity",
|
||||
desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`",
|
||||
desc: "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`",
|
||||
deprecation: None,
|
||||
module: "methods",
|
||||
},
|
||||
@ -2258,6 +2258,13 @@ vec![
|
||||
deprecation: None,
|
||||
module: "methods",
|
||||
},
|
||||
Lint {
|
||||
name: "string_from_utf8_as_bytes",
|
||||
group: "complexity",
|
||||
desc: "casting string slices to byte slices and back",
|
||||
deprecation: None,
|
||||
module: "strings",
|
||||
},
|
||||
Lint {
|
||||
name: "string_lit_as_bytes",
|
||||
group: "nursery",
|
||||
@ -2594,6 +2601,13 @@ vec![
|
||||
deprecation: None,
|
||||
module: "unwrap",
|
||||
},
|
||||
Lint {
|
||||
name: "unnecessary_wraps",
|
||||
group: "complexity",
|
||||
desc: "functions that only return `Ok` or `Some`",
|
||||
deprecation: None,
|
||||
module: "unnecessary_wraps",
|
||||
},
|
||||
Lint {
|
||||
name: "unneeded_field_pattern",
|
||||
group: "restriction",
|
||||
@ -2737,7 +2751,7 @@ vec![
|
||||
Lint {
|
||||
name: "useless_conversion",
|
||||
group: "complexity",
|
||||
desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type",
|
||||
desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type",
|
||||
deprecation: None,
|
||||
module: "useless_conversion",
|
||||
},
|
||||
|
16
tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
Normal file
16
tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// this file solely exists to test constants defined in foreign crates.
|
||||
// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure.
|
||||
|
||||
#![allow(clippy::declare_interior_mutable_const)]
|
||||
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
|
||||
enum Private<T> {
|
||||
ToBeUnfrozen(T),
|
||||
Frozen(usize),
|
||||
}
|
||||
|
||||
pub struct Wrapper(Private<AtomicUsize>);
|
||||
|
||||
pub const WRAPPED_PRIVATE_UNFROZEN_VARIANT: Wrapper = Wrapper(Private::ToBeUnfrozen(AtomicUsize::new(6)));
|
||||
pub const WRAPPED_PRIVATE_FROZEN_VARIANT: Wrapper = Wrapper(Private::Frozen(7));
|
101
tests/ui/borrow_interior_mutable_const/enums.rs
Normal file
101
tests/ui/borrow_interior_mutable_const/enums.rs
Normal file
@ -0,0 +1,101 @@
|
||||
// aux-build:helper.rs
|
||||
|
||||
#![warn(clippy::borrow_interior_mutable_const)]
|
||||
#![allow(clippy::declare_interior_mutable_const)]
|
||||
|
||||
// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions.
|
||||
|
||||
extern crate helper;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
|
||||
enum OptionalCell {
|
||||
Unfrozen(Cell<bool>),
|
||||
Frozen,
|
||||
}
|
||||
|
||||
const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
|
||||
const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
|
||||
|
||||
fn borrow_optional_cell() {
|
||||
let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability
|
||||
let _ = &FROZEN_VARIANT;
|
||||
}
|
||||
|
||||
trait AssocConsts {
|
||||
const TO_BE_UNFROZEN_VARIANT: OptionalCell;
|
||||
const TO_BE_FROZEN_VARIANT: OptionalCell;
|
||||
|
||||
const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
|
||||
const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
|
||||
|
||||
fn function() {
|
||||
// This is the "suboptimal behavior" mentioned in `is_value_unfrozen`
|
||||
// caused by a similar reason to unfrozen types without any default values
|
||||
// get linted even if it has frozen variants'.
|
||||
let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable
|
||||
|
||||
// The lint ignores default values because an impl of this trait can set
|
||||
// an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`.
|
||||
let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
impl AssocConsts for u64 {
|
||||
const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
|
||||
const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
|
||||
|
||||
fn function() {
|
||||
let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
|
||||
let _ = &<Self as AssocConsts>::TO_BE_FROZEN_VARIANT;
|
||||
let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable
|
||||
let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
|
||||
}
|
||||
}
|
||||
|
||||
trait AssocTypes {
|
||||
type ToBeUnfrozen;
|
||||
|
||||
const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
|
||||
const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
|
||||
|
||||
// there's no need to test here because it's the exactly same as `trait::AssocTypes`
|
||||
fn function();
|
||||
}
|
||||
|
||||
impl AssocTypes for u64 {
|
||||
type ToBeUnfrozen = AtomicUsize;
|
||||
|
||||
const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
|
||||
const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
|
||||
|
||||
fn function() {
|
||||
let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
|
||||
let _ = &<Self as AssocTypes>::TO_BE_FROZEN_VARIANT;
|
||||
}
|
||||
}
|
||||
|
||||
enum BothOfCellAndGeneric<T> {
|
||||
Unfrozen(Cell<*const T>),
|
||||
Generic(*const T),
|
||||
Frozen(usize),
|
||||
}
|
||||
|
||||
impl<T> BothOfCellAndGeneric<T> {
|
||||
const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
|
||||
const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
|
||||
const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability
|
||||
let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability
|
||||
let _ = &Self::FROZEN_VARIANT;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// constants defined in foreign crates
|
||||
let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability
|
||||
let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT;
|
||||
}
|
75
tests/ui/borrow_interior_mutable_const/enums.stderr
Normal file
75
tests/ui/borrow_interior_mutable_const/enums.stderr
Normal file
@ -0,0 +1,75 @@
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:22:14
|
||||
|
|
||||
LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:37:18
|
||||
|
|
||||
LL | let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:41:18
|
||||
|
|
||||
LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:50:18
|
||||
|
|
||||
LL | let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:52:18
|
||||
|
|
||||
LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:74:18
|
||||
|
|
||||
LL | let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:91:18
|
||||
|
|
||||
LL | let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:92:18
|
||||
|
|
||||
LL | let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/enums.rs:99:14
|
||||
|
|
||||
LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
@ -19,33 +19,7 @@ const NO_ANN: &dyn Display = &70;
|
||||
static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
|
||||
const ONCE_INIT: Once = Once::new();
|
||||
|
||||
trait Trait<T> {
|
||||
type AssocType;
|
||||
|
||||
const ATOMIC: AtomicUsize;
|
||||
const INPUT: T;
|
||||
const ASSOC: Self::AssocType;
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::INPUT;
|
||||
let _ = &Self::ASSOC;
|
||||
}
|
||||
}
|
||||
|
||||
impl Trait<u32> for u64 {
|
||||
type AssocType = AtomicUsize;
|
||||
|
||||
const ATOMIC: AtomicUsize = AtomicUsize::new(9);
|
||||
const INPUT: u32 = 10;
|
||||
const ASSOC: Self::AssocType = AtomicUsize::new(11);
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::INPUT;
|
||||
let _ = &Self::ASSOC; //~ ERROR interior mutability
|
||||
}
|
||||
}
|
||||
|
||||
// This is just a pointer that can be safely dereferended,
|
||||
// This is just a pointer that can be safely dereferenced,
|
||||
// it's semantically the same as `&'static T`;
|
||||
// but it isn't allowed to make a static reference from an arbitrary integer value at the moment.
|
||||
// For more information, please see the issue #5918.
|
||||
@ -100,7 +74,7 @@ fn main() {
|
||||
let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
|
||||
let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
|
||||
let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability
|
||||
let _ = &*ATOMIC_TUPLE.1;
|
||||
let _ = &ATOMIC_TUPLE.2;
|
||||
let _ = (&&&&ATOMIC_TUPLE).0;
|
||||
let _ = (&&&&ATOMIC_TUPLE).2;
|
||||
@ -124,9 +98,6 @@ fn main() {
|
||||
assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3);
|
||||
assert!(STATIC_TUPLE.1.is_empty());
|
||||
|
||||
u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
|
||||
|
||||
assert_eq!(NO_ANN.to_string(), "70"); // should never lint this.
|
||||
|
||||
let _ = &CELL_REF.0;
|
@ -1,22 +1,14 @@
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:44:18
|
||||
--> $DIR/others.rs:54:5
|
||||
|
|
||||
LL | let _ = &Self::ASSOC; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^
|
||||
LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:80:5
|
||||
|
|
||||
LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
| ^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:81:16
|
||||
--> $DIR/others.rs:55:16
|
||||
|
|
||||
LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
|
||||
| ^^^^^^
|
||||
@ -24,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:84:22
|
||||
--> $DIR/others.rs:58:22
|
||||
|
|
||||
LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -32,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:85:25
|
||||
--> $DIR/others.rs:59:25
|
||||
|
|
||||
LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -40,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:86:27
|
||||
--> $DIR/others.rs:60:27
|
||||
|
|
||||
LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -48,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:87:26
|
||||
--> $DIR/others.rs:61:26
|
||||
|
|
||||
LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^
|
||||
@ -56,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:98:14
|
||||
--> $DIR/others.rs:72:14
|
||||
|
|
||||
LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -64,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:99:14
|
||||
--> $DIR/others.rs:73:14
|
||||
|
|
||||
LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -72,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:100:19
|
||||
--> $DIR/others.rs:74:19
|
||||
|
|
||||
LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -80,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:101:14
|
||||
--> $DIR/others.rs:75:14
|
||||
|
|
||||
LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -88,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:102:13
|
||||
--> $DIR/others.rs:76:13
|
||||
|
|
||||
LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -96,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:108:13
|
||||
--> $DIR/others.rs:82:13
|
||||
|
|
||||
LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^^
|
||||
@ -104,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:113:5
|
||||
--> $DIR/others.rs:87:5
|
||||
|
|
||||
LL | CELL.set(2); //~ ERROR interior mutability
|
||||
| ^^^^
|
||||
@ -112,28 +104,12 @@ LL | CELL.set(2); //~ ERROR interior mutability
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:114:16
|
||||
--> $DIR/others.rs:88:16
|
||||
|
|
||||
LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
|
||||
| ^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:127:5
|
||||
|
|
||||
LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/borrow_interior_mutable_const.rs:128:16
|
||||
|
|
||||
LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: aborting due to 14 previous errors
|
||||
|
202
tests/ui/borrow_interior_mutable_const/traits.rs
Normal file
202
tests/ui/borrow_interior_mutable_const/traits.rs
Normal file
@ -0,0 +1,202 @@
|
||||
#![warn(clippy::borrow_interior_mutable_const)]
|
||||
#![allow(clippy::declare_interior_mutable_const)]
|
||||
|
||||
// this file replicates its `declare` counterpart. Please see it for more discussions.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
trait ConcreteTypes {
|
||||
const ATOMIC: AtomicUsize;
|
||||
const STRING: String;
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::ATOMIC; //~ ERROR interior mutable
|
||||
let _ = &Self::STRING;
|
||||
}
|
||||
}
|
||||
|
||||
impl ConcreteTypes for u64 {
|
||||
const ATOMIC: AtomicUsize = AtomicUsize::new(9);
|
||||
const STRING: String = String::new();
|
||||
|
||||
fn function() {
|
||||
// Lint this again since implementers can choose not to borrow it.
|
||||
let _ = &Self::ATOMIC; //~ ERROR interior mutable
|
||||
let _ = &Self::STRING;
|
||||
}
|
||||
}
|
||||
|
||||
// a helper trait used below
|
||||
trait ConstDefault {
|
||||
const DEFAULT: Self;
|
||||
}
|
||||
|
||||
trait GenericTypes<T, U> {
|
||||
const TO_REMAIN_GENERIC: T;
|
||||
const TO_BE_CONCRETE: U;
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::TO_REMAIN_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for Vec<T> {
|
||||
const TO_REMAIN_GENERIC: T = T::DEFAULT;
|
||||
const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::TO_REMAIN_GENERIC;
|
||||
let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
// a helper type used below
|
||||
pub struct Wrapper<T>(T);
|
||||
|
||||
trait AssocTypes {
|
||||
type ToBeFrozen;
|
||||
type ToBeUnfrozen;
|
||||
type ToBeGenericParam;
|
||||
|
||||
const TO_BE_FROZEN: Self::ToBeFrozen;
|
||||
const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
|
||||
const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
|
||||
const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::TO_BE_FROZEN;
|
||||
let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ConstDefault> AssocTypes for Vec<T> {
|
||||
type ToBeFrozen = u16;
|
||||
type ToBeUnfrozen = AtomicUsize;
|
||||
type ToBeGenericParam = T;
|
||||
|
||||
const TO_BE_FROZEN: Self::ToBeFrozen = 12;
|
||||
const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
|
||||
const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
|
||||
const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::TO_BE_FROZEN;
|
||||
let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable
|
||||
let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable
|
||||
let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
// a helper trait used below
|
||||
trait AssocTypesHelper {
|
||||
type NotToBeBounded;
|
||||
type ToBeBounded;
|
||||
|
||||
const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
|
||||
}
|
||||
|
||||
trait AssocTypesFromGenericParam<T>
|
||||
where
|
||||
T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
|
||||
{
|
||||
const NOT_BOUNDED: T::NotToBeBounded;
|
||||
const BOUNDED: T::ToBeBounded;
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::NOT_BOUNDED;
|
||||
let _ = &Self::BOUNDED; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AssocTypesFromGenericParam<T> for Vec<T>
|
||||
where
|
||||
T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
|
||||
{
|
||||
const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
|
||||
const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::NOT_BOUNDED;
|
||||
let _ = &Self::BOUNDED; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
trait SelfType: Sized {
|
||||
const SELF: Self;
|
||||
const WRAPPED_SELF: Option<Self>;
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::SELF;
|
||||
let _ = &Self::WRAPPED_SELF;
|
||||
}
|
||||
}
|
||||
|
||||
impl SelfType for u64 {
|
||||
const SELF: Self = 16;
|
||||
const WRAPPED_SELF: Option<Self> = Some(20);
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::SELF;
|
||||
let _ = &Self::WRAPPED_SELF;
|
||||
}
|
||||
}
|
||||
|
||||
impl SelfType for AtomicUsize {
|
||||
const SELF: Self = AtomicUsize::new(17);
|
||||
const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::SELF; //~ ERROR interior mutable
|
||||
let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
trait BothOfCellAndGeneric<T> {
|
||||
const DIRECT: Cell<T>;
|
||||
const INDIRECT: Cell<*const T>;
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::DIRECT;
|
||||
let _ = &Self::INDIRECT; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ConstDefault> BothOfCellAndGeneric<T> for Vec<T> {
|
||||
const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
|
||||
const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::DIRECT;
|
||||
let _ = &Self::INDIRECT; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
struct Local<T>(T);
|
||||
|
||||
impl<T> Local<T>
|
||||
where
|
||||
T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
|
||||
{
|
||||
const ATOMIC: AtomicUsize = AtomicUsize::new(18);
|
||||
const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
|
||||
|
||||
const GENERIC_TYPE: T = T::DEFAULT;
|
||||
|
||||
const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
|
||||
const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
|
||||
|
||||
fn function() {
|
||||
let _ = &Self::ATOMIC; //~ ERROR interior mutable
|
||||
let _ = &Self::COW;
|
||||
let _ = &Self::GENERIC_TYPE;
|
||||
let _ = &Self::ASSOC_TYPE;
|
||||
let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
|
||||
}
|
123
tests/ui/borrow_interior_mutable_const/traits.stderr
Normal file
123
tests/ui/borrow_interior_mutable_const/traits.stderr
Normal file
@ -0,0 +1,123 @@
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:15:18
|
||||
|
|
||||
LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:26:18
|
||||
|
|
||||
LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:51:18
|
||||
|
|
||||
LL | let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:86:18
|
||||
|
|
||||
LL | let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:87:18
|
||||
|
|
||||
LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:109:18
|
||||
|
|
||||
LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:122:18
|
||||
|
|
||||
LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:151:18
|
||||
|
|
||||
LL | let _ = &Self::SELF; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:152:18
|
||||
|
|
||||
LL | let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:162:18
|
||||
|
|
||||
LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:172:18
|
||||
|
|
||||
LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:191:18
|
||||
|
|
||||
LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:195:18
|
||||
|
|
||||
LL | let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:200:5
|
||||
|
|
||||
LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: a `const` item with interior mutability should not be borrowed
|
||||
--> $DIR/traits.rs:201:16
|
||||
|
|
||||
LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: assign this const to a local or static variable, and use the variable here
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
|
@ -19,7 +19,7 @@ LL | loop {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::empty-loop` implied by `-D warnings`
|
||||
= help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
|
||||
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
11
tests/ui/crashes/ice-6332.rs
Normal file
11
tests/ui/crashes/ice-6332.rs
Normal file
@ -0,0 +1,11 @@
|
||||
fn cmark_check() {
|
||||
let mut link_err = false;
|
||||
macro_rules! cmark_error {
|
||||
($bad:expr) => {
|
||||
*$bad = true;
|
||||
};
|
||||
}
|
||||
cmark_error!(&mut link_err);
|
||||
}
|
||||
|
||||
pub fn main() {}
|
5
tests/ui/crashes/implements-trait.rs
Normal file
5
tests/ui/crashes/implements-trait.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[allow(clippy::needless_borrowed_reference)]
|
||||
fn main() {
|
||||
let mut v = Vec::<String>::new();
|
||||
let _ = v.iter_mut().filter(|&ref a| a.is_empty());
|
||||
}
|
123
tests/ui/declare_interior_mutable_const/enums.rs
Normal file
123
tests/ui/declare_interior_mutable_const/enums.rs
Normal file
@ -0,0 +1,123 @@
|
||||
#![warn(clippy::declare_interior_mutable_const)]
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
|
||||
enum OptionalCell {
|
||||
Unfrozen(Cell<bool>),
|
||||
Frozen,
|
||||
}
|
||||
|
||||
// a constant with enums should be linted only when the used variant is unfrozen (#3962).
|
||||
const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable
|
||||
const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
|
||||
|
||||
const fn unfrozen_variant() -> OptionalCell {
|
||||
OptionalCell::Unfrozen(Cell::new(false))
|
||||
}
|
||||
|
||||
const fn frozen_variant() -> OptionalCell {
|
||||
OptionalCell::Frozen
|
||||
}
|
||||
|
||||
const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable
|
||||
const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
|
||||
|
||||
enum NestedInnermost {
|
||||
Unfrozen(AtomicUsize),
|
||||
Frozen,
|
||||
}
|
||||
|
||||
struct NestedInner {
|
||||
inner: NestedInnermost,
|
||||
}
|
||||
|
||||
enum NestedOuter {
|
||||
NestedInner(NestedInner),
|
||||
NotNested(usize),
|
||||
}
|
||||
|
||||
struct NestedOutermost {
|
||||
outer: NestedOuter,
|
||||
}
|
||||
|
||||
// a constant with enums should be linted according to its value, no matter how structs involve.
|
||||
const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
|
||||
outer: NestedOuter::NestedInner(NestedInner {
|
||||
inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
|
||||
}),
|
||||
}; //~ ERROR interior mutable
|
||||
const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost {
|
||||
outer: NestedOuter::NestedInner(NestedInner {
|
||||
inner: NestedInnermost::Frozen,
|
||||
}),
|
||||
};
|
||||
|
||||
trait AssocConsts {
|
||||
// When there's no default value, lint it only according to its type.
|
||||
// Further details are on the corresponding code (`NonCopyConst::check_trait_item`).
|
||||
const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
|
||||
const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
|
||||
|
||||
// Lint default values accordingly.
|
||||
const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable
|
||||
const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
|
||||
}
|
||||
|
||||
// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it
|
||||
// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'.
|
||||
impl AssocConsts for u64 {
|
||||
const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
|
||||
const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
|
||||
|
||||
// even if this sets an unfrozen variant, the lint ignores it.
|
||||
const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
|
||||
}
|
||||
|
||||
// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters
|
||||
// here are values; and I think substituted generics at definitions won't appear in MIR.
|
||||
trait AssocTypes {
|
||||
type ToBeUnfrozen;
|
||||
|
||||
const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
|
||||
const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
|
||||
}
|
||||
|
||||
impl AssocTypes for u64 {
|
||||
type ToBeUnfrozen = AtomicUsize;
|
||||
|
||||
const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
|
||||
const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
|
||||
}
|
||||
|
||||
// Use raw pointers since direct generics have a false negative at the type level.
|
||||
enum BothOfCellAndGeneric<T> {
|
||||
Unfrozen(Cell<*const T>),
|
||||
Generic(*const T),
|
||||
Frozen(usize),
|
||||
}
|
||||
|
||||
impl<T> BothOfCellAndGeneric<T> {
|
||||
const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
|
||||
|
||||
// This is a false positive. The argument about this is on `is_value_unfrozen_raw`
|
||||
const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
|
||||
|
||||
const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
|
||||
|
||||
// This is what is likely to be a false negative when one tries to fix
|
||||
// the `GENERIC_VARIANT` false positive.
|
||||
const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable
|
||||
}
|
||||
|
||||
// associated types here is basically the same as the one above.
|
||||
trait BothOfCellAndGenericWithAssocType {
|
||||
type AssocType;
|
||||
|
||||
const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
|
||||
BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
|
||||
const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
|
||||
const FROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Frozen(5);
|
||||
}
|
||||
|
||||
fn main() {}
|
89
tests/ui/declare_interior_mutable_const/enums.stderr
Normal file
89
tests/ui/declare_interior_mutable_const/enums.stderr
Normal file
@ -0,0 +1,89 @@
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:12:1
|
||||
|
|
||||
LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
|
|
||||
= note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:23:1
|
||||
|
|
||||
LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:45:1
|
||||
|
|
||||
LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
|
||||
| ^----
|
||||
| |
|
||||
| _make this a static item (maybe with lazy_static)
|
||||
| |
|
||||
LL | | outer: NestedOuter::NestedInner(NestedInner {
|
||||
LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
|
||||
LL | | }),
|
||||
LL | | }; //~ ERROR interior mutable
|
||||
| |__^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:59:5
|
||||
|
|
||||
LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:60:5
|
||||
|
|
||||
LL | const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:63:5
|
||||
|
|
||||
LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:89:5
|
||||
|
|
||||
LL | const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:101:5
|
||||
|
|
||||
LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mut...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:104:5
|
||||
|
|
||||
LL | const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:110:5
|
||||
|
|
||||
LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:117:5
|
||||
|
|
||||
LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
|
||||
LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
|
||||
| |____________________________________________________________________^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/enums.rs:119:5
|
||||
|
|
||||
LL | const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mu...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
34
tests/ui/declare_interior_mutable_const/others.rs
Normal file
34
tests/ui/declare_interior_mutable_const/others.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#![warn(clippy::declare_interior_mutable_const)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Display;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::Once;
|
||||
|
||||
const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
|
||||
const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
|
||||
const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
|
||||
//~^ ERROR interior mutable
|
||||
|
||||
macro_rules! declare_const {
|
||||
($name:ident: $ty:ty = $e:expr) => {
|
||||
const $name: $ty = $e;
|
||||
};
|
||||
}
|
||||
declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
|
||||
|
||||
// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
|
||||
|
||||
const INTEGER: u8 = 8;
|
||||
const STRING: String = String::new();
|
||||
const STR: &str = "012345";
|
||||
const COW: Cow<str> = Cow::Borrowed("abcdef");
|
||||
//^ note: a const item of Cow is used in the `postgres` package.
|
||||
|
||||
const NO_ANN: &dyn Display = &70;
|
||||
|
||||
static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
|
||||
//^ there should be no lints on this line
|
||||
|
||||
fn main() {}
|
39
tests/ui/declare_interior_mutable_const/others.stderr
Normal file
39
tests/ui/declare_interior_mutable_const/others.stderr
Normal file
@ -0,0 +1,39 @@
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/others.rs:9:1
|
||||
|
|
||||
LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
|
|
||||
= note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/others.rs:10:1
|
||||
|
|
||||
LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/others.rs:11:1
|
||||
|
|
||||
LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/others.rs:16:9
|
||||
|
|
||||
LL | const $name: $ty = $e;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
|
||||
| ------------------------------------------ in this macro invocation
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
@ -2,37 +2,13 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Display;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::Once;
|
||||
|
||||
const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
|
||||
const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
|
||||
const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
|
||||
//~^ ERROR interior mutable
|
||||
|
||||
macro_rules! declare_const {
|
||||
($name:ident: $ty:ty = $e:expr) => {
|
||||
const $name: $ty = $e;
|
||||
};
|
||||
}
|
||||
declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
|
||||
|
||||
// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
|
||||
|
||||
const INTEGER: u8 = 8;
|
||||
const STRING: String = String::new();
|
||||
const STR: &str = "012345";
|
||||
const COW: Cow<str> = Cow::Borrowed("abcdef");
|
||||
//^ note: a const item of Cow is used in the `postgres` package.
|
||||
|
||||
const NO_ANN: &dyn Display = &70;
|
||||
|
||||
static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
|
||||
//^ there should be no lints on this line
|
||||
|
||||
#[allow(clippy::declare_interior_mutable_const)]
|
||||
const ONCE_INIT: Once = Once::new();
|
||||
|
||||
// a constant whose type is a concrete type should be linted at the definition site.
|
||||
trait ConcreteTypes {
|
@ -1,48 +1,13 @@
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:9:1
|
||||
--> $DIR/traits.rs:15:5
|
||||
|
|
||||
LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:10:1
|
||||
|
|
||||
LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:11:1
|
||||
|
|
||||
LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
|
||||
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| make this a static item (maybe with lazy_static)
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:16:9
|
||||
|
|
||||
LL | const $name: $ty = $e;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
|
||||
| ------------------------------------------ in this macro invocation
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:39:5
|
||||
|
|
||||
LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:16:9
|
||||
--> $DIR/traits.rs:9:9
|
||||
|
|
||||
LL | const $name: $ty = $e;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -53,58 +18,58 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR i
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:67:5
|
||||
--> $DIR/traits.rs:43:5
|
||||
|
|
||||
LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:92:5
|
||||
--> $DIR/traits.rs:68:5
|
||||
|
|
||||
LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:93:5
|
||||
--> $DIR/traits.rs:69:5
|
||||
|
|
||||
LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:112:5
|
||||
--> $DIR/traits.rs:88:5
|
||||
|
|
||||
LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:140:5
|
||||
--> $DIR/traits.rs:116:5
|
||||
|
|
||||
LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:141:5
|
||||
--> $DIR/traits.rs:117:5
|
||||
|
|
||||
LL | const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:149:5
|
||||
--> $DIR/traits.rs:125:5
|
||||
|
|
||||
LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:165:5
|
||||
--> $DIR/traits.rs:141:5
|
||||
|
|
||||
LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: a `const` item should never be interior mutable
|
||||
--> $DIR/declare_interior_mutable_const.rs:171:5
|
||||
--> $DIR/traits.rs:147:5
|
||||
|
|
||||
LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
error: aborting due to 11 previous errors
|
||||
|
@ -10,5 +10,6 @@
|
||||
#[warn(clippy::regex_macro)]
|
||||
#[warn(clippy::drop_bounds)]
|
||||
#[warn(clippy::temporary_cstring_as_ptr)]
|
||||
#[warn(clippy::panic_params)]
|
||||
|
||||
fn main() {}
|
||||
|
@ -72,11 +72,17 @@ error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has
|
||||
LL | #[warn(clippy::temporary_cstring_as_ptr)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt``
|
||||
--> $DIR/deprecated.rs:13:8
|
||||
|
|
||||
LL | #[warn(clippy::panic_params)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
|
||||
--> $DIR/deprecated.rs:1:8
|
||||
|
|
||||
LL | #[warn(clippy::str_to_string)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// run-rustfix
|
||||
#![warn(clippy::deref_addrof)]
|
||||
|
||||
fn get_number() -> usize {
|
||||
10
|
||||
@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize {
|
||||
|
||||
#[allow(clippy::many_single_char_names, clippy::double_parens)]
|
||||
#[allow(unused_variables, unused_parens)]
|
||||
#[warn(clippy::deref_addrof)]
|
||||
fn main() {
|
||||
let a = 10;
|
||||
let aref = &a;
|
||||
@ -37,3 +37,27 @@ fn main() {
|
||||
|
||||
let b = *aref;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro_rules! m {
|
||||
($visitor: expr) => {
|
||||
$visitor
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro_rules! m_mut {
|
||||
($visitor: expr) => {
|
||||
$visitor
|
||||
};
|
||||
}
|
||||
|
||||
pub struct S;
|
||||
impl S {
|
||||
pub fn f(&self) -> &Self {
|
||||
m!(self)
|
||||
}
|
||||
pub fn f_mut(&self) -> &Self {
|
||||
m_mut!(self)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
// run-rustfix
|
||||
#![warn(clippy::deref_addrof)]
|
||||
|
||||
fn get_number() -> usize {
|
||||
10
|
||||
@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize {
|
||||
|
||||
#[allow(clippy::many_single_char_names, clippy::double_parens)]
|
||||
#[allow(unused_variables, unused_parens)]
|
||||
#[warn(clippy::deref_addrof)]
|
||||
fn main() {
|
||||
let a = 10;
|
||||
let aref = &a;
|
||||
@ -37,3 +37,27 @@ fn main() {
|
||||
|
||||
let b = **&aref;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro_rules! m {
|
||||
($visitor: expr) => {
|
||||
*& $visitor
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
macro_rules! m_mut {
|
||||
($visitor: expr) => {
|
||||
*& mut $visitor
|
||||
};
|
||||
}
|
||||
|
||||
pub struct S;
|
||||
impl S {
|
||||
pub fn f(&self) -> &Self {
|
||||
m!(self)
|
||||
}
|
||||
pub fn f_mut(&self) -> &Self {
|
||||
m_mut!(self)
|
||||
}
|
||||
}
|
||||
|
@ -48,5 +48,27 @@ error: immediately dereferencing a reference
|
||||
LL | let b = **&aref;
|
||||
| ^^^^^^ help: try this: `aref`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:44:9
|
||||
|
|
||||
LL | *& $visitor
|
||||
| ^^^^^^^^^^^ help: try this: `$visitor`
|
||||
...
|
||||
LL | m!(self)
|
||||
| -------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: immediately dereferencing a reference
|
||||
--> $DIR/deref_addrof.rs:51:9
|
||||
|
|
||||
LL | *& mut $visitor
|
||||
| ^^^^^^^^^^^^^^^ help: try this: `$visitor`
|
||||
...
|
||||
LL | m_mut!(self)
|
||||
| ------------ in this macro invocation
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![warn(clippy::derive_ord_xor_partial_ord)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:20:10
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:21:10
|
||||
|
|
||||
LL | #[derive(Ord, PartialEq, Eq)]
|
||||
| ^^^
|
||||
|
|
||||
= note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings`
|
||||
note: `PartialOrd` implemented here
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:23:1
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:24:1
|
||||
|
|
||||
LL | / impl PartialOrd for DeriveOrd {
|
||||
LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
@ -17,13 +17,13 @@ LL | | }
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:29:10
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:30:10
|
||||
|
|
||||
LL | #[derive(Ord, PartialEq, Eq)]
|
||||
| ^^^
|
||||
|
|
||||
note: `PartialOrd` implemented here
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:32:1
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:33:1
|
||||
|
|
||||
LL | / impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable {
|
||||
LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
@ -34,7 +34,7 @@ LL | | }
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: you are implementing `Ord` explicitly but have derived `PartialOrd`
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:41:1
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:42:1
|
||||
|
|
||||
LL | / impl std::cmp::Ord for DerivePartialOrd {
|
||||
LL | | fn cmp(&self, other: &Self) -> Ordering {
|
||||
@ -44,14 +44,14 @@ LL | | }
|
||||
| |_^
|
||||
|
|
||||
note: `PartialOrd` implemented here
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:38:10
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:39:10
|
||||
|
|
||||
LL | #[derive(PartialOrd, PartialEq, Eq)]
|
||||
| ^^^^^^^^^^
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: you are implementing `Ord` explicitly but have derived `PartialOrd`
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:61:5
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:62:5
|
||||
|
|
||||
LL | / impl Ord for DerivePartialOrdInUseOrd {
|
||||
LL | | fn cmp(&self, other: &Self) -> Ordering {
|
||||
@ -61,7 +61,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
|
||||
note: `PartialOrd` implemented here
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:58:14
|
||||
--> $DIR/derive_ord_xor_partial_ord.rs:59:14
|
||||
|
|
||||
LL | #[derive(PartialOrd, PartialEq, Eq)]
|
||||
| ^^^^^^^^^^
|
||||
|
@ -1,6 +1,7 @@
|
||||
// edition:2018
|
||||
#![warn(clippy::missing_errors_doc)]
|
||||
#![allow(clippy::result_unit_err)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
use std::io;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: docs for function returning `Result` missing `# Errors` section
|
||||
--> $DIR/doc_errors.rs:7:1
|
||||
--> $DIR/doc_errors.rs:8:1
|
||||
|
|
||||
LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
|
||||
LL | | unimplemented!();
|
||||
@ -9,7 +9,7 @@ LL | | }
|
||||
= note: `-D clippy::missing-errors-doc` implied by `-D warnings`
|
||||
|
||||
error: docs for function returning `Result` missing `# Errors` section
|
||||
--> $DIR/doc_errors.rs:11:1
|
||||
--> $DIR/doc_errors.rs:12:1
|
||||
|
|
||||
LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
|
||||
LL | | unimplemented!();
|
||||
@ -17,7 +17,7 @@ LL | | }
|
||||
| |_^
|
||||
|
||||
error: docs for function returning `Result` missing `# Errors` section
|
||||
--> $DIR/doc_errors.rs:16:1
|
||||
--> $DIR/doc_errors.rs:17:1
|
||||
|
|
||||
LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
|
||||
LL | | unimplemented!();
|
||||
@ -25,7 +25,7 @@ LL | | }
|
||||
| |_^
|
||||
|
||||
error: docs for function returning `Result` missing `# Errors` section
|
||||
--> $DIR/doc_errors.rs:21:1
|
||||
--> $DIR/doc_errors.rs:22:1
|
||||
|
|
||||
LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
|
||||
LL | | unimplemented!();
|
||||
@ -33,7 +33,7 @@ LL | | }
|
||||
| |_^
|
||||
|
||||
error: docs for function returning `Result` missing `# Errors` section
|
||||
--> $DIR/doc_errors.rs:51:5
|
||||
--> $DIR/doc_errors.rs:52:5
|
||||
|
|
||||
LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> {
|
||||
LL | | unimplemented!();
|
||||
@ -41,7 +41,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
||||
error: docs for function returning `Result` missing `# Errors` section
|
||||
--> $DIR/doc_errors.rs:56:5
|
||||
--> $DIR/doc_errors.rs:57:5
|
||||
|
|
||||
LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
|
||||
LL | | unimplemented!();
|
||||
@ -49,7 +49,7 @@ LL | | }
|
||||
| |_____^
|
||||
|
||||
error: docs for function returning `Result` missing `# Errors` section
|
||||
--> $DIR/doc_errors.rs:85:5
|
||||
--> $DIR/doc_errors.rs:86:5
|
||||
|
|
||||
LL | fn trait_method_missing_errors_header() -> Result<(), ()>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![warn(clippy::drop_ref)]
|
||||
#![allow(clippy::toplevel_ref_arg)]
|
||||
#![allow(clippy::map_err_ignore)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
use std::mem::drop;
|
||||
|
||||
|
@ -1,108 +1,108 @@
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:10:5
|
||||
--> $DIR/drop_ref.rs:11:5
|
||||
|
|
||||
LL | drop(&SomeStruct);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::drop-ref` implied by `-D warnings`
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/drop_ref.rs:10:10
|
||||
--> $DIR/drop_ref.rs:11:10
|
||||
|
|
||||
LL | drop(&SomeStruct);
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:13:5
|
||||
--> $DIR/drop_ref.rs:14:5
|
||||
|
|
||||
LL | drop(&owned1);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/drop_ref.rs:13:10
|
||||
--> $DIR/drop_ref.rs:14:10
|
||||
|
|
||||
LL | drop(&owned1);
|
||||
| ^^^^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:14:5
|
||||
--> $DIR/drop_ref.rs:15:5
|
||||
|
|
||||
LL | drop(&&owned1);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&&SomeStruct`
|
||||
--> $DIR/drop_ref.rs:14:10
|
||||
--> $DIR/drop_ref.rs:15:10
|
||||
|
|
||||
LL | drop(&&owned1);
|
||||
| ^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:15:5
|
||||
--> $DIR/drop_ref.rs:16:5
|
||||
|
|
||||
LL | drop(&mut owned1);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&mut SomeStruct`
|
||||
--> $DIR/drop_ref.rs:15:10
|
||||
--> $DIR/drop_ref.rs:16:10
|
||||
|
|
||||
LL | drop(&mut owned1);
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:19:5
|
||||
--> $DIR/drop_ref.rs:20:5
|
||||
|
|
||||
LL | drop(reference1);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/drop_ref.rs:19:10
|
||||
--> $DIR/drop_ref.rs:20:10
|
||||
|
|
||||
LL | drop(reference1);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:22:5
|
||||
--> $DIR/drop_ref.rs:23:5
|
||||
|
|
||||
LL | drop(reference2);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&mut SomeStruct`
|
||||
--> $DIR/drop_ref.rs:22:10
|
||||
--> $DIR/drop_ref.rs:23:10
|
||||
|
|
||||
LL | drop(reference2);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:25:5
|
||||
--> $DIR/drop_ref.rs:26:5
|
||||
|
|
||||
LL | drop(reference3);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/drop_ref.rs:25:10
|
||||
--> $DIR/drop_ref.rs:26:10
|
||||
|
|
||||
LL | drop(reference3);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:30:5
|
||||
--> $DIR/drop_ref.rs:31:5
|
||||
|
|
||||
LL | drop(&val);
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&T`
|
||||
--> $DIR/drop_ref.rs:30:10
|
||||
--> $DIR/drop_ref.rs:31:10
|
||||
|
|
||||
LL | drop(&val);
|
||||
| ^^^^
|
||||
|
||||
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
|
||||
--> $DIR/drop_ref.rs:38:5
|
||||
--> $DIR/drop_ref.rs:39:5
|
||||
|
|
||||
LL | std::mem::drop(&SomeStruct);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/drop_ref.rs:38:20
|
||||
--> $DIR/drop_ref.rs:39:20
|
||||
|
|
||||
LL | std::mem::drop(&SomeStruct);
|
||||
| ^^^^^^^^^^^
|
||||
|
@ -5,7 +5,7 @@ LL | loop {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::empty-loop` implied by `-D warnings`
|
||||
= help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
|
||||
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
||||
|
||||
error: empty `loop {}` wastes CPU cycles
|
||||
--> $DIR/empty_loop.rs:11:9
|
||||
@ -13,7 +13,7 @@ error: empty `loop {}` wastes CPU cycles
|
||||
LL | loop {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
|
||||
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
||||
|
||||
error: empty `loop {}` wastes CPU cycles
|
||||
--> $DIR/empty_loop.rs:15:9
|
||||
@ -21,7 +21,7 @@ error: empty `loop {}` wastes CPU cycles
|
||||
LL | 'inner: loop {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
|
||||
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -10,13 +10,18 @@ use core::panic::PanicInfo;
|
||||
|
||||
#[start]
|
||||
fn main(argc: isize, argv: *const *const u8) -> isize {
|
||||
// This should trigger the lint
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
// This should NOT trigger the lint
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
extern "C" fn eh_personality() {}
|
||||
extern "C" fn eh_personality() {
|
||||
// This should also trigger the lint
|
||||
loop {}
|
||||
}
|
||||
|
19
tests/ui/empty_loop_no_std.stderr
Normal file
19
tests/ui/empty_loop_no_std.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error: empty `loop {}` wastes CPU cycles
|
||||
--> $DIR/empty_loop_no_std.rs:14:5
|
||||
|
|
||||
LL | loop {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::empty-loop` implied by `-D warnings`
|
||||
= help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
|
||||
|
||||
error: empty `loop {}` wastes CPU cycles
|
||||
--> $DIR/empty_loop_no_std.rs:26:5
|
||||
|
|
||||
LL | loop {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(clippy::clippy::let_underscore_drop)]
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
|
||||
fn main() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: called `filter(..).map(..)` on an `Iterator`
|
||||
--> $DIR/filter_methods.rs:5:21
|
||||
--> $DIR/filter_methods.rs:6:21
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -8,7 +8,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x *
|
||||
= help: this is more succinctly expressed by calling `.filter_map(..)` instead
|
||||
|
||||
error: called `filter(..).flat_map(..)` on an `Iterator`
|
||||
--> $DIR/filter_methods.rs:7:21
|
||||
--> $DIR/filter_methods.rs:8:21
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6]
|
||||
| _____________________^
|
||||
@ -20,7 +20,7 @@ LL | | .flat_map(|x| x.checked_mul(2))
|
||||
= help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
|
||||
|
||||
error: called `filter_map(..).flat_map(..)` on an `Iterator`
|
||||
--> $DIR/filter_methods.rs:13:21
|
||||
--> $DIR/filter_methods.rs:14:21
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6]
|
||||
| _____________________^
|
||||
@ -32,7 +32,7 @@ LL | | .flat_map(|x| x.checked_mul(2))
|
||||
= help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
|
||||
|
||||
error: called `filter_map(..).map(..)` on an `Iterator`
|
||||
--> $DIR/filter_methods.rs:19:21
|
||||
--> $DIR/filter_methods.rs:20:21
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6]
|
||||
| _____________________^
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![warn(clippy::forget_ref)]
|
||||
#![allow(clippy::toplevel_ref_arg)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
use std::mem::forget;
|
||||
|
||||
|
@ -1,108 +1,108 @@
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:9:5
|
||||
--> $DIR/forget_ref.rs:10:5
|
||||
|
|
||||
LL | forget(&SomeStruct);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::forget-ref` implied by `-D warnings`
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/forget_ref.rs:9:12
|
||||
--> $DIR/forget_ref.rs:10:12
|
||||
|
|
||||
LL | forget(&SomeStruct);
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:12:5
|
||||
--> $DIR/forget_ref.rs:13:5
|
||||
|
|
||||
LL | forget(&owned);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/forget_ref.rs:12:12
|
||||
--> $DIR/forget_ref.rs:13:12
|
||||
|
|
||||
LL | forget(&owned);
|
||||
| ^^^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:13:5
|
||||
--> $DIR/forget_ref.rs:14:5
|
||||
|
|
||||
LL | forget(&&owned);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&&SomeStruct`
|
||||
--> $DIR/forget_ref.rs:13:12
|
||||
--> $DIR/forget_ref.rs:14:12
|
||||
|
|
||||
LL | forget(&&owned);
|
||||
| ^^^^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:14:5
|
||||
--> $DIR/forget_ref.rs:15:5
|
||||
|
|
||||
LL | forget(&mut owned);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&mut SomeStruct`
|
||||
--> $DIR/forget_ref.rs:14:12
|
||||
--> $DIR/forget_ref.rs:15:12
|
||||
|
|
||||
LL | forget(&mut owned);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:18:5
|
||||
--> $DIR/forget_ref.rs:19:5
|
||||
|
|
||||
LL | forget(&*reference1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/forget_ref.rs:18:12
|
||||
--> $DIR/forget_ref.rs:19:12
|
||||
|
|
||||
LL | forget(&*reference1);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:21:5
|
||||
--> $DIR/forget_ref.rs:22:5
|
||||
|
|
||||
LL | forget(reference2);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&mut SomeStruct`
|
||||
--> $DIR/forget_ref.rs:21:12
|
||||
--> $DIR/forget_ref.rs:22:12
|
||||
|
|
||||
LL | forget(reference2);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:24:5
|
||||
--> $DIR/forget_ref.rs:25:5
|
||||
|
|
||||
LL | forget(reference3);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/forget_ref.rs:24:12
|
||||
--> $DIR/forget_ref.rs:25:12
|
||||
|
|
||||
LL | forget(reference3);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:29:5
|
||||
--> $DIR/forget_ref.rs:30:5
|
||||
|
|
||||
LL | forget(&val);
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&T`
|
||||
--> $DIR/forget_ref.rs:29:12
|
||||
--> $DIR/forget_ref.rs:30:12
|
||||
|
|
||||
LL | forget(&val);
|
||||
| ^^^^
|
||||
|
||||
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
--> $DIR/forget_ref.rs:37:5
|
||||
--> $DIR/forget_ref.rs:38:5
|
||||
|
|
||||
LL | std::mem::forget(&SomeStruct);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: argument has type `&SomeStruct`
|
||||
--> $DIR/forget_ref.rs:37:22
|
||||
--> $DIR/forget_ref.rs:38:22
|
||||
|
|
||||
LL | std::mem::forget(&SomeStruct);
|
||||
| ^^^^^^^^^^^
|
||||
|
19
tests/ui/let_underscore_drop.rs
Normal file
19
tests/ui/let_underscore_drop.rs
Normal file
@ -0,0 +1,19 @@
|
||||
#![warn(clippy::let_underscore_drop)]
|
||||
|
||||
struct Droppable;
|
||||
|
||||
impl Drop for Droppable {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let unit = ();
|
||||
let boxed = Box::new(());
|
||||
let droppable = Droppable;
|
||||
let optional = Some(Droppable);
|
||||
|
||||
let _ = ();
|
||||
let _ = Box::new(());
|
||||
let _ = Droppable;
|
||||
let _ = Some(Droppable);
|
||||
}
|
27
tests/ui/let_underscore_drop.stderr
Normal file
27
tests/ui/let_underscore_drop.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error: non-binding `let` on a type that implements `Drop`
|
||||
--> $DIR/let_underscore_drop.rs:16:5
|
||||
|
|
||||
LL | let _ = Box::new(());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::let-underscore-drop` implied by `-D warnings`
|
||||
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
|
||||
|
||||
error: non-binding `let` on a type that implements `Drop`
|
||||
--> $DIR/let_underscore_drop.rs:17:5
|
||||
|
|
||||
LL | let _ = Droppable;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
|
||||
|
||||
error: non-binding `let` on a type that implements `Drop`
|
||||
--> $DIR/let_underscore_drop.rs:18:5
|
||||
|
|
||||
LL | let _ = Some(Droppable);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![warn(clippy::let_underscore_must_use)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
// Debug implementations can fire this lint,
|
||||
// so we shouldn't lint external macros
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: non-binding let on a result of a `#[must_use]` function
|
||||
--> $DIR/let_underscore_must_use.rs:66:5
|
||||
--> $DIR/let_underscore_must_use.rs:67:5
|
||||
|
|
||||
LL | let _ = f();
|
||||
| ^^^^^^^^^^^^
|
||||
@ -8,7 +8,7 @@ LL | let _ = f();
|
||||
= help: consider explicitly using function result
|
||||
|
||||
error: non-binding let on an expression with `#[must_use]` type
|
||||
--> $DIR/let_underscore_must_use.rs:67:5
|
||||
--> $DIR/let_underscore_must_use.rs:68:5
|
||||
|
|
||||
LL | let _ = g();
|
||||
| ^^^^^^^^^^^^
|
||||
@ -16,7 +16,7 @@ LL | let _ = g();
|
||||
= help: consider explicitly using expression value
|
||||
|
||||
error: non-binding let on a result of a `#[must_use]` function
|
||||
--> $DIR/let_underscore_must_use.rs:69:5
|
||||
--> $DIR/let_underscore_must_use.rs:70:5
|
||||
|
|
||||
LL | let _ = l(0_u32);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
@ -24,7 +24,7 @@ LL | let _ = l(0_u32);
|
||||
= help: consider explicitly using function result
|
||||
|
||||
error: non-binding let on a result of a `#[must_use]` function
|
||||
--> $DIR/let_underscore_must_use.rs:73:5
|
||||
--> $DIR/let_underscore_must_use.rs:74:5
|
||||
|
|
||||
LL | let _ = s.f();
|
||||
| ^^^^^^^^^^^^^^
|
||||
@ -32,7 +32,7 @@ LL | let _ = s.f();
|
||||
= help: consider explicitly using function result
|
||||
|
||||
error: non-binding let on an expression with `#[must_use]` type
|
||||
--> $DIR/let_underscore_must_use.rs:74:5
|
||||
--> $DIR/let_underscore_must_use.rs:75:5
|
||||
|
|
||||
LL | let _ = s.g();
|
||||
| ^^^^^^^^^^^^^^
|
||||
@ -40,7 +40,7 @@ LL | let _ = s.g();
|
||||
= help: consider explicitly using expression value
|
||||
|
||||
error: non-binding let on a result of a `#[must_use]` function
|
||||
--> $DIR/let_underscore_must_use.rs:77:5
|
||||
--> $DIR/let_underscore_must_use.rs:78:5
|
||||
|
|
||||
LL | let _ = S::h();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -48,7 +48,7 @@ LL | let _ = S::h();
|
||||
= help: consider explicitly using function result
|
||||
|
||||
error: non-binding let on an expression with `#[must_use]` type
|
||||
--> $DIR/let_underscore_must_use.rs:78:5
|
||||
--> $DIR/let_underscore_must_use.rs:79:5
|
||||
|
|
||||
LL | let _ = S::p();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -56,7 +56,7 @@ LL | let _ = S::p();
|
||||
= help: consider explicitly using expression value
|
||||
|
||||
error: non-binding let on a result of a `#[must_use]` function
|
||||
--> $DIR/let_underscore_must_use.rs:80:5
|
||||
--> $DIR/let_underscore_must_use.rs:81:5
|
||||
|
|
||||
LL | let _ = S::a();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -64,7 +64,7 @@ LL | let _ = S::a();
|
||||
= help: consider explicitly using function result
|
||||
|
||||
error: non-binding let on an expression with `#[must_use]` type
|
||||
--> $DIR/let_underscore_must_use.rs:82:5
|
||||
--> $DIR/let_underscore_must_use.rs:83:5
|
||||
|
|
||||
LL | let _ = if true { Ok(()) } else { Err(()) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -72,7 +72,7 @@ LL | let _ = if true { Ok(()) } else { Err(()) };
|
||||
= help: consider explicitly using expression value
|
||||
|
||||
error: non-binding let on a result of a `#[must_use]` function
|
||||
--> $DIR/let_underscore_must_use.rs:86:5
|
||||
--> $DIR/let_underscore_must_use.rs:87:5
|
||||
|
|
||||
LL | let _ = a.is_ok();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@ -80,7 +80,7 @@ LL | let _ = a.is_ok();
|
||||
= help: consider explicitly using function result
|
||||
|
||||
error: non-binding let on an expression with `#[must_use]` type
|
||||
--> $DIR/let_underscore_must_use.rs:88:5
|
||||
--> $DIR/let_underscore_must_use.rs:89:5
|
||||
|
|
||||
LL | let _ = a.map(|_| ());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -88,7 +88,7 @@ LL | let _ = a.map(|_| ());
|
||||
= help: consider explicitly using expression value
|
||||
|
||||
error: non-binding let on an expression with `#[must_use]` type
|
||||
--> $DIR/let_underscore_must_use.rs:90:5
|
||||
--> $DIR/let_underscore_must_use.rs:91:5
|
||||
|
|
||||
LL | let _ = a;
|
||||
| ^^^^^^^^^^
|
||||
|
@ -7,7 +7,19 @@ use std::future::Future;
|
||||
|
||||
async fn fut() -> i32 { 42 }
|
||||
|
||||
async fn empty_fut() {}
|
||||
#[rustfmt::skip]
|
||||
async fn fut2() -> i32 { 42 }
|
||||
|
||||
#[rustfmt::skip]
|
||||
async fn fut3() -> i32 { 42 }
|
||||
|
||||
async fn empty_fut() {}
|
||||
|
||||
#[rustfmt::skip]
|
||||
async fn empty_fut2() {}
|
||||
|
||||
#[rustfmt::skip]
|
||||
async fn empty_fut3() {}
|
||||
|
||||
async fn core_fut() -> i32 { 42 }
|
||||
|
||||
|
@ -9,10 +9,30 @@ fn fut() -> impl Future<Output = i32> {
|
||||
async { 42 }
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn fut2() ->impl Future<Output = i32> {
|
||||
async { 42 }
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn fut3()-> impl Future<Output = i32> {
|
||||
async { 42 }
|
||||
}
|
||||
|
||||
fn empty_fut() -> impl Future<Output = ()> {
|
||||
async {}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn empty_fut2() ->impl Future<Output = ()> {
|
||||
async {}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn empty_fut3()-> impl Future<Output = ()> {
|
||||
async {}
|
||||
}
|
||||
|
||||
fn core_fut() -> impl core::future::Future<Output = i32> {
|
||||
async move { 42 }
|
||||
}
|
||||
|
@ -15,14 +15,44 @@ LL | fn fut() -> impl Future<Output = i32> { 42 }
|
||||
| ^^^^^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:12:1
|
||||
--> $DIR/manual_async_fn.rs:13:1
|
||||
|
|
||||
LL | fn fut2() ->impl Future<Output = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function `async` and return the output of the future directly
|
||||
|
|
||||
LL | async fn fut2() -> i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: move the body of the async block to the enclosing function
|
||||
|
|
||||
LL | fn fut2() ->impl Future<Output = i32> { 42 }
|
||||
| ^^^^^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:18:1
|
||||
|
|
||||
LL | fn fut3()-> impl Future<Output = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function `async` and return the output of the future directly
|
||||
|
|
||||
LL | async fn fut3() -> i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: move the body of the async block to the enclosing function
|
||||
|
|
||||
LL | fn fut3()-> impl Future<Output = i32> { 42 }
|
||||
| ^^^^^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:22:1
|
||||
|
|
||||
LL | fn empty_fut() -> impl Future<Output = ()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function `async` and remove the return type
|
||||
|
|
||||
LL | async fn empty_fut() {
|
||||
LL | async fn empty_fut() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
help: move the body of the async block to the enclosing function
|
||||
|
|
||||
@ -30,7 +60,37 @@ LL | fn empty_fut() -> impl Future<Output = ()> {}
|
||||
| ^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:16:1
|
||||
--> $DIR/manual_async_fn.rs:27:1
|
||||
|
|
||||
LL | fn empty_fut2() ->impl Future<Output = ()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function `async` and remove the return type
|
||||
|
|
||||
LL | async fn empty_fut2() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
help: move the body of the async block to the enclosing function
|
||||
|
|
||||
LL | fn empty_fut2() ->impl Future<Output = ()> {}
|
||||
| ^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:32:1
|
||||
|
|
||||
LL | fn empty_fut3()-> impl Future<Output = ()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: make the function `async` and remove the return type
|
||||
|
|
||||
LL | async fn empty_fut3() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
help: move the body of the async block to the enclosing function
|
||||
|
|
||||
LL | fn empty_fut3()-> impl Future<Output = ()> {}
|
||||
| ^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:36:1
|
||||
|
|
||||
LL | fn core_fut() -> impl core::future::Future<Output = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -45,7 +105,7 @@ LL | fn core_fut() -> impl core::future::Future<Output = i32> { 42 }
|
||||
| ^^^^^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:38:5
|
||||
--> $DIR/manual_async_fn.rs:58:5
|
||||
|
|
||||
LL | fn inh_fut() -> impl Future<Output = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -65,7 +125,7 @@ LL | let c = 21;
|
||||
...
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:73:1
|
||||
--> $DIR/manual_async_fn.rs:93:1
|
||||
|
|
||||
LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -80,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ { 42 }
|
||||
| ^^^^^^
|
||||
|
||||
error: this function can be simplified using the `async fn` syntax
|
||||
--> $DIR/manual_async_fn.rs:82:1
|
||||
--> $DIR/manual_async_fn.rs:102:1
|
||||
|
|
||||
LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -94,5 +154,5 @@ help: move the body of the async block to the enclosing function
|
||||
LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { 42 }
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
@ -28,7 +28,7 @@ fn main() {
|
||||
// not applicable, or side isn't `Result::Err`
|
||||
foo.map_or(Ok::<i32, &str>(1), |v| Ok(v));
|
||||
|
||||
// not applicatble, expr is not a `Result` value
|
||||
// not applicable, expr is not a `Result` value
|
||||
foo.map_or(42, |v| v);
|
||||
|
||||
// TODO patterns not covered yet
|
||||
|
@ -32,7 +32,7 @@ fn main() {
|
||||
// not applicable, or side isn't `Result::Err`
|
||||
foo.map_or(Ok::<i32, &str>(1), |v| Ok(v));
|
||||
|
||||
// not applicatble, expr is not a `Result` value
|
||||
// not applicable, expr is not a `Result` value
|
||||
foo.map_or(42, |v| v);
|
||||
|
||||
// TODO patterns not covered yet
|
||||
|
@ -1,6 +1,6 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
||||
|
||||
fn option_unwrap_or() {
|
||||
// int case
|
||||
|
@ -1,6 +1,6 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
||||
|
||||
fn option_unwrap_or() {
|
||||
// int case
|
||||
|
@ -2,6 +2,7 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(clippy::iter_cloned_collect)]
|
||||
#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
|
||||
#![allow(clippy::let_underscore_drop)]
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::redundant_closure_for_method_calls)]
|
||||
#![allow(clippy::many_single_char_names)]
|
||||
@ -44,4 +45,19 @@ fn main() {
|
||||
let v = vec![&mut d];
|
||||
let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
|
||||
}
|
||||
|
||||
// Issue #6299
|
||||
{
|
||||
let mut aa = 5;
|
||||
let mut bb = 3;
|
||||
let items = vec![&mut aa, &mut bb];
|
||||
let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect();
|
||||
}
|
||||
|
||||
// Issue #6239 deref coercion and clone deref
|
||||
{
|
||||
use std::cell::RefCell;
|
||||
|
||||
let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(clippy::iter_cloned_collect)]
|
||||
#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
|
||||
#![allow(clippy::let_underscore_drop)]
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::redundant_closure_for_method_calls)]
|
||||
#![allow(clippy::many_single_char_names)]
|
||||
@ -44,4 +45,19 @@ fn main() {
|
||||
let v = vec![&mut d];
|
||||
let _: Vec<u32> = v.into_iter().map(|&mut x| x).collect();
|
||||
}
|
||||
|
||||
// Issue #6299
|
||||
{
|
||||
let mut aa = 5;
|
||||
let mut bb = 3;
|
||||
let items = vec![&mut aa, &mut bb];
|
||||
let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect();
|
||||
}
|
||||
|
||||
// Issue #6239 deref coercion and clone deref
|
||||
{
|
||||
use std::cell::RefCell;
|
||||
|
||||
let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: you are using an explicit closure for copying elements
|
||||
--> $DIR/map_clone.rs:10:22
|
||||
--> $DIR/map_clone.rs:11:22
|
||||
|
|
||||
LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
|
||||
@ -7,31 +7,31 @@ LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
|
||||
= note: `-D clippy::map-clone` implied by `-D warnings`
|
||||
|
||||
error: you are using an explicit closure for cloning elements
|
||||
--> $DIR/map_clone.rs:11:26
|
||||
--> $DIR/map_clone.rs:12:26
|
||||
|
|
||||
LL | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
|
||||
|
||||
error: you are using an explicit closure for copying elements
|
||||
--> $DIR/map_clone.rs:12:23
|
||||
--> $DIR/map_clone.rs:13:23
|
||||
|
|
||||
LL | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
|
||||
|
||||
error: you are using an explicit closure for copying elements
|
||||
--> $DIR/map_clone.rs:14:26
|
||||
--> $DIR/map_clone.rs:15:26
|
||||
|
|
||||
LL | let _: Option<u64> = Some(&16).map(|b| *b);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
|
||||
|
||||
error: you are using an explicit closure for copying elements
|
||||
--> $DIR/map_clone.rs:15:25
|
||||
--> $DIR/map_clone.rs:16:25
|
||||
|
|
||||
LL | let _: Option<u8> = Some(&1).map(|x| x.clone());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
|
||||
|
||||
error: you are needlessly cloning iterator elements
|
||||
--> $DIR/map_clone.rs:26:29
|
||||
--> $DIR/map_clone.rs:27:29
|
||||
|
|
||||
LL | let _ = std::env::args().map(|v| v.clone());
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![warn(clippy::map_err_ignore)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
use std::convert::TryFrom;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: `map_err(|_|...` ignores the original error
|
||||
--> $DIR/map_err.rs:22:32
|
||||
--> $DIR/map_err.rs:23:32
|
||||
|
|
||||
LL | println!("{:?}", x.map_err(|_| Errors::Ignored));
|
||||
| ^^^
|
||||
|
@ -1,8 +1,10 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(clippy::let_underscore_drop)]
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
fn main() {
|
||||
// mapping to Option on Iterator
|
||||
|
@ -1,8 +1,10 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(clippy::let_underscore_drop)]
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
fn main() {
|
||||
// mapping to Option on Iterator
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:14:46
|
||||
--> $DIR/map_flatten.rs:16:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)`
|
||||
@ -7,31 +7,31 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll
|
||||
= note: `-D clippy::map-flatten` implied by `-D warnings`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:15:46
|
||||
--> $DIR/map_flatten.rs:17:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:16:46
|
||||
--> $DIR/map_flatten.rs:18:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:17:46
|
||||
--> $DIR/map_flatten.rs:19:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:20:46
|
||||
--> $DIR/map_flatten.rs:22:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Option`
|
||||
--> $DIR/map_flatten.rs:23:39
|
||||
--> $DIR/map_flatten.rs:25:39
|
||||
|
|
||||
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
|
||||
|
@ -133,50 +133,6 @@ fn filter_next() {
|
||||
let _ = foo.filter().next();
|
||||
}
|
||||
|
||||
/// Checks implementation of `SEARCH_IS_SOME` lint.
|
||||
#[rustfmt::skip]
|
||||
fn search_is_some() {
|
||||
let v = vec![3, 2, 1, 0, -1, -2, -3];
|
||||
let y = &&42;
|
||||
|
||||
// Check `find().is_some()`, single-line case.
|
||||
let _ = v.iter().find(|&x| *x < 0).is_some();
|
||||
let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
|
||||
let _ = (0..1).find(|x| *x == 0).is_some();
|
||||
let _ = v.iter().find(|x| **x == 0).is_some();
|
||||
|
||||
// Check `find().is_some()`, multi-line case.
|
||||
let _ = v.iter().find(|&x| {
|
||||
*x < 0
|
||||
}
|
||||
).is_some();
|
||||
|
||||
// Check `position().is_some()`, single-line case.
|
||||
let _ = v.iter().position(|&x| x < 0).is_some();
|
||||
|
||||
// Check `position().is_some()`, multi-line case.
|
||||
let _ = v.iter().position(|&x| {
|
||||
x < 0
|
||||
}
|
||||
).is_some();
|
||||
|
||||
// Check `rposition().is_some()`, single-line case.
|
||||
let _ = v.iter().rposition(|&x| x < 0).is_some();
|
||||
|
||||
// Check `rposition().is_some()`, multi-line case.
|
||||
let _ = v.iter().rposition(|&x| {
|
||||
x < 0
|
||||
}
|
||||
).is_some();
|
||||
|
||||
// Check that we don't lint if the caller is not an `Iterator`.
|
||||
let foo = IteratorFalsePositives { foo: 0 };
|
||||
let _ = foo.find().is_some();
|
||||
let _ = foo.position().is_some();
|
||||
let _ = foo.rposition().is_some();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
filter_next();
|
||||
search_is_some();
|
||||
}
|
||||
|
@ -20,73 +20,5 @@ LL | | ).next();
|
||||
|
|
||||
= note: `-D clippy::filter-next` implied by `-D warnings`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:143:22
|
||||
|
|
||||
LL | let _ = v.iter().find(|&x| *x < 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
|
||||
|
|
||||
= note: `-D clippy::search-is-some` implied by `-D warnings`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:144:20
|
||||
|
|
||||
LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:145:20
|
||||
|
|
||||
LL | let _ = (0..1).find(|x| *x == 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:146:22
|
||||
|
|
||||
LL | let _ = v.iter().find(|x| **x == 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:149:13
|
||||
|
|
||||
LL | let _ = v.iter().find(|&x| {
|
||||
| _____________^
|
||||
LL | | *x < 0
|
||||
LL | | }
|
||||
LL | | ).is_some();
|
||||
| |______________________________^
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:155:22
|
||||
|
|
||||
LL | let _ = v.iter().position(|&x| x < 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:158:13
|
||||
|
|
||||
LL | let _ = v.iter().position(|&x| {
|
||||
| _____________^
|
||||
LL | | x < 0
|
||||
LL | | }
|
||||
LL | | ).is_some();
|
||||
| |______________________________^
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:164:22
|
||||
|
|
||||
LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
||||
|
||||
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
||||
--> $DIR/methods.rs:167:13
|
||||
|
|
||||
LL | let _ = v.iter().rposition(|&x| {
|
||||
| _____________^
|
||||
LL | | x < 0
|
||||
LL | | }
|
||||
LL | | ).is_some();
|
||||
| |______________________________^
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![warn(clippy::needless_lifetimes)]
|
||||
#![allow(dead_code, clippy::needless_pass_by_value)]
|
||||
#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)]
|
||||
|
||||
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#![warn(clippy::option_map_unit_fn)]
|
||||
#![allow(unused)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
fn do_nothing<T>(_: T) {}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#![warn(clippy::option_map_unit_fn)]
|
||||
#![allow(unused)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
fn do_nothing<T>(_: T) {}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:38:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:39:5
|
||||
|
|
||||
LL | x.field.map(do_nothing);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -9,7 +9,7 @@ LL | x.field.map(do_nothing);
|
||||
= note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:40:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:41:5
|
||||
|
|
||||
LL | x.field.map(do_nothing);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -17,7 +17,7 @@ LL | x.field.map(do_nothing);
|
||||
| help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:42:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:43:5
|
||||
|
|
||||
LL | x.field.map(diverge);
|
||||
| ^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -25,7 +25,7 @@ LL | x.field.map(diverge);
|
||||
| help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:48:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:49:5
|
||||
|
|
||||
LL | x.field.map(|value| x.do_option_nothing(value + captured));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured));
|
||||
| help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:50:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:51:5
|
||||
|
|
||||
LL | x.field.map(|value| { x.do_option_plus_one(value + captured); });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); });
|
||||
| help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:53:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:54:5
|
||||
|
|
||||
LL | x.field.map(|value| do_nothing(value + captured));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured));
|
||||
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:55:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:56:5
|
||||
|
|
||||
LL | x.field.map(|value| { do_nothing(value + captured) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) });
|
||||
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:57:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:58:5
|
||||
|
|
||||
LL | x.field.map(|value| { do_nothing(value + captured); });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); });
|
||||
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:59:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:60:5
|
||||
|
|
||||
LL | x.field.map(|value| { { do_nothing(value + captured); } });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } });
|
||||
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:62:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:63:5
|
||||
|
|
||||
LL | x.field.map(|value| diverge(value + captured));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured));
|
||||
| help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:64:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:65:5
|
||||
|
|
||||
LL | x.field.map(|value| { diverge(value + captured) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) });
|
||||
| help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:66:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:67:5
|
||||
|
|
||||
LL | x.field.map(|value| { diverge(value + captured); });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); });
|
||||
| help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:68:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:69:5
|
||||
|
|
||||
LL | x.field.map(|value| { { diverge(value + captured); } });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } });
|
||||
| help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:73:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:74:5
|
||||
|
|
||||
LL | x.field.map(|value| { let y = plus_one(value + captured); });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); });
|
||||
| help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:75:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:76:5
|
||||
|
|
||||
LL | x.field.map(|value| { plus_one(value + captured); });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); });
|
||||
| help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:77:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:78:5
|
||||
|
|
||||
LL | x.field.map(|value| { { plus_one(value + captured); } });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } });
|
||||
| help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:80:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:81:5
|
||||
|
|
||||
LL | x.field.map(|ref value| { do_nothing(value + captured) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) });
|
||||
| help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
|
||||
|
||||
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:82:5
|
||||
--> $DIR/option_map_unit_fn_fixable.rs:83:5
|
||||
|
|
||||
LL | option().map(do_nothing);}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^-
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![deny(clippy::option_option)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
fn input(_: Option<Option<u8>>) {}
|
||||
|
||||
@ -72,8 +73,6 @@ mod issue_4298 {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(borrow)]
|
||||
// FIXME: should not lint here
|
||||
#[allow(clippy::option_option)]
|
||||
foo: Option<Option<Cow<'a, str>>>,
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:3:13
|
||||
--> $DIR/option_option.rs:4:13
|
||||
|
|
||||
LL | fn input(_: Option<Option<u8>>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@ -11,55 +11,55 @@ LL | #![deny(clippy::option_option)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:5:16
|
||||
--> $DIR/option_option.rs:6:16
|
||||
|
|
||||
LL | fn output() -> Option<Option<u8>> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:9:27
|
||||
--> $DIR/option_option.rs:10:27
|
||||
|
|
||||
LL | fn output_nested() -> Vec<Option<Option<u8>>> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:14:30
|
||||
--> $DIR/option_option.rs:15:30
|
||||
|
|
||||
LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:19:8
|
||||
--> $DIR/option_option.rs:20:8
|
||||
|
|
||||
LL | x: Option<Option<u8>>,
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:23:23
|
||||
--> $DIR/option_option.rs:24:23
|
||||
|
|
||||
LL | fn struct_fn() -> Option<Option<u8>> {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:29:22
|
||||
--> $DIR/option_option.rs:30:22
|
||||
|
|
||||
LL | fn trait_fn() -> Option<Option<u8>>;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:33:11
|
||||
--> $DIR/option_option.rs:34:11
|
||||
|
|
||||
LL | Tuple(Option<Option<u8>>),
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:34:17
|
||||
--> $DIR/option_option.rs:35:17
|
||||
|
|
||||
LL | Struct { x: Option<Option<u8>> },
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
|
||||
--> $DIR/option_option.rs:77:14
|
||||
--> $DIR/option_option.rs:76:14
|
||||
|
|
||||
LL | foo: Option<Option<Cow<'a, str>>>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#![warn(clippy::or_fun_call)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
@ -70,6 +71,15 @@ fn or_fun_call() {
|
||||
let opt = Some(1);
|
||||
let hello = "Hello";
|
||||
let _ = opt.ok_or(format!("{} world.", hello));
|
||||
|
||||
// index
|
||||
let map = HashMap::<u64, u64>::new();
|
||||
let _ = Some(1).unwrap_or_else(|| map[&1]);
|
||||
let map = BTreeMap::<u64, u64>::new();
|
||||
let _ = Some(1).unwrap_or_else(|| map[&1]);
|
||||
// don't lint index vec
|
||||
let vec = vec![1];
|
||||
let _ = Some(1).unwrap_or(vec[1]);
|
||||
}
|
||||
|
||||
struct Foo(u8);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user