mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-21 20:23:12 +00:00
Merge commit '4bdfb0741dbcecd5279a2635c3280726db0604b5' into clippyup
This commit is contained in:
parent
cfe1e040e7
commit
1c422524c7
127 changed files with 2710 additions and 605 deletions
7
.github/workflows/clippy_bors.yml
vendored
7
.github/workflows/clippy_bors.yml
vendored
|
@ -82,13 +82,6 @@ jobs:
|
|||
with:
|
||||
github_token: "${{ secrets.github_token }}"
|
||||
|
||||
- name: Install dependencies (Linux-i686)
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-multilib libssl-dev:i386 libgit2-dev:i386
|
||||
if: matrix.host == 'i686-unknown-linux-gnu'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3.0.2
|
||||
|
||||
|
|
177
CHANGELOG.md
177
CHANGELOG.md
|
@ -6,11 +6,181 @@ document.
|
|||
|
||||
## Unreleased / Beta / In Rust Nightly
|
||||
|
||||
[b52fb523...master](https://github.com/rust-lang/rust-clippy/compare/b52fb523...master)
|
||||
[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
|
||||
|
||||
## Rust 1.66
|
||||
|
||||
Current stable, released 2022-12-15
|
||||
|
||||
[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
|
||||
|
||||
### New Lints
|
||||
|
||||
* [`manual_clamp`]
|
||||
[#9484](https://github.com/rust-lang/rust-clippy/pull/9484)
|
||||
* [`missing_trait_methods`]
|
||||
[#9670](https://github.com/rust-lang/rust-clippy/pull/9670)
|
||||
* [`unused_format_specs`]
|
||||
[#9637](https://github.com/rust-lang/rust-clippy/pull/9637)
|
||||
* [`iter_kv_map`]
|
||||
[#9409](https://github.com/rust-lang/rust-clippy/pull/9409)
|
||||
* [`manual_filter`]
|
||||
[#9451](https://github.com/rust-lang/rust-clippy/pull/9451)
|
||||
* [`box_default`]
|
||||
[#9511](https://github.com/rust-lang/rust-clippy/pull/9511)
|
||||
* [`implicit_saturating_add`]
|
||||
[#9549](https://github.com/rust-lang/rust-clippy/pull/9549)
|
||||
* [`as_ptr_cast_mut`]
|
||||
[#9572](https://github.com/rust-lang/rust-clippy/pull/9572)
|
||||
* [`disallowed_macros`]
|
||||
[#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
|
||||
* [`partial_pub_fields`]
|
||||
[#9658](https://github.com/rust-lang/rust-clippy/pull/9658)
|
||||
* [`uninlined_format_args`]
|
||||
[#9233](https://github.com/rust-lang/rust-clippy/pull/9233)
|
||||
* [`cast_nan_to_int`]
|
||||
[#9617](https://github.com/rust-lang/rust-clippy/pull/9617)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* `positional_named_format_parameters` was uplifted to rustc under the new name
|
||||
`named_arguments_used_positionally`
|
||||
[#8518](https://github.com/rust-lang/rust-clippy/pull/8518)
|
||||
* Moved [`implicit_saturating_sub`] to `style` (Now warn-by-default)
|
||||
[#9584](https://github.com/rust-lang/rust-clippy/pull/9584)
|
||||
* Moved `derive_partial_eq_without_eq` to `nursery` (now allow-by-default)
|
||||
[#9536](https://github.com/rust-lang/rust-clippy/pull/9536)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`nonstandard_macro_braces`]: Now includes `matches!()` in the default lint config
|
||||
[#9471](https://github.com/rust-lang/rust-clippy/pull/9471)
|
||||
* [`suboptimal_flops`]: Now supports multiplication and subtraction operations
|
||||
[#9581](https://github.com/rust-lang/rust-clippy/pull/9581)
|
||||
* [`arithmetic_side_effects`]: Now detects cases with literals behind references
|
||||
[#9587](https://github.com/rust-lang/rust-clippy/pull/9587)
|
||||
* [`upper_case_acronyms`]: Now also checks enum names
|
||||
[#9580](https://github.com/rust-lang/rust-clippy/pull/9580)
|
||||
* [`needless_borrowed_reference`]: Now lints nested patterns
|
||||
[#9573](https://github.com/rust-lang/rust-clippy/pull/9573)
|
||||
* [`unnecessary_cast`]: Now works for non-trivial non-literal expressions
|
||||
[#9576](https://github.com/rust-lang/rust-clippy/pull/9576)
|
||||
* [`arithmetic_side_effects`]: Now detects operations with custom types
|
||||
[#9559](https://github.com/rust-lang/rust-clippy/pull/9559)
|
||||
* [`disallowed_methods`], [`disallowed_types`]: Not correctly lints types, functions and macros
|
||||
with the same path
|
||||
[#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
|
||||
* [`self_named_module_files`], [`mod_module_files`]: Now take remapped path prefixes into account
|
||||
[#9475](https://github.com/rust-lang/rust-clippy/pull/9475)
|
||||
* [`bool_to_int_with_if`]: Now detects the inverse if case
|
||||
[#9476](https://github.com/rust-lang/rust-clippy/pull/9476)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`arithmetic_side_effects`]: Now allows operations that can't overflow
|
||||
[#9474](https://github.com/rust-lang/rust-clippy/pull/9474)
|
||||
* [`unnecessary_lazy_evaluations`]: No longer lints in external macros
|
||||
[#9486](https://github.com/rust-lang/rust-clippy/pull/9486)
|
||||
* [`needless_borrow`], [`explicit_auto_deref`]: No longer lint on unions that require the reference
|
||||
[#9490](https://github.com/rust-lang/rust-clippy/pull/9490)
|
||||
* [`almost_complete_letter_range`]: No longer lints in external macros
|
||||
[#9467](https://github.com/rust-lang/rust-clippy/pull/9467)
|
||||
* [`drop_copy`]: No longer lints on idiomatic cases in match arms
|
||||
[#9491](https://github.com/rust-lang/rust-clippy/pull/9491)
|
||||
* [`question_mark`]: No longer lints in const context
|
||||
[#9487](https://github.com/rust-lang/rust-clippy/pull/9487)
|
||||
* [`collapsible_if`]: Suggestion now work in macros
|
||||
[#9410](https://github.com/rust-lang/rust-clippy/pull/9410)
|
||||
* [`std_instead_of_core`]: No longer triggers on unstable modules
|
||||
[#9545](https://github.com/rust-lang/rust-clippy/pull/9545)
|
||||
* [`unused_peekable`]: No longer lints, if the peak is done in a closure or function
|
||||
[#9465](https://github.com/rust-lang/rust-clippy/pull/9465)
|
||||
* [`useless_attribute`]: No longer lints on `#[allow]` attributes for [`unsafe_removed_from_name`]
|
||||
[#9593](https://github.com/rust-lang/rust-clippy/pull/9593)
|
||||
* [`unnecessary_lazy_evaluations`]: No longer suggest switching to early evaluation when type has
|
||||
custom `Drop` implementation
|
||||
[#9551](https://github.com/rust-lang/rust-clippy/pull/9551)
|
||||
* [`unnecessary_cast`]: No longer lints on negative hexadecimal literals when cast as floats
|
||||
[#9609](https://github.com/rust-lang/rust-clippy/pull/9609)
|
||||
* [`use_self`]: No longer lints in proc macros
|
||||
[#9454](https://github.com/rust-lang/rust-clippy/pull/9454)
|
||||
* [`never_loop`]: Now takes `let ... else` statements into consideration.
|
||||
[#9496](https://github.com/rust-lang/rust-clippy/pull/9496)
|
||||
* [`default_numeric_fallback`]: Now ignores constants
|
||||
[#9636](https://github.com/rust-lang/rust-clippy/pull/9636)
|
||||
* [`uninit_vec`]: No longer lints `Vec::set_len(0)`
|
||||
[#9519](https://github.com/rust-lang/rust-clippy/pull/9519)
|
||||
* [`arithmetic_side_effects`]: Now ignores references to integer types
|
||||
[#9507](https://github.com/rust-lang/rust-clippy/pull/9507)
|
||||
* [`large_stack_arrays`]: No longer lints inside static items
|
||||
[#9466](https://github.com/rust-lang/rust-clippy/pull/9466)
|
||||
* [`ref_option_ref`]: No longer lints if the inner reference is mutable
|
||||
[#9684](https://github.com/rust-lang/rust-clippy/pull/9684)
|
||||
* [`ptr_arg`]: No longer lints if the argument is used as an incomplete trait object
|
||||
[#9645](https://github.com/rust-lang/rust-clippy/pull/9645)
|
||||
* [`should_implement_trait`]: Now also works for `default` methods
|
||||
[#9546](https://github.com/rust-lang/rust-clippy/pull/9546)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`derivable_impls`]: The suggestion is now machine applicable
|
||||
[#9429](https://github.com/rust-lang/rust-clippy/pull/9429)
|
||||
* [`match_single_binding`]: The suggestion now handles scrutinies with side effects better
|
||||
[#9601](https://github.com/rust-lang/rust-clippy/pull/9601)
|
||||
* [`zero_prefixed_literal`]: Only suggests using octal numbers, if this is possible
|
||||
[#9652](https://github.com/rust-lang/rust-clippy/pull/9652)
|
||||
* [`rc_buffer`]: The suggestion is no longer machine applicable to avoid semantic changes
|
||||
[#9633](https://github.com/rust-lang/rust-clippy/pull/9633)
|
||||
* [`print_literal`], [`write_literal`], [`uninlined_format_args`]: The suggestion now ignores
|
||||
comments after the macro call.
|
||||
[#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
|
||||
* [`expect_fun_call`]:Improved the suggestion for `format!` calls with captured variables
|
||||
[#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
|
||||
* [`nonstandard_macro_braces`]: The suggestion is now machine applicable and will no longer
|
||||
replace brackets inside the macro argument.
|
||||
[#9499](https://github.com/rust-lang/rust-clippy/pull/9499)
|
||||
* [`from_over_into`]: The suggestion is now a machine applicable and contains explanations
|
||||
[#9649](https://github.com/rust-lang/rust-clippy/pull/9649)
|
||||
* [`needless_return`]: The automatic suggestion now removes all required semicolons
|
||||
[#9497](https://github.com/rust-lang/rust-clippy/pull/9497)
|
||||
* [`to_string_in_format_args`]: The suggestion now keeps parenthesis around values
|
||||
[#9590](https://github.com/rust-lang/rust-clippy/pull/9590)
|
||||
* [`manual_assert`]: The suggestion now preserves comments
|
||||
[#9479](https://github.com/rust-lang/rust-clippy/pull/9479)
|
||||
* [`redundant_allocation`]: The suggestion applicability is now marked `MaybeIncorrect` to
|
||||
avoid semantic changes
|
||||
[#9634](https://github.com/rust-lang/rust-clippy/pull/9634)
|
||||
* [`assertions_on_result_states`]: The suggestion has been corrected, for cases where the
|
||||
`assert!` is not in a statement.
|
||||
[#9453](https://github.com/rust-lang/rust-clippy/pull/9453)
|
||||
* [`nonminimal_bool`]: The suggestion no longer expands macros
|
||||
[#9457](https://github.com/rust-lang/rust-clippy/pull/9457)
|
||||
* [`collapsible_match`]: Now specifies field names, when a struct is destructed
|
||||
[#9685](https://github.com/rust-lang/rust-clippy/pull/9685)
|
||||
* [`unnecessary_cast`]: The suggestion now adds parenthesis for negative numbers
|
||||
[#9577](https://github.com/rust-lang/rust-clippy/pull/9577)
|
||||
* [`redundant_closure`]: The suggestion now works for `impl FnMut` arguments
|
||||
[#9556](https://github.com/rust-lang/rust-clippy/pull/9556)
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
|
||||
[#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
|
||||
* [`manual_range_contains`]: No longer ICEs on values behind references
|
||||
[#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
|
||||
* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
|
||||
[#9531](https://github.com/rust-lang/rust-clippy/pull/9531)
|
||||
* `*_interior_mutable_const` lints: no longer ICE on const unions containing `!Freeze` types
|
||||
[#9539](https://github.com/rust-lang/rust-clippy/pull/9539)
|
||||
|
||||
### Others
|
||||
|
||||
* Released `rustc_tools_util` for version information on `Crates.io`. (Further adjustments will
|
||||
not be published as part of this changelog)
|
||||
|
||||
## Rust 1.65
|
||||
|
||||
Current stable, released 2022-11-03
|
||||
Released 2022-11-03
|
||||
|
||||
[3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523)
|
||||
|
||||
|
@ -3875,6 +4045,7 @@ Released 2018-09-13
|
|||
[`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
|
||||
[`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
|
||||
[`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
|
||||
[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
|
||||
[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
|
||||
[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
|
||||
[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
|
||||
|
@ -4353,6 +4524,8 @@ Released 2018-09-13
|
|||
[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
|
||||
[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
|
||||
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
|
||||
[`semicolon_inside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block
|
||||
[`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block
|
||||
[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
|
||||
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
|
||||
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
@ -23,7 +23,7 @@ path = "src/driver.rs"
|
|||
[dependencies]
|
||||
clippy_lints = { path = "clippy_lints" }
|
||||
semver = "1.0"
|
||||
rustc_tools_util = "0.2.1"
|
||||
rustc_tools_util = "0.3.0"
|
||||
tempfile = { version = "3.2", optional = true }
|
||||
termize = "0.1"
|
||||
|
||||
|
@ -55,7 +55,7 @@ tokio = { version = "1", features = ["io-util"] }
|
|||
rustc-semver = "1.1"
|
||||
|
||||
[build-dependencies]
|
||||
rustc_tools_util = "0.2.1"
|
||||
rustc_tools_util = "0.3.0"
|
||||
|
||||
[features]
|
||||
deny-warnings = ["clippy_lints/deny-warnings"]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Clippy
|
||||
|
||||
[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
|
||||
[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto)
|
||||
[![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
|
||||
|
||||
A collection of lints to catch common mistakes and improve your
|
||||
|
|
14
build.rs
14
build.rs
|
@ -3,17 +3,5 @@ fn main() {
|
|||
println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap());
|
||||
// Don't rebuild even if nothing changed
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
// forward git repo hashes we build at
|
||||
println!(
|
||||
"cargo:rustc-env=GIT_HASH={}",
|
||||
rustc_tools_util::get_commit_hash().unwrap_or_default()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=COMMIT_DATE={}",
|
||||
rustc_tools_util::get_commit_date().unwrap_or_default()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
|
||||
rustc_tools_util::get_channel()
|
||||
);
|
||||
rustc_tools_util::setup_version_info!();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -10,8 +10,8 @@ use rustc_span::Span;
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
|
||||
/// don't because they're a half open range.
|
||||
/// Checks for ranges which almost include the entire range of letters from 'a' to 'z'
|
||||
/// or digits from '0' to '9', but don't because they're a half open range.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
|
||||
|
@ -25,21 +25,21 @@ declare_clippy_lint! {
|
|||
/// let _ = 'a'..='z';
|
||||
/// ```
|
||||
#[clippy::version = "1.63.0"]
|
||||
pub ALMOST_COMPLETE_LETTER_RANGE,
|
||||
pub ALMOST_COMPLETE_RANGE,
|
||||
suspicious,
|
||||
"almost complete letter range"
|
||||
"almost complete range"
|
||||
}
|
||||
impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]);
|
||||
impl_lint_pass!(AlmostCompleteRange => [ALMOST_COMPLETE_RANGE]);
|
||||
|
||||
pub struct AlmostCompleteLetterRange {
|
||||
pub struct AlmostCompleteRange {
|
||||
msrv: Msrv,
|
||||
}
|
||||
impl AlmostCompleteLetterRange {
|
||||
impl AlmostCompleteRange {
|
||||
pub fn new(msrv: Msrv) -> Self {
|
||||
Self { msrv }
|
||||
}
|
||||
}
|
||||
impl EarlyLintPass for AlmostCompleteLetterRange {
|
||||
impl EarlyLintPass for AlmostCompleteRange {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
|
||||
if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
|
||||
let ctxt = e.span.ctxt();
|
||||
|
@ -87,14 +87,18 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg
|
|||
Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
|
||||
Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
|
||||
)
|
||||
| (
|
||||
Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
|
||||
Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
|
||||
)
|
||||
)
|
||||
&& !in_external_macro(cx.sess(), span)
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
ALMOST_COMPLETE_LETTER_RANGE,
|
||||
ALMOST_COMPLETE_RANGE,
|
||||
span,
|
||||
"almost complete ascii letter range",
|
||||
"almost complete ascii range",
|
||||
|diag| {
|
||||
if let Some((span, sugg)) = sugg {
|
||||
diag.span_suggestion(
|
|
@ -30,7 +30,7 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let x: Box<String> = Box::default();
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub BOX_DEFAULT,
|
||||
perf,
|
||||
"Using Box::new(T::default()) instead of Box::default()"
|
||||
|
|
|
@ -641,7 +641,7 @@ declare_clippy_lint! {
|
|||
/// ```rust,ignore
|
||||
/// let _: = 0_u64;
|
||||
/// ```
|
||||
#[clippy::version = "1.64.0"]
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub CAST_NAN_TO_INT,
|
||||
suspicious,
|
||||
"casting a known floating-point NaN into an integer"
|
||||
|
|
|
@ -35,7 +35,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
|
||||
#[cfg(feature = "internal")]
|
||||
crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
|
||||
crate::almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE_INFO,
|
||||
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
|
||||
crate::approx_const::APPROX_CONSTANT_INFO,
|
||||
crate::as_conversions::AS_CONVERSIONS_INFO,
|
||||
crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
|
||||
|
@ -525,6 +525,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::returns::NEEDLESS_RETURN_INFO,
|
||||
crate::same_name_method::SAME_NAME_METHOD_INFO,
|
||||
crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
|
||||
crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
|
||||
crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO,
|
||||
crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
|
||||
crate::serde_api::SERDE_API_MISUSE_INFO,
|
||||
crate::shadow::SHADOW_REUSE_INFO,
|
||||
|
|
|
@ -1390,10 +1390,15 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
|
|||
continue;
|
||||
},
|
||||
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||
ty::Alias(ty::Projection, _) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||
ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Alias(ty::Opaque, ..) | ty::Placeholder(_) | ty::Dynamic(..) => {
|
||||
Position::ReborrowStable(precedence).into()
|
||||
ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
|
||||
TyPosition::new_deref_stable_for_result(precedence, ty)
|
||||
},
|
||||
ty::Infer(_)
|
||||
| ty::Error(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Alias(ty::Opaque, ..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
|
||||
ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
|
||||
Position::ReborrowStable(precedence).into()
|
||||
},
|
||||
|
|
|
@ -513,10 +513,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
|
|||
tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
|
||||
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
|
||||
tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
|
||||
trait_ref: tcx.mk_trait_ref(
|
||||
eq_trait_id,
|
||||
[tcx.mk_param_from_def(param)],
|
||||
),
|
||||
trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]),
|
||||
constness: BoundConstness::NotConst,
|
||||
polarity: ImplPolarity::Positive,
|
||||
}))))
|
||||
|
|
|
@ -47,7 +47,7 @@ declare_clippy_lint! {
|
|||
/// value: usize,
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub DISALLOWED_MACROS,
|
||||
style,
|
||||
"use of a disallowed macro"
|
||||
|
|
|
@ -2,7 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
|||
use clippy_utils::is_diag_trait_item;
|
||||
use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred};
|
||||
use clippy_utils::macros::{
|
||||
is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
|
||||
is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam,
|
||||
FormatParamUsage,
|
||||
};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
|
@ -122,7 +123,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// If a format string contains a numbered argument that cannot be inlined
|
||||
/// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
|
||||
#[clippy::version = "1.65.0"]
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub UNINLINED_FORMAT_ARGS,
|
||||
style,
|
||||
"using non-inlined variables in `format!` calls"
|
||||
|
@ -290,8 +291,9 @@ fn check_uninlined_args(
|
|||
if args.format_string.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if call_site.edition() < Edition2021 && is_panic(cx, def_id) {
|
||||
// panic! before 2021 edition considers a single string argument as non-format
|
||||
if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) {
|
||||
// panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as
|
||||
// non-format
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc_hir::{
|
|||
TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::{hir::nested_filter::OnlyBodies, ty};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
@ -78,6 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|
|||
&& let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
|
||||
&& let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
|
||||
&& !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
|
@ -31,7 +31,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// u = u.saturating_add(1);
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub IMPLICIT_SATURATING_ADD,
|
||||
style,
|
||||
"Perform saturating addition instead of implicitly checking max bound of data type"
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
//! lint on indexing and slicing operations
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::higher;
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -82,15 +82,29 @@ declare_clippy_lint! {
|
|||
"indexing/slicing usage"
|
||||
}
|
||||
|
||||
declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
|
||||
impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct IndexingSlicing {
|
||||
suppress_restriction_lint_in_const: bool,
|
||||
}
|
||||
|
||||
impl IndexingSlicing {
|
||||
pub fn new(suppress_restriction_lint_in_const: bool) -> Self {
|
||||
Self {
|
||||
suppress_restriction_lint_in_const,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
|
||||
if self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let ExprKind::Index(array, index) = &expr.kind {
|
||||
let note = "the suggestion might not be applicable in constant blocks";
|
||||
let ty = cx.typeck_results().expr_ty(array).peel_refs();
|
||||
if let Some(range) = higher::Range::hir(index) {
|
||||
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
|
||||
|
@ -141,7 +155,13 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
|||
(None, None) => return, // [..] is ok.
|
||||
};
|
||||
|
||||
span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic", None, help_msg);
|
||||
span_lint_and_then(cx, INDEXING_SLICING, expr.span, "slicing may panic", |diag| {
|
||||
diag.help(help_msg);
|
||||
|
||||
if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
|
||||
diag.note(note);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Catchall non-range index, i.e., [n] or [n << m]
|
||||
if let ty::Array(..) = ty.kind() {
|
||||
|
@ -156,14 +176,13 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
|||
}
|
||||
}
|
||||
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
INDEXING_SLICING,
|
||||
expr.span,
|
||||
"indexing may panic",
|
||||
None,
|
||||
"consider using `.get(n)` or `.get_mut(n)` instead",
|
||||
);
|
||||
span_lint_and_then(cx, INDEXING_SLICING, expr.span, "indexing may panic", |diag| {
|
||||
diag.help("consider using `.get(n)` or `.get_mut(n)` instead");
|
||||
|
||||
if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
|
||||
diag.note(note);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed};
|
||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefIdSet;
|
||||
use rustc_hir::{
|
||||
def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
|
||||
ItemKind, Mutability, Node, TraitItemRef, TyKind,
|
||||
ItemKind, Mutability, Node, TraitItemRef, TyKind, UnOp,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
||||
|
@ -16,6 +16,7 @@ use rustc_span::{
|
|||
source_map::{Span, Spanned, Symbol},
|
||||
symbol::sym,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -428,16 +429,23 @@ fn check_len(
|
|||
fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
|
||||
if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let lit1 = peel_ref_operators(cx, lit1);
|
||||
let mut lit_str = snippet_with_applicability(cx, lit1.span, "_", &mut applicability);
|
||||
|
||||
// Wrap the expression in parentheses if it's a deref expression. Otherwise operator precedence will
|
||||
// cause the code to dereference boolean(won't compile).
|
||||
if let ExprKind::Unary(UnOp::Deref, _) = lit1.kind {
|
||||
lit_str = Cow::from(format!("({lit_str})"));
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
COMPARISON_TO_EMPTY,
|
||||
span,
|
||||
"comparison to empty slice",
|
||||
&format!("using `{op}is_empty` is clearer and more explicit"),
|
||||
format!(
|
||||
"{op}{}.is_empty()",
|
||||
snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
|
||||
),
|
||||
format!("{op}{lit_str}.is_empty()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ mod declared_lints;
|
|||
mod renamed_lints;
|
||||
|
||||
// begin lints modules, do not remove this comment, it’s used in `update_lints`
|
||||
mod almost_complete_letter_range;
|
||||
mod almost_complete_range;
|
||||
mod approx_const;
|
||||
mod as_conversions;
|
||||
mod asm_syntax;
|
||||
|
@ -256,6 +256,7 @@ mod return_self_not_must_use;
|
|||
mod returns;
|
||||
mod same_name_method;
|
||||
mod self_named_constructors;
|
||||
mod semicolon_block;
|
||||
mod semicolon_if_nothing_returned;
|
||||
mod serde_api;
|
||||
mod shadow;
|
||||
|
@ -507,9 +508,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
}
|
||||
|
||||
let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
|
||||
let arithmetic_side_effects_allowed_binary = conf.arithmetic_side_effects_allowed_binary.clone();
|
||||
let arithmetic_side_effects_allowed_unary = conf.arithmetic_side_effects_allowed_unary.clone();
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
|
||||
arithmetic_side_effects_allowed.clone(),
|
||||
arithmetic_side_effects_allowed
|
||||
.iter()
|
||||
.flat_map(|el| [[el.clone(), "*".to_string()], ["*".to_string(), el.clone()]])
|
||||
.chain(arithmetic_side_effects_allowed_binary.clone())
|
||||
.collect(),
|
||||
arithmetic_side_effects_allowed
|
||||
.iter()
|
||||
.chain(arithmetic_side_effects_allowed_unary.iter())
|
||||
.cloned()
|
||||
.collect(),
|
||||
))
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
|
||||
|
@ -538,7 +550,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
|
||||
store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
|
||||
store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
|
||||
store.register_late_pass(|_| Box::new(misc::MiscLints));
|
||||
store.register_late_pass(|_| Box::<misc::LintPass>::default());
|
||||
store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
|
||||
store.register_late_pass(|_| Box::new(mut_mut::MutMut));
|
||||
store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
|
||||
|
@ -561,6 +573,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
|
||||
let allow_expect_in_tests = conf.allow_expect_in_tests;
|
||||
let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
|
||||
let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const;
|
||||
store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(methods::Methods::new(
|
||||
|
@ -682,7 +695,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
|
||||
store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
|
||||
store.register_late_pass(|_| Box::new(unwrap::Unwrap));
|
||||
store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(indexing_slicing::IndexingSlicing::new(
|
||||
suppress_restriction_lint_in_const,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
|
||||
store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
|
||||
store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
|
||||
|
@ -859,7 +876,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
|
||||
store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
|
||||
store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
|
||||
store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv())));
|
||||
store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(msrv())));
|
||||
store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
|
||||
store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
|
||||
store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
|
||||
|
@ -884,6 +901,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
|
||||
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
|
||||
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
|
||||
store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ pub(super) struct IncrementVisitor<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>, // context reference
|
||||
states: HirIdMap<IncrementVisitorVarState>, // incremented variables
|
||||
depth: u32, // depth of conditional expressions
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
|
||||
|
@ -34,7 +33,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
|
|||
cx,
|
||||
states: HirIdMap::default(),
|
||||
depth: 0,
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,10 +49,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if self.done {
|
||||
return;
|
||||
}
|
||||
|
||||
// If node is a variable
|
||||
if let Some(def_id) = path_to_local(expr) {
|
||||
if let Some(parent) = get_parent_expr(self.cx, expr) {
|
||||
|
@ -95,7 +89,9 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
|
|||
walk_expr(self, expr);
|
||||
self.depth -= 1;
|
||||
} else if let ExprKind::Continue(_) = expr.kind {
|
||||
self.done = true;
|
||||
// If we see a `continue` block, then we increment depth so that the IncrementVisitor
|
||||
// state will be set to DontWarn if we see the variable being modified anywhere afterwards.
|
||||
self.depth += 1;
|
||||
} else {
|
||||
walk_expr(self, expr);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::rustc_lint::LintContext;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{peel_blocks_with_stmt, span_extract_comment, sugg};
|
||||
use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -47,6 +47,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
|
|||
if cx.tcx.item_name(macro_call.def_id) == sym::panic;
|
||||
if !cx.tcx.sess.source_map().is_multiline(cond.span);
|
||||
if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
|
||||
// Don't change `else if foo { panic!(..) }` to `else { assert!(foo, ..) }` as it just
|
||||
// shuffles the condition around.
|
||||
// Should this have a config value?
|
||||
if !is_else_clause(cx.tcx, expr);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet};
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_ast::LitKind::{Byte, Char};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{def_id::DefId, sym};
|
||||
use rustc_span::{def_id::DefId, sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -23,6 +24,10 @@ declare_clippy_lint! {
|
|||
/// assert!(matches!(b'X', b'A'..=b'Z'));
|
||||
/// assert!(matches!('2', '0'..='9'));
|
||||
/// assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
||||
///
|
||||
/// ('0'..='9').contains(&'0');
|
||||
/// ('a'..='z').contains(&'a');
|
||||
/// ('A'..='Z').contains(&'A');
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
|
@ -32,6 +37,10 @@ declare_clippy_lint! {
|
|||
/// assert!(b'X'.is_ascii_uppercase());
|
||||
/// assert!('2'.is_ascii_digit());
|
||||
/// assert!('x'.is_ascii_alphabetic());
|
||||
///
|
||||
/// '0'.is_ascii_digit();
|
||||
/// 'a'.is_ascii_lowercase();
|
||||
/// 'A'.is_ascii_uppercase();
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
|
@ -75,40 +84,21 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
|||
return;
|
||||
}
|
||||
|
||||
let Some(macro_call) = root_macro_call(expr.span) else { return };
|
||||
|
||||
if is_matches_macro(cx, macro_call.def_id) {
|
||||
if let Some(macro_call) = root_macro_call(expr.span)
|
||||
&& is_matches_macro(cx, macro_call.def_id) {
|
||||
if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
|
||||
let range = check_pat(&arm.pat.kind);
|
||||
|
||||
if let Some(sugg) = match range {
|
||||
CharRange::UpperChar => Some("is_ascii_uppercase"),
|
||||
CharRange::LowerChar => Some("is_ascii_lowercase"),
|
||||
CharRange::FullChar => Some("is_ascii_alphabetic"),
|
||||
CharRange::Digit => Some("is_ascii_digit"),
|
||||
CharRange::Otherwise => None,
|
||||
} {
|
||||
let default_snip = "..";
|
||||
// `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
|
||||
// macro span, so we check applicability manually by comparing `recv` is not default.
|
||||
let recv = snippet(cx, recv.span, default_snip);
|
||||
|
||||
let applicability = if recv == default_snip {
|
||||
Applicability::HasPlaceholders
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_IS_ASCII_CHECK,
|
||||
macro_call.span,
|
||||
"manual check for common ascii range",
|
||||
"try",
|
||||
format!("{recv}.{sugg}()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
check_is_ascii(cx, macro_call.span, recv, &range);
|
||||
}
|
||||
} else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
|
||||
&& path.ident.name == sym!(contains)
|
||||
&& let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed })
|
||||
= higher::Range::hir(receiver) {
|
||||
let range = check_range(start, end);
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind {
|
||||
check_is_ascii(cx, expr.span, e, &range);
|
||||
} else {
|
||||
check_is_ascii(cx, expr.span, arg, &range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +106,37 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
|||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) {
|
||||
if let Some(sugg) = match range {
|
||||
CharRange::UpperChar => Some("is_ascii_uppercase"),
|
||||
CharRange::LowerChar => Some("is_ascii_lowercase"),
|
||||
CharRange::FullChar => Some("is_ascii_alphabetic"),
|
||||
CharRange::Digit => Some("is_ascii_digit"),
|
||||
CharRange::Otherwise => None,
|
||||
} {
|
||||
let default_snip = "..";
|
||||
// `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
|
||||
// macro span, so we check applicability manually by comparing `recv` is not default.
|
||||
let recv = snippet(cx, recv.span, default_snip);
|
||||
|
||||
let applicability = if recv == default_snip {
|
||||
Applicability::HasPlaceholders
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_IS_ASCII_CHECK,
|
||||
span,
|
||||
"manual check for common ascii range",
|
||||
"try",
|
||||
format!("{recv}.{sugg}()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
|
||||
match pat_kind {
|
||||
PatKind::Or(pats) => {
|
||||
|
|
|
@ -151,7 +151,12 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
|
|||
} else {
|
||||
format!("{{ {sn_else} }}")
|
||||
};
|
||||
let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
|
||||
let sn_bl = if matches!(pat.kind, PatKind::Or(..)) {
|
||||
format!("({sn_pat})")
|
||||
} else {
|
||||
sn_pat.into_owned()
|
||||
};
|
||||
let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};");
|
||||
diag.span_suggestion(span, "consider writing", sugg, app);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -70,7 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
|
|||
&& seg.args.is_none()
|
||||
&& let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
|
||||
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
|
||||
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
|
||||
&& cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
|
||||
{
|
||||
check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
|
||||
check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
|
||||
check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::peel_mid_ty_refs;
|
||||
use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
|
||||
use clippy_utils::{is_diag_item_method, is_diag_trait_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -19,6 +19,8 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
|
|||
let (input_type, ref_count) = peel_mid_ty_refs(input_type);
|
||||
if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
|
||||
if return_type == input_type;
|
||||
if let Some(clone_trait) = cx.tcx.lang_items().clone_trait();
|
||||
if implements_trait(cx, return_type, clone_trait, &[]);
|
||||
then {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
|
||||
|
|
|
@ -3059,7 +3059,7 @@ declare_clippy_lint! {
|
|||
/// let map: HashMap<u32, u32> = HashMap::new();
|
||||
/// let values = map.values().collect::<Vec<_>>();
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub ITER_KV_MAP,
|
||||
complexity,
|
||||
"iterating on map using `iter` when `keys` or `values` would do"
|
||||
|
@ -3672,7 +3672,10 @@ impl Methods {
|
|||
no_effect_replace::check(cx, expr, arg1, arg2);
|
||||
|
||||
// Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
|
||||
if name == "replace" && let Some(("replace", ..)) = method_call(recv) {
|
||||
if self.msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY)
|
||||
&& name == "replace"
|
||||
&& let Some(("replace", ..)) = method_call(recv)
|
||||
{
|
||||
collapsible_str_replace::check(cx, expr, arg1, arg2);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{get_trait_def_id, match_def_path, paths};
|
||||
use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths};
|
||||
use rustc_ast::ast::{LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
|
@ -19,6 +19,10 @@ pub(super) fn check<'tcx>(
|
|||
// Get receiver type
|
||||
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
if is_expr_used_or_unified(cx.tcx, expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
|
||||
implements_trait(cx, ty, seek_trait_id, &[]) &&
|
||||
let ExprKind::Call(func, args1) = arg.kind &&
|
||||
|
|
|
@ -9,12 +9,14 @@ use rustc_hir::{
|
|||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::{ExpnKind, Span};
|
||||
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{get_parent_expr, in_constant, is_integer_literal, iter_input_pats, last_path_segment, SpanlessEq};
|
||||
use clippy_utils::{
|
||||
get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq,
|
||||
};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -120,14 +122,28 @@ declare_clippy_lint! {
|
|||
"using `0 as *{const, mut} T`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(MiscLints => [
|
||||
pub struct LintPass {
|
||||
std_or_core: &'static str,
|
||||
}
|
||||
impl Default for LintPass {
|
||||
fn default() -> Self {
|
||||
Self { std_or_core: "std" }
|
||||
}
|
||||
}
|
||||
impl_lint_pass!(LintPass => [
|
||||
TOPLEVEL_REF_ARG,
|
||||
USED_UNDERSCORE_BINDING,
|
||||
SHORT_CIRCUIT_STATEMENT,
|
||||
ZERO_PTR,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MiscLints {
|
||||
impl<'tcx> LateLintPass<'tcx> for LintPass {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
if is_no_std_crate(cx) {
|
||||
self.std_or_core = "core";
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
|
@ -231,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
|
|||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Cast(e, ty) = expr.kind {
|
||||
check_cast(cx, expr.span, e, ty);
|
||||
self.check_cast(cx, expr.span, e, ty);
|
||||
return;
|
||||
}
|
||||
if in_attributes_expansion(expr) || expr.span.is_desugaring(DesugaringKind::Await) {
|
||||
|
@ -310,26 +326,28 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
|
||||
if_chain! {
|
||||
if let TyKind::Ptr(ref mut_ty) = ty.kind;
|
||||
if is_integer_literal(e, 0);
|
||||
if !in_constant(cx, e.hir_id);
|
||||
then {
|
||||
let (msg, sugg_fn) = match mut_ty.mutbl {
|
||||
Mutability::Mut => ("`0 as *mut _` detected", "std::ptr::null_mut"),
|
||||
Mutability::Not => ("`0 as *const _` detected", "std::ptr::null"),
|
||||
};
|
||||
impl LintPass {
|
||||
fn check_cast(&self, cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
|
||||
if_chain! {
|
||||
if let TyKind::Ptr(ref mut_ty) = ty.kind;
|
||||
if is_integer_literal(e, 0);
|
||||
if !in_constant(cx, e.hir_id);
|
||||
then {
|
||||
let (msg, sugg_fn) = match mut_ty.mutbl {
|
||||
Mutability::Mut => ("`0 as *mut _` detected", "ptr::null_mut"),
|
||||
Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
|
||||
};
|
||||
|
||||
let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
|
||||
(format!("{sugg_fn}()"), Applicability::MachineApplicable)
|
||||
} else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
|
||||
(format!("{sugg_fn}::<{mut_ty_snip}>()"), Applicability::MachineApplicable)
|
||||
} else {
|
||||
// `MaybeIncorrect` as type inference may not work with the suggested code
|
||||
(format!("{sugg_fn}()"), Applicability::MaybeIncorrect)
|
||||
};
|
||||
span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
|
||||
let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
|
||||
(format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MachineApplicable)
|
||||
} else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
|
||||
(format!("{}::{sugg_fn}::<{mut_ty_snip}>()", self.std_or_core), Applicability::MachineApplicable)
|
||||
} else {
|
||||
// `MaybeIncorrect` as type inference may not work with the suggested code
|
||||
(format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MaybeIncorrect)
|
||||
};
|
||||
span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,25 +5,26 @@ use clippy_utils::{
|
|||
peel_hir_expr_refs,
|
||||
};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
|
||||
const HARD_CODED_ALLOWED: &[&str] = &[
|
||||
"&str",
|
||||
"f32",
|
||||
"f64",
|
||||
"std::num::Saturating",
|
||||
"std::num::Wrapping",
|
||||
"std::string::String",
|
||||
const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[
|
||||
["f32", "f32"],
|
||||
["f64", "f64"],
|
||||
["std::num::Saturating", "std::num::Saturating"],
|
||||
["std::num::Wrapping", "std::num::Wrapping"],
|
||||
["std::string::String", "&str"],
|
||||
];
|
||||
const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArithmeticSideEffects {
|
||||
allowed: FxHashSet<String>,
|
||||
allowed_binary: FxHashMap<String, FxHashSet<String>>,
|
||||
allowed_unary: FxHashSet<String>,
|
||||
// Used to check whether expressions are constants, such as in enum discriminants and consts
|
||||
const_span: Option<Span>,
|
||||
expr_span: Option<Span>,
|
||||
|
@ -33,19 +34,55 @@ impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
|
|||
|
||||
impl ArithmeticSideEffects {
|
||||
#[must_use]
|
||||
pub fn new(mut allowed: FxHashSet<String>) -> Self {
|
||||
allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
|
||||
pub fn new(user_allowed_binary: Vec<[String; 2]>, user_allowed_unary: Vec<String>) -> Self {
|
||||
let mut allowed_binary: FxHashMap<String, FxHashSet<String>> = <_>::default();
|
||||
for [lhs, rhs] in user_allowed_binary.into_iter().chain(
|
||||
HARD_CODED_ALLOWED_BINARY
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|[lhs, rhs]| [lhs.to_string(), rhs.to_string()]),
|
||||
) {
|
||||
allowed_binary.entry(lhs).or_default().insert(rhs);
|
||||
}
|
||||
let allowed_unary = user_allowed_unary
|
||||
.into_iter()
|
||||
.chain(HARD_CODED_ALLOWED_UNARY.iter().copied().map(String::from))
|
||||
.collect();
|
||||
Self {
|
||||
allowed,
|
||||
allowed_binary,
|
||||
allowed_unary,
|
||||
const_span: None,
|
||||
expr_span: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given `expr` has any of the inner `allowed` elements.
|
||||
fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
|
||||
self.allowed
|
||||
.contains(ty.to_string().split('<').next().unwrap_or_default())
|
||||
/// Checks if the lhs and the rhs types of a binary operation like "addition" or
|
||||
/// "multiplication" are present in the inner set of allowed types.
|
||||
fn has_allowed_binary(&self, lhs_ty: Ty<'_>, rhs_ty: Ty<'_>) -> bool {
|
||||
let lhs_ty_string = lhs_ty.to_string();
|
||||
let lhs_ty_string_elem = lhs_ty_string.split('<').next().unwrap_or_default();
|
||||
let rhs_ty_string = rhs_ty.to_string();
|
||||
let rhs_ty_string_elem = rhs_ty_string.split('<').next().unwrap_or_default();
|
||||
if let Some(rhs_from_specific) = self.allowed_binary.get(lhs_ty_string_elem)
|
||||
&& {
|
||||
let rhs_has_allowed_ty = rhs_from_specific.contains(rhs_ty_string_elem);
|
||||
rhs_has_allowed_ty || rhs_from_specific.contains("*")
|
||||
}
|
||||
{
|
||||
true
|
||||
} else if let Some(rhs_from_glob) = self.allowed_binary.get("*") {
|
||||
rhs_from_glob.contains(rhs_ty_string_elem)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the type of an unary operation like "negation" is present in the inner set of
|
||||
/// allowed types.
|
||||
fn has_allowed_unary(&self, ty: Ty<'_>) -> bool {
|
||||
let ty_string = ty.to_string();
|
||||
let ty_string_elem = ty_string.split('<').next().unwrap_or_default();
|
||||
self.allowed_unary.contains(ty_string_elem)
|
||||
}
|
||||
|
||||
// For example, 8i32 or &i64::MAX.
|
||||
|
@ -97,8 +134,7 @@ impl ArithmeticSideEffects {
|
|||
};
|
||||
let lhs_ty = cx.typeck_results().expr_ty(lhs);
|
||||
let rhs_ty = cx.typeck_results().expr_ty(rhs);
|
||||
let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
|
||||
if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) {
|
||||
if self.has_allowed_binary(lhs_ty, rhs_ty) {
|
||||
return;
|
||||
}
|
||||
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
|
||||
|
@ -137,7 +173,7 @@ impl ArithmeticSideEffects {
|
|||
return;
|
||||
}
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
if self.is_allowed_ty(ty) {
|
||||
if self.has_allowed_unary(ty) {
|
||||
return;
|
||||
}
|
||||
let actual_un_expr = peel_hir_expr_refs(un_expr).0;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{clip, unsext};
|
||||
use clippy_utils::{clip, peel_hir_expr_refs, unsext};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -20,20 +20,76 @@ pub(crate) fn check<'tcx>(
|
|||
if !is_allowed(cx, op, left, right) {
|
||||
match op {
|
||||
BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
|
||||
check_op(cx, left, 0, expr.span, right.span, needs_parenthesis(cx, expr, right));
|
||||
check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
|
||||
check_op(
|
||||
cx,
|
||||
left,
|
||||
0,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(right).0.span,
|
||||
needs_parenthesis(cx, expr, right),
|
||||
);
|
||||
check_op(
|
||||
cx,
|
||||
right,
|
||||
0,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(left).0.span,
|
||||
Parens::Unneeded,
|
||||
);
|
||||
},
|
||||
BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
|
||||
check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
|
||||
check_op(
|
||||
cx,
|
||||
right,
|
||||
0,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(left).0.span,
|
||||
Parens::Unneeded,
|
||||
);
|
||||
},
|
||||
BinOpKind::Mul => {
|
||||
check_op(cx, left, 1, expr.span, right.span, needs_parenthesis(cx, expr, right));
|
||||
check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded);
|
||||
check_op(
|
||||
cx,
|
||||
left,
|
||||
1,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(right).0.span,
|
||||
needs_parenthesis(cx, expr, right),
|
||||
);
|
||||
check_op(
|
||||
cx,
|
||||
right,
|
||||
1,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(left).0.span,
|
||||
Parens::Unneeded,
|
||||
);
|
||||
},
|
||||
BinOpKind::Div => check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded),
|
||||
BinOpKind::Div => check_op(
|
||||
cx,
|
||||
right,
|
||||
1,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(left).0.span,
|
||||
Parens::Unneeded,
|
||||
),
|
||||
BinOpKind::BitAnd => {
|
||||
check_op(cx, left, -1, expr.span, right.span, needs_parenthesis(cx, expr, right));
|
||||
check_op(cx, right, -1, expr.span, left.span, Parens::Unneeded);
|
||||
check_op(
|
||||
cx,
|
||||
left,
|
||||
-1,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(right).0.span,
|
||||
needs_parenthesis(cx, expr, right),
|
||||
);
|
||||
check_op(
|
||||
cx,
|
||||
right,
|
||||
-1,
|
||||
expr.span,
|
||||
peel_hir_expr_refs(left).0.span,
|
||||
Parens::Unneeded,
|
||||
);
|
||||
},
|
||||
BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
|
||||
_ => (),
|
||||
|
|
|
@ -90,9 +90,6 @@ declare_clippy_lint! {
|
|||
/// use rust_decimal::Decimal;
|
||||
/// let _n = Decimal::MAX + Decimal::MAX;
|
||||
/// ```
|
||||
///
|
||||
/// ### Allowed types
|
||||
/// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
|
||||
#[clippy::version = "1.64.0"]
|
||||
pub ARITHMETIC_SIDE_EFFECTS,
|
||||
restriction,
|
||||
|
|
|
@ -84,7 +84,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
|
|||
|
||||
fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
|
||||
if let ItemKind::Use(path, _) = item.kind {
|
||||
if path.res.iter().all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) {
|
||||
if path
|
||||
.res
|
||||
.iter()
|
||||
.all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if let ItemKind::Macro(..) = item.kind {
|
||||
|
|
|
@ -66,7 +66,7 @@ impl RedundantStaticLifetimes {
|
|||
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
|
||||
if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
|
||||
let snip = snippet(cx, borrow_type.ty.span, "<type>");
|
||||
let sugg = format!("&{snip}");
|
||||
let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_STATIC_LIFETIMES,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#[rustfmt::skip]
|
||||
pub static RENAMED_LINTS: &[(&str, &str)] = &[
|
||||
("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
|
||||
("clippy::blacklisted_name", "clippy::disallowed_names"),
|
||||
("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
|
||||
("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
|
||||
|
|
137
clippy_lints/src/semicolon_block.rs
Normal file
137
clippy_lints/src/semicolon_block.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Suggests moving the semicolon after a block to the inside of the block, after its last
|
||||
/// expression.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
|
||||
/// and this lint suggests inside the block.
|
||||
/// Take a look at `semicolon_outside_block` for the other alternative.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # fn f(_: u32) {}
|
||||
/// # let x = 0;
|
||||
/// unsafe { f(x) };
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # fn f(_: u32) {}
|
||||
/// # let x = 0;
|
||||
/// unsafe { f(x); }
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub SEMICOLON_INSIDE_BLOCK,
|
||||
restriction,
|
||||
"add a semicolon inside the block"
|
||||
}
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Suggests moving the semicolon from a block's final expression outside of the block.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
|
||||
/// and this lint suggests outside the block.
|
||||
/// Take a look at `semicolon_inside_block` for the other alternative.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # fn f(_: u32) {}
|
||||
/// # let x = 0;
|
||||
/// unsafe { f(x); }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # fn f(_: u32) {}
|
||||
/// # let x = 0;
|
||||
/// unsafe { f(x) };
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
pub SEMICOLON_OUTSIDE_BLOCK,
|
||||
restriction,
|
||||
"add a semicolon outside the block"
|
||||
}
|
||||
declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
|
||||
|
||||
impl LateLintPass<'_> for SemicolonBlock {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
||||
match stmt.kind {
|
||||
StmtKind::Expr(Expr {
|
||||
kind: ExprKind::Block(block, _),
|
||||
..
|
||||
}) if !block.span.from_expansion() => {
|
||||
let Block {
|
||||
expr: None,
|
||||
stmts: [.., stmt],
|
||||
..
|
||||
} = block else { return };
|
||||
let &Stmt {
|
||||
kind: StmtKind::Semi(expr),
|
||||
span,
|
||||
..
|
||||
} = stmt else { return };
|
||||
semicolon_outside_block(cx, block, expr, span);
|
||||
},
|
||||
StmtKind::Semi(Expr {
|
||||
kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
|
||||
..
|
||||
}) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
|
||||
let insert_span = tail.span.source_callsite().shrink_to_hi();
|
||||
let remove_span = semi_span.with_lo(block.span.hi());
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SEMICOLON_INSIDE_BLOCK,
|
||||
semi_span,
|
||||
"consider moving the `;` inside the block for consistent formatting",
|
||||
|diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"put the `;` here",
|
||||
Applicability::MachineApplicable,
|
||||
[(remove_span, String::new()), (insert_span, ";".to_owned())],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
|
||||
let insert_span = block.span.with_lo(block.span.hi());
|
||||
// account for macro calls
|
||||
let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
|
||||
let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SEMICOLON_OUTSIDE_BLOCK,
|
||||
block.span,
|
||||
"consider moving the `;` outside the block for consistent formatting",
|
||||
|diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"put the `;` here",
|
||||
Applicability::MachineApplicable,
|
||||
[(remove_span, String::new()), (insert_span, ";".to_owned())],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::{get_expr_use_or_unification_node, peel_blocks, SpanlessEq};
|
||||
use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
|
||||
use clippy_utils::{peel_blocks, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
|
||||
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty;
|
||||
|
@ -249,6 +249,7 @@ const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;
|
|||
declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
||||
#[expect(clippy::too_many_lines)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
use rustc_ast::LitKind;
|
||||
|
||||
|
@ -316,18 +317,27 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
|||
&& lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
|
||||
&& !receiver.span.from_expansion()
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_LIT_AS_BYTES,
|
||||
e.span,
|
||||
"calling `as_bytes()` on a string literal",
|
||||
"consider using a byte string literal instead",
|
||||
format!(
|
||||
"b{}",
|
||||
snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e)
|
||||
&& let Node::Expr(parent) = parent
|
||||
&& let ExprKind::Match(scrutinee, ..) = parent.kind
|
||||
&& scrutinee.hir_id == id
|
||||
{
|
||||
// Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
|
||||
// `&[u8]`. This change would prevent matching with different sized slices.
|
||||
} else {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_LIT_AS_BYTES,
|
||||
e.span,
|
||||
"calling `as_bytes()` on a string literal",
|
||||
"consider using a byte string literal instead",
|
||||
format!(
|
||||
"b{}",
|
||||
snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,10 +205,49 @@ macro_rules! define_Conf {
|
|||
}
|
||||
|
||||
define_Conf! {
|
||||
/// Lint: Arithmetic.
|
||||
/// Lint: ARITHMETIC_SIDE_EFFECTS.
|
||||
///
|
||||
/// Suppress checking of the passed type names.
|
||||
/// Suppress checking of the passed type names in all types of operations.
|
||||
///
|
||||
/// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
|
||||
///
|
||||
/// #### Example
|
||||
///
|
||||
/// ```toml
|
||||
/// arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
|
||||
/// ```
|
||||
///
|
||||
/// #### Noteworthy
|
||||
///
|
||||
/// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
|
||||
(arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
|
||||
/// Lint: ARITHMETIC_SIDE_EFFECTS.
|
||||
///
|
||||
/// Suppress checking of the passed type pair names in binary operations like addition or
|
||||
/// multiplication.
|
||||
///
|
||||
/// Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
|
||||
/// of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
|
||||
///
|
||||
/// Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
|
||||
/// `["AnotherType", "SomeType"]`.
|
||||
///
|
||||
/// #### Example
|
||||
///
|
||||
/// ```toml
|
||||
/// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
|
||||
/// ```
|
||||
(arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()),
|
||||
/// Lint: ARITHMETIC_SIDE_EFFECTS.
|
||||
///
|
||||
/// Suppress checking of the passed type names in unary operations like "negation" (`-`).
|
||||
///
|
||||
/// #### Example
|
||||
///
|
||||
/// ```toml
|
||||
/// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
|
||||
/// ```
|
||||
(arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
|
||||
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
|
||||
///
|
||||
/// Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
|
@ -406,6 +445,14 @@ define_Conf! {
|
|||
///
|
||||
/// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
|
||||
(allow_mixed_uninlined_format_args: bool = true),
|
||||
/// Lint: INDEXING_SLICING
|
||||
///
|
||||
/// Whether to suppress a restriction lint in constant code. In same
|
||||
/// cases the restructured operation might not be unavoidable, as the
|
||||
/// suggested counterparts are unavailable in constant code. This
|
||||
/// configuration will cause restriction lints to trigger even
|
||||
/// if no suggestion can be made.
|
||||
(suppress_restriction_lint_in_const: bool = false),
|
||||
}
|
||||
|
||||
/// Search for the configuration file.
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_hir::def::DefKind;
|
|||
use rustc_hir::Item;
|
||||
use rustc_hir_analysis::hir_ty_to_ty;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy};
|
||||
use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
|
@ -73,10 +73,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
|
|||
let lang_items = cx.tcx.lang_items();
|
||||
// This list isn't complete, but good enough for our current list of paths.
|
||||
let incoherent_impls = [
|
||||
SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
|
||||
SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
|
||||
SimplifiedTypeGen::SliceSimplifiedType,
|
||||
SimplifiedTypeGen::StrSimplifiedType,
|
||||
SimplifiedType::FloatSimplifiedType(FloatTy::F32),
|
||||
SimplifiedType::FloatSimplifiedType(FloatTy::F64),
|
||||
SimplifiedType::SliceSimplifiedType,
|
||||
SimplifiedType::StrSimplifiedType,
|
||||
]
|
||||
.iter()
|
||||
.flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
|
|||
let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
|
||||
match cx.tcx.hir().get_by_def_id(parent_id) {
|
||||
Node::Item(&Item {
|
||||
kind: ItemKind::Const(..) | ItemKind::Static(..),
|
||||
kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..),
|
||||
..
|
||||
})
|
||||
| Node::TraitItem(&TraitItem {
|
||||
|
|
|
@ -208,6 +208,12 @@ pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
/// Is `def_id` of `assert!` or `debug_assert!`
|
||||
pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
|
||||
let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
|
||||
matches!(name, sym::assert_macro | sym::debug_assert_macro)
|
||||
}
|
||||
|
||||
pub enum PanicExpn<'a> {
|
||||
/// No arguments - `panic!()`
|
||||
Empty,
|
||||
|
|
|
@ -21,7 +21,7 @@ macro_rules! msrv_aliases {
|
|||
msrv_aliases! {
|
||||
1,65,0 { LET_ELSE }
|
||||
1,62,0 { BOOL_THEN_SOME }
|
||||
1,58,0 { FORMAT_ARGS_CAPTURE }
|
||||
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
|
||||
1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
|
||||
1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
|
||||
1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
|
||||
|
|
|
@ -20,7 +20,6 @@ pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "
|
|||
pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
|
||||
pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
|
||||
pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
|
||||
pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"];
|
||||
pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
|
||||
pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
|
||||
pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
|
||||
|
|
|
@ -301,10 +301,7 @@ fn check_terminator<'tcx>(
|
|||
check_operand(tcx, value, span, body)
|
||||
},
|
||||
|
||||
TerminatorKind::SwitchInt {
|
||||
discr,
|
||||
targets: _,
|
||||
} => check_operand(tcx, discr, span, body),
|
||||
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
|
||||
|
||||
TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
|
||||
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
|
||||
|
|
|
@ -16,8 +16,8 @@ use rustc_infer::infer::{
|
|||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
|
||||
AliasTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
|
||||
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
|
||||
PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
|
||||
VariantDef, VariantDiscr,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||
|
@ -30,7 +30,7 @@ use std::iter;
|
|||
|
||||
use crate::{match_def_path, path_res, paths};
|
||||
|
||||
// Checks if the given type implements copy.
|
||||
/// Checks if the given type implements copy.
|
||||
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
|
||||
}
|
||||
|
@ -69,50 +69,66 @@ pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
|
|||
/// This method also recurses into opaque type predicates, so call it with `impl Trait<U>` and `U`
|
||||
/// will also return `true`.
|
||||
pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool {
|
||||
ty.walk().any(|inner| match inner.unpack() {
|
||||
GenericArgKind::Type(inner_ty) => {
|
||||
if inner_ty == needle {
|
||||
return true;
|
||||
}
|
||||
fn contains_ty_adt_constructor_opaque_inner<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
needle: Ty<'tcx>,
|
||||
seen: &mut FxHashSet<DefId>,
|
||||
) -> bool {
|
||||
ty.walk().any(|inner| match inner.unpack() {
|
||||
GenericArgKind::Type(inner_ty) => {
|
||||
if inner_ty == needle {
|
||||
return true;
|
||||
}
|
||||
|
||||
if inner_ty.ty_adt_def() == needle.ty_adt_def() {
|
||||
return true;
|
||||
}
|
||||
if inner_ty.ty_adt_def() == needle.ty_adt_def() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
|
||||
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||
match predicate.kind().skip_binder() {
|
||||
// For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
|
||||
// and check substituions to find `U`.
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
|
||||
if trait_predicate
|
||||
.trait_ref
|
||||
.substs
|
||||
.types()
|
||||
.skip(1) // Skip the implicit `Self` generic parameter
|
||||
.any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
},
|
||||
// For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
|
||||
// so we check the term for `U`.
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
|
||||
if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
|
||||
if contains_ty_adt_constructor_opaque(cx, ty, needle) {
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
|
||||
if !seen.insert(def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||
match predicate.kind().skip_binder() {
|
||||
// For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
|
||||
// and check substituions to find `U`.
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
|
||||
if trait_predicate
|
||||
.trait_ref
|
||||
.substs
|
||||
.types()
|
||||
.skip(1) // Skip the implicit `Self` generic parameter
|
||||
.any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
// For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
|
||||
// so we check the term for `U`.
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
|
||||
if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
|
||||
if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
},
|
||||
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
|
||||
})
|
||||
false
|
||||
},
|
||||
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
|
||||
})
|
||||
}
|
||||
|
||||
// A hash set to ensure that the same opaque type (`impl Trait` in RPIT or TAIT) is not
|
||||
// visited twice.
|
||||
let mut seen = FxHashSet::default();
|
||||
contains_ty_adt_constructor_opaque_inner(cx, ty, needle, &mut seen)
|
||||
}
|
||||
|
||||
/// Resolves `<T as Iterator>::Item` for `T`
|
||||
|
@ -631,7 +647,9 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
|
|||
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
|
||||
},
|
||||
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
|
||||
sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id))
|
||||
},
|
||||
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
|
||||
ty::Dynamic(bounds, _, _) => {
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
|
@ -685,8 +703,7 @@ fn sig_from_bounds<'tcx>(
|
|||
inputs = Some(i);
|
||||
},
|
||||
PredicateKind::Clause(ty::Clause::Projection(p))
|
||||
if Some(p.projection_ty.def_id) == lang_items.fn_once_output()
|
||||
&& p.projection_ty.self_ty() == ty =>
|
||||
if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
|
||||
{
|
||||
if output.is_some() {
|
||||
// Multiple different fn trait impls. Is this even allowed?
|
||||
|
@ -1039,10 +1056,7 @@ pub fn make_projection<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
Some(tcx.mk_alias_ty(
|
||||
assoc_item.def_id,
|
||||
substs,
|
||||
))
|
||||
Some(tcx.mk_alias_ty(assoc_item.def_id, substs))
|
||||
}
|
||||
helper(
|
||||
tcx,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.67"
|
||||
version = "0.1.68"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2022-12-01"
|
||||
channel = "nightly-2022-12-17"
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
|
|
6
rustc_tools_util/CHANGELOG.md
Normal file
6
rustc_tools_util/CHANGELOG.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Changelog
|
||||
|
||||
## Version 0.3.0
|
||||
|
||||
* Added `setup_version_info!();` macro for automated scripts.
|
||||
* `get_version_info!()` no longer requires the user to import `rustc_tools_util::VersionInfo` and `std::env`
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "rustc_tools_util"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
description = "small helper to generate version information for git packages"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -13,43 +13,39 @@ build = "build.rs"
|
|||
List rustc_tools_util as regular AND build dependency.
|
||||
````toml
|
||||
[dependencies]
|
||||
rustc_tools_util = "0.2.1"
|
||||
rustc_tools_util = "0.3.0"
|
||||
|
||||
[build-dependencies]
|
||||
rustc_tools_util = "0.2.1"
|
||||
rustc_tools_util = "0.3.0"
|
||||
````
|
||||
|
||||
In `build.rs`, generate the data in your `main()`
|
||||
````rust
|
||||
fn main() {
|
||||
println!(
|
||||
"cargo:rustc-env=GIT_HASH={}",
|
||||
rustc_tools_util::get_commit_hash().unwrap_or_default()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=COMMIT_DATE={}",
|
||||
rustc_tools_util::get_commit_date().unwrap_or_default()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
|
||||
rustc_tools_util::get_channel().unwrap_or_default()
|
||||
);
|
||||
}
|
||||
|
||||
````
|
||||
```rust
|
||||
fn main() {
|
||||
rustc_tools_util::setup_version_info!();
|
||||
}
|
||||
```
|
||||
|
||||
Use the version information in your main.rs
|
||||
````rust
|
||||
use rustc_tools_util::*;
|
||||
|
||||
```rust
|
||||
fn show_version() {
|
||||
let version_info = rustc_tools_util::get_version_info!();
|
||||
println!("{}", version_info);
|
||||
}
|
||||
````
|
||||
This gives the following output in clippy:
|
||||
`clippy 0.0.212 (a416c5e 2018-12-14)`
|
||||
```
|
||||
|
||||
This gives the following output in clippy:
|
||||
`clippy 0.1.66 (a28f3c8 2022-11-20)`
|
||||
|
||||
## Repository
|
||||
|
||||
This project is part of the rust-lang/rust-clippy repository. The source code
|
||||
can be found under `./rustc_tools_util/`.
|
||||
|
||||
The changelog for `rustc_tools_util` is available under:
|
||||
[`rustc_tools_util/CHANGELOG.md`](https://github.com/rust-lang/rust-clippy/blob/master/rustc_tools_util/CHANGELOG.md)
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
|
||||
use std::env;
|
||||
|
||||
/// This macro creates the version string during compilation from the
|
||||
/// current environment
|
||||
#[macro_export]
|
||||
macro_rules! get_version_info {
|
||||
() => {{
|
||||
let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
|
||||
let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
|
||||
let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
|
||||
let crate_name = String::from(env!("CARGO_PKG_NAME"));
|
||||
let major = std::env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
|
||||
let minor = std::env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
|
||||
let patch = std::env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
|
||||
let crate_name = String::from(std::env!("CARGO_PKG_NAME"));
|
||||
|
||||
let host_compiler = option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
|
||||
let commit_hash = option_env!("GIT_HASH").map(str::to_string);
|
||||
let commit_date = option_env!("COMMIT_DATE").map(str::to_string);
|
||||
let host_compiler = std::option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
|
||||
let commit_hash = std::option_env!("GIT_HASH").map(str::to_string);
|
||||
let commit_date = std::option_env!("COMMIT_DATE").map(str::to_string);
|
||||
|
||||
VersionInfo {
|
||||
$crate::VersionInfo {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
|
@ -26,6 +26,24 @@ macro_rules! get_version_info {
|
|||
}};
|
||||
}
|
||||
|
||||
/// This macro can be used in `build.rs` to automatically set the needed
|
||||
/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and
|
||||
/// `RUSTC_RELEASE_CHANNEL`
|
||||
#[macro_export]
|
||||
macro_rules! setup_version_info {
|
||||
() => {{
|
||||
println!(
|
||||
"cargo:rustc-env=GIT_HASH={}",
|
||||
$crate::get_commit_hash().unwrap_or_default()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-env=COMMIT_DATE={}",
|
||||
$crate::get_commit_date().unwrap_or_default()
|
||||
);
|
||||
println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel());
|
||||
}};
|
||||
}
|
||||
|
||||
// some code taken and adapted from RLS and cargo
|
||||
pub struct VersionInfo {
|
||||
pub major: u8,
|
||||
|
@ -101,7 +119,7 @@ pub fn get_commit_date() -> Option<String> {
|
|||
|
||||
#[must_use]
|
||||
pub fn get_channel() -> String {
|
||||
match env::var("CFG_RELEASE_CHANNEL") {
|
||||
match std::env::var("CFG_RELEASE_CHANNEL") {
|
||||
Ok(channel) => channel,
|
||||
Err(_) => {
|
||||
// if that failed, try to ask rustc -V, do some parsing and find out
|
||||
|
@ -136,8 +154,8 @@ mod test {
|
|||
fn test_struct_local() {
|
||||
let vi = get_version_info!();
|
||||
assert_eq!(vi.major, 0);
|
||||
assert_eq!(vi.minor, 2);
|
||||
assert_eq!(vi.patch, 1);
|
||||
assert_eq!(vi.minor, 3);
|
||||
assert_eq!(vi.patch, 0);
|
||||
assert_eq!(vi.crate_name, "rustc_tools_util");
|
||||
// hard to make positive tests for these since they will always change
|
||||
assert!(vi.commit_hash.is_none());
|
||||
|
@ -147,7 +165,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_display_local() {
|
||||
let vi = get_version_info!();
|
||||
assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1");
|
||||
assert_eq!(vi.to_string(), "rustc_tools_util 0.3.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -156,7 +174,7 @@ mod test {
|
|||
let s = format!("{vi:?}");
|
||||
assert_eq!(
|
||||
s,
|
||||
"VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }"
|
||||
"VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 3, patch: 0 }"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ extern crate rustc_span;
|
|||
use rustc_interface::interface;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_tools_util::VersionInfo;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// warn on lints, that are included in `rust-lang/rust`s bootstrap
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
|
||||
use rustc_tools_util::VersionInfo;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, Command};
|
||||
|
|
|
@ -7,14 +7,6 @@ LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
|
|||
= help: convert all references to use `sym::Deref`
|
||||
= note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
|
||||
|
||||
error: hardcoded path to a diagnostic item
|
||||
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
||||
|
|
||||
LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: convert all references to use `sym::deref_method`
|
||||
|
||||
error: hardcoded path to a language item
|
||||
--> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
|
||||
|
|
||||
|
@ -23,5 +15,13 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
|
|||
|
|
||||
= help: convert all references to use `LangItem::DerefMut`
|
||||
|
||||
error: hardcoded path to a diagnostic item
|
||||
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
||||
|
|
||||
LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: convert all references to use `sym::deref_method`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -2,32 +2,117 @@
|
|||
|
||||
use core::ops::{Add, Neg};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
macro_rules! create {
|
||||
($name:ident) => {
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct $name;
|
||||
|
||||
impl Add<$name> for $name {
|
||||
type Output = $name;
|
||||
fn add(self, other: $name) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<i32> for $name {
|
||||
type Output = $name;
|
||||
fn add(self, other: i32) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<$name> for i32 {
|
||||
type Output = $name;
|
||||
fn add(self, other: $name) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<i64> for $name {
|
||||
type Output = $name;
|
||||
fn add(self, other: i64) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<$name> for i64 {
|
||||
type Output = $name;
|
||||
fn add(self, other: $name) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for $name {
|
||||
type Output = $name;
|
||||
fn neg(self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Add for Point {
|
||||
type Output = Self;
|
||||
create!(Foo);
|
||||
create!(Bar);
|
||||
create!(Baz);
|
||||
create!(OutOfNames);
|
||||
|
||||
fn add(self, other: Self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
fn lhs_and_rhs_are_equal() {
|
||||
// is explicitly on the list
|
||||
let _ = OutOfNames + OutOfNames;
|
||||
// is explicitly on the list
|
||||
let _ = Foo + Foo;
|
||||
// is implicitly on the list
|
||||
let _ = Bar + Bar;
|
||||
// not on the list
|
||||
let _ = Baz + Baz;
|
||||
}
|
||||
|
||||
impl Neg for Point {
|
||||
type Output = Self;
|
||||
fn lhs_is_different() {
|
||||
// is explicitly on the list
|
||||
let _ = 1i32 + OutOfNames;
|
||||
// is explicitly on the list
|
||||
let _ = 1i32 + Foo;
|
||||
// is implicitly on the list
|
||||
let _ = 1i32 + Bar;
|
||||
// not on the list
|
||||
let _ = 1i32 + Baz;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
todo!()
|
||||
}
|
||||
// not on the list
|
||||
let _ = 1i64 + Foo;
|
||||
// is implicitly on the list
|
||||
let _ = 1i64 + Bar;
|
||||
// not on the list
|
||||
let _ = 1i64 + Baz;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 };
|
||||
fn rhs_is_different() {
|
||||
// is explicitly on the list
|
||||
let _ = OutOfNames + 1i32;
|
||||
// is explicitly on the list
|
||||
let _ = Foo + 1i32;
|
||||
// is implicitly on the list
|
||||
let _ = Bar + 1i32;
|
||||
// not on the list
|
||||
let _ = Baz + 1i32;
|
||||
|
||||
let point: Point = Point { x: 1, y: 0 };
|
||||
let _ = point + point;
|
||||
let _ = -point;
|
||||
// not on the list
|
||||
let _ = Foo + 1i64;
|
||||
// is implicitly on the list
|
||||
let _ = Bar + 1i64;
|
||||
// not on the list
|
||||
let _ = Baz + 1i64;
|
||||
}
|
||||
|
||||
fn unary() {
|
||||
// is explicitly on the list
|
||||
let _ = -OutOfNames;
|
||||
// is specifically on the list
|
||||
let _ = -Foo;
|
||||
// not on the list
|
||||
let _ = -Bar;
|
||||
// not on the list
|
||||
let _ = -Baz;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:68:13
|
||||
|
|
||||
LL | let _ = Baz + Baz;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:79:13
|
||||
|
|
||||
LL | let _ = 1i32 + Baz;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:82:13
|
||||
|
|
||||
LL | let _ = 1i64 + Foo;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:86:13
|
||||
|
|
||||
LL | let _ = 1i64 + Baz;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:97:13
|
||||
|
|
||||
LL | let _ = Baz + 1i32;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:100:13
|
||||
|
|
||||
LL | let _ = Foo + 1i64;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:104:13
|
||||
|
|
||||
LL | let _ = Baz + 1i64;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:113:13
|
||||
|
|
||||
LL | let _ = -Bar;
|
||||
| ^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects_allowed.rs:115:13
|
||||
|
|
||||
LL | let _ = -Baz;
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
|
@ -1 +1,11 @@
|
|||
arithmetic-side-effects-allowed = ["Point"]
|
||||
arithmetic-side-effects-allowed = [
|
||||
"OutOfNames"
|
||||
]
|
||||
arithmetic-side-effects-allowed-binary = [
|
||||
["Foo", "Foo"],
|
||||
["Foo", "i32"],
|
||||
["i32", "Foo"],
|
||||
["Bar", "*"],
|
||||
["*", "Bar"],
|
||||
]
|
||||
arithmetic-side-effects-allowed-unary = ["Foo"]
|
||||
|
|
1
tests/ui-toml/suppress_lint_in_const/clippy.toml
Normal file
1
tests/ui-toml/suppress_lint_in_const/clippy.toml
Normal file
|
@ -0,0 +1 @@
|
|||
suppress-restriction-lint-in-const = true
|
60
tests/ui-toml/suppress_lint_in_const/test.rs
Normal file
60
tests/ui-toml/suppress_lint_in_const/test.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
#![feature(inline_const)]
|
||||
#![warn(clippy::indexing_slicing)]
|
||||
// We also check the out_of_bounds_indexing lint here, because it lints similar things and
|
||||
// we want to avoid false positives.
|
||||
#![warn(clippy::out_of_bounds_indexing)]
|
||||
#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
|
||||
|
||||
const ARR: [i32; 2] = [1, 2];
|
||||
const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
||||
const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
||||
|
||||
const fn idx() -> usize {
|
||||
1
|
||||
}
|
||||
const fn idx4() -> usize {
|
||||
4
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = [1, 2, 3, 4];
|
||||
let index: usize = 1;
|
||||
x[index];
|
||||
x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
|
||||
x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
|
||||
|
||||
x[0]; // Ok, should not produce stderr.
|
||||
x[3]; // Ok, should not produce stderr.
|
||||
x[const { idx() }]; // Ok, should not produce stderr.
|
||||
x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
|
||||
const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
||||
const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
||||
|
||||
let y = &x;
|
||||
y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
|
||||
y[4]; // Ok, rustc will handle references too.
|
||||
|
||||
let v = vec![0; 5];
|
||||
v[0];
|
||||
v[10];
|
||||
v[1 << 3];
|
||||
|
||||
const N: usize = 15; // Out of bounds
|
||||
const M: usize = 3; // In bounds
|
||||
x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
|
||||
x[M]; // Ok, should not produce stderr.
|
||||
v[N];
|
||||
v[M];
|
||||
}
|
||||
|
||||
/// An opaque integer representation
|
||||
pub struct Integer<'a> {
|
||||
/// The underlying data
|
||||
value: &'a [u8],
|
||||
}
|
||||
impl<'a> Integer<'a> {
|
||||
// Check whether `self` holds a negative number or not
|
||||
pub const fn is_negative(&self) -> bool {
|
||||
self.value[0] & 0b1000_0000 != 0
|
||||
}
|
||||
}
|
70
tests/ui-toml/suppress_lint_in_const/test.stderr
Normal file
70
tests/ui-toml/suppress_lint_in_const/test.stderr
Normal file
|
@ -0,0 +1,70 @@
|
|||
error[E0080]: evaluation of `main::{constant#3}` failed
|
||||
--> $DIR/test.rs:31:14
|
||||
|
|
||||
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
||||
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
||||
|
||||
note: erroneous constant used
|
||||
--> $DIR/test.rs:31:5
|
||||
|
|
||||
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/test.rs:22:5
|
||||
|
|
||||
LL | x[index];
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
= note: `-D clippy::indexing-slicing` implied by `-D warnings`
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/test.rs:38:5
|
||||
|
|
||||
LL | v[0];
|
||||
| ^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/test.rs:39:5
|
||||
|
|
||||
LL | v[10];
|
||||
| ^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/test.rs:40:5
|
||||
|
|
||||
LL | v[1 << 3];
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/test.rs:46:5
|
||||
|
|
||||
LL | v[N];
|
||||
| ^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/test.rs:47:5
|
||||
|
|
||||
LL | v[M];
|
||||
| ^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/test.rs:10:24
|
||||
|
|
||||
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
||||
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
|
@ -6,6 +6,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
|
|||
allow-unwrap-in-tests
|
||||
allowed-scripts
|
||||
arithmetic-side-effects-allowed
|
||||
arithmetic-side-effects-allowed-binary
|
||||
arithmetic-side-effects-allowed-unary
|
||||
array-size-threshold
|
||||
avoid-breaking-exported-api
|
||||
await-holding-invalid-types
|
||||
|
@ -35,6 +37,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
|
|||
pass-by-value-size-limit
|
||||
single-char-binding-names-threshold
|
||||
standard-macro-braces
|
||||
suppress-restriction-lint-in-const
|
||||
third-party
|
||||
too-large-for-stack
|
||||
too-many-arguments-threshold
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:29:17
|
||||
|
|
||||
LL | let _ = ('a') ..'z';
|
||||
| ^^^^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
|
||||
= note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:30:17
|
||||
|
|
||||
LL | let _ = 'A' .. ('Z');
|
||||
| ^^^^--^^^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:36:13
|
||||
|
|
||||
LL | let _ = (b'a')..(b'z');
|
||||
| ^^^^^^--^^^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:37:13
|
||||
|
|
||||
LL | let _ = b'A'..b'Z';
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:42:13
|
||||
|
|
||||
LL | let _ = a!()..'z';
|
||||
| ^^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:45:9
|
||||
|
|
||||
LL | b'a'..b'z' if true => 1,
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:46:9
|
||||
|
|
||||
LL | b'A'..b'Z' if true => 2,
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:53:9
|
||||
|
|
||||
LL | 'a'..'z' if true => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:54:9
|
||||
|
|
||||
LL | 'A'..'Z' if true => 2,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:22:17
|
||||
|
|
||||
LL | let _ = 'a'..'z';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
...
|
||||
LL | b!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:67:9
|
||||
|
|
||||
LL | 'a'..'z' => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `...`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:74:13
|
||||
|
|
||||
LL | let _ = 'a'..'z';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:76:9
|
||||
|
|
||||
LL | 'a'..'z' => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![warn(clippy::almost_complete_letter_range)]
|
||||
#![warn(clippy::almost_complete_range)]
|
||||
#![allow(ellipsis_inclusive_range_patterns)]
|
||||
#![allow(clippy::needless_parens_on_range_literals)]
|
||||
#![allow(clippy::double_parens)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate macro_rules;
|
||||
|
@ -16,10 +17,22 @@ macro_rules! a {
|
|||
'a'
|
||||
};
|
||||
}
|
||||
macro_rules! A {
|
||||
() => {
|
||||
'A'
|
||||
};
|
||||
}
|
||||
macro_rules! zero {
|
||||
() => {
|
||||
'0'
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! b {
|
||||
() => {
|
||||
let _ = 'a'..='z';
|
||||
let _ = 'A'..='Z';
|
||||
let _ = '0'..='9';
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,36 +41,46 @@ fn main() {
|
|||
{
|
||||
let _ = ('a') ..='z';
|
||||
let _ = 'A' ..= ('Z');
|
||||
let _ = ((('0'))) ..= ('9');
|
||||
}
|
||||
|
||||
let _ = 'b'..'z';
|
||||
let _ = 'B'..'Z';
|
||||
let _ = '1'..'9';
|
||||
|
||||
let _ = (b'a')..=(b'z');
|
||||
let _ = b'A'..=b'Z';
|
||||
let _ = b'0'..=b'9';
|
||||
|
||||
let _ = b'b'..b'z';
|
||||
let _ = b'B'..b'Z';
|
||||
let _ = b'1'..b'9';
|
||||
|
||||
let _ = a!()..='z';
|
||||
let _ = A!()..='Z';
|
||||
let _ = zero!()..='9';
|
||||
|
||||
let _ = match 0u8 {
|
||||
b'a'..=b'z' if true => 1,
|
||||
b'A'..=b'Z' if true => 2,
|
||||
b'b'..b'z' => 3,
|
||||
b'B'..b'Z' => 4,
|
||||
_ => 5,
|
||||
b'0'..=b'9' if true => 3,
|
||||
b'b'..b'z' => 4,
|
||||
b'B'..b'Z' => 5,
|
||||
b'1'..b'9' => 6,
|
||||
_ => 7,
|
||||
};
|
||||
|
||||
let _ = match 'x' {
|
||||
'a'..='z' if true => 1,
|
||||
'A'..='Z' if true => 2,
|
||||
'b'..'z' => 3,
|
||||
'B'..'Z' => 4,
|
||||
_ => 5,
|
||||
'0'..='9' if true => 3,
|
||||
'b'..'z' => 4,
|
||||
'B'..'Z' => 5,
|
||||
'1'..'9' => 6,
|
||||
_ => 7,
|
||||
};
|
||||
|
||||
almost_complete_letter_range!();
|
||||
almost_complete_range!();
|
||||
b!();
|
||||
}
|
||||
|
||||
|
@ -65,15 +88,21 @@ fn main() {
|
|||
fn _under_msrv() {
|
||||
let _ = match 'a' {
|
||||
'a'...'z' => 1,
|
||||
_ => 2,
|
||||
'A'...'Z' => 2,
|
||||
'0'...'9' => 3,
|
||||
_ => 4,
|
||||
};
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.26"]
|
||||
fn _meets_msrv() {
|
||||
let _ = 'a'..='z';
|
||||
let _ = 'A'..='Z';
|
||||
let _ = '0'..='9';
|
||||
let _ = match 'a' {
|
||||
'a'..='z' => 1,
|
||||
_ => 2,
|
||||
'A'..='Z' => 1,
|
||||
'0'..='9' => 3,
|
||||
_ => 4,
|
||||
};
|
||||
}
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![warn(clippy::almost_complete_letter_range)]
|
||||
#![warn(clippy::almost_complete_range)]
|
||||
#![allow(ellipsis_inclusive_range_patterns)]
|
||||
#![allow(clippy::needless_parens_on_range_literals)]
|
||||
#![allow(clippy::double_parens)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate macro_rules;
|
||||
|
@ -16,10 +17,22 @@ macro_rules! a {
|
|||
'a'
|
||||
};
|
||||
}
|
||||
macro_rules! A {
|
||||
() => {
|
||||
'A'
|
||||
};
|
||||
}
|
||||
macro_rules! zero {
|
||||
() => {
|
||||
'0'
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! b {
|
||||
() => {
|
||||
let _ = 'a'..'z';
|
||||
let _ = 'A'..'Z';
|
||||
let _ = '0'..'9';
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,36 +41,46 @@ fn main() {
|
|||
{
|
||||
let _ = ('a') ..'z';
|
||||
let _ = 'A' .. ('Z');
|
||||
let _ = ((('0'))) .. ('9');
|
||||
}
|
||||
|
||||
let _ = 'b'..'z';
|
||||
let _ = 'B'..'Z';
|
||||
let _ = '1'..'9';
|
||||
|
||||
let _ = (b'a')..(b'z');
|
||||
let _ = b'A'..b'Z';
|
||||
let _ = b'0'..b'9';
|
||||
|
||||
let _ = b'b'..b'z';
|
||||
let _ = b'B'..b'Z';
|
||||
let _ = b'1'..b'9';
|
||||
|
||||
let _ = a!()..'z';
|
||||
let _ = A!()..'Z';
|
||||
let _ = zero!()..'9';
|
||||
|
||||
let _ = match 0u8 {
|
||||
b'a'..b'z' if true => 1,
|
||||
b'A'..b'Z' if true => 2,
|
||||
b'b'..b'z' => 3,
|
||||
b'B'..b'Z' => 4,
|
||||
_ => 5,
|
||||
b'0'..b'9' if true => 3,
|
||||
b'b'..b'z' => 4,
|
||||
b'B'..b'Z' => 5,
|
||||
b'1'..b'9' => 6,
|
||||
_ => 7,
|
||||
};
|
||||
|
||||
let _ = match 'x' {
|
||||
'a'..'z' if true => 1,
|
||||
'A'..'Z' if true => 2,
|
||||
'b'..'z' => 3,
|
||||
'B'..'Z' => 4,
|
||||
_ => 5,
|
||||
'0'..'9' if true => 3,
|
||||
'b'..'z' => 4,
|
||||
'B'..'Z' => 5,
|
||||
'1'..'9' => 6,
|
||||
_ => 7,
|
||||
};
|
||||
|
||||
almost_complete_letter_range!();
|
||||
almost_complete_range!();
|
||||
b!();
|
||||
}
|
||||
|
||||
|
@ -65,15 +88,21 @@ fn main() {
|
|||
fn _under_msrv() {
|
||||
let _ = match 'a' {
|
||||
'a'..'z' => 1,
|
||||
_ => 2,
|
||||
'A'..'Z' => 2,
|
||||
'0'..'9' => 3,
|
||||
_ => 4,
|
||||
};
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.26"]
|
||||
fn _meets_msrv() {
|
||||
let _ = 'a'..'z';
|
||||
let _ = 'A'..'Z';
|
||||
let _ = '0'..'9';
|
||||
let _ = match 'a' {
|
||||
'a'..'z' => 1,
|
||||
_ => 2,
|
||||
'A'..'Z' => 1,
|
||||
'0'..'9' => 3,
|
||||
_ => 4,
|
||||
};
|
||||
}
|
235
tests/ui/almost_complete_range.stderr
Normal file
235
tests/ui/almost_complete_range.stderr
Normal file
|
@ -0,0 +1,235 @@
|
|||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:42:17
|
||||
|
|
||||
LL | let _ = ('a') ..'z';
|
||||
| ^^^^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
|
||||
= note: `-D clippy::almost-complete-range` implied by `-D warnings`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:43:17
|
||||
|
|
||||
LL | let _ = 'A' .. ('Z');
|
||||
| ^^^^--^^^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:44:17
|
||||
|
|
||||
LL | let _ = ((('0'))) .. ('9');
|
||||
| ^^^^^^^^^^--^^^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:51:13
|
||||
|
|
||||
LL | let _ = (b'a')..(b'z');
|
||||
| ^^^^^^--^^^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:52:13
|
||||
|
|
||||
LL | let _ = b'A'..b'Z';
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:53:13
|
||||
|
|
||||
LL | let _ = b'0'..b'9';
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:59:13
|
||||
|
|
||||
LL | let _ = a!()..'z';
|
||||
| ^^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:60:13
|
||||
|
|
||||
LL | let _ = A!()..'Z';
|
||||
| ^^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:61:13
|
||||
|
|
||||
LL | let _ = zero!()..'9';
|
||||
| ^^^^^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:64:9
|
||||
|
|
||||
LL | b'a'..b'z' if true => 1,
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:65:9
|
||||
|
|
||||
LL | b'A'..b'Z' if true => 2,
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:66:9
|
||||
|
|
||||
LL | b'0'..b'9' if true => 3,
|
||||
| ^^^^--^^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:74:9
|
||||
|
|
||||
LL | 'a'..'z' if true => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:75:9
|
||||
|
|
||||
LL | 'A'..'Z' if true => 2,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:76:9
|
||||
|
|
||||
LL | '0'..'9' if true => 3,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:33:17
|
||||
|
|
||||
LL | let _ = 'a'..'z';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
...
|
||||
LL | b!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:34:17
|
||||
|
|
||||
LL | let _ = 'A'..'Z';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
...
|
||||
LL | b!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:35:17
|
||||
|
|
||||
LL | let _ = '0'..'9';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
...
|
||||
LL | b!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:90:9
|
||||
|
|
||||
LL | 'a'..'z' => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `...`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:91:9
|
||||
|
|
||||
LL | 'A'..'Z' => 2,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `...`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:92:9
|
||||
|
|
||||
LL | '0'..'9' => 3,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `...`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:99:13
|
||||
|
|
||||
LL | let _ = 'a'..'z';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:100:13
|
||||
|
|
||||
LL | let _ = 'A'..'Z';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:101:13
|
||||
|
|
||||
LL | let _ = '0'..'9';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:103:9
|
||||
|
|
||||
LL | 'a'..'z' => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:104:9
|
||||
|
|
||||
LL | 'A'..'Z' => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii range
|
||||
--> $DIR/almost_complete_range.rs:105:9
|
||||
|
|
||||
LL | '0'..'9' => 3,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: aborting due to 27 previous errors
|
||||
|
|
@ -1,28 +1,10 @@
|
|||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:78:13
|
||||
|
|
||||
LL | let _ = String::new() + "";
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:86:27
|
||||
|
|
||||
LL | let inferred_string = string + "";
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:90:13
|
||||
|
|
||||
LL | let _ = inferred_string + "";
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:165:5
|
||||
|
|
||||
LL | _n += 1;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:166:5
|
||||
|
@ -348,5 +330,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec
|
|||
LL | _n = -&_n;
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 58 previous errors
|
||||
error: aborting due to 55 previous errors
|
||||
|
||||
|
|
|
@ -142,8 +142,10 @@ macro_rules! equatable_if_let {
|
|||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! almost_complete_letter_range {
|
||||
macro_rules! almost_complete_range {
|
||||
() => {
|
||||
let _ = 'a'..'z';
|
||||
let _ = 'A'..'Z';
|
||||
let _ = '0'..'9';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -45,3 +45,9 @@ mod cast_lossless_in_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[repr(i64)]
|
||||
enum Test {
|
||||
A = u32::MAX as i64 + 1,
|
||||
}
|
||||
|
|
|
@ -45,3 +45,9 @@ mod cast_lossless_in_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[repr(i64)]
|
||||
enum Test {
|
||||
A = u32::MAX as i64 + 1,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::collapsible_str_replace)]
|
||||
|
||||
fn get_filter() -> char {
|
||||
|
@ -71,3 +72,13 @@ fn main() {
|
|||
.replace('u', iter.next().unwrap())
|
||||
.replace('s', iter.next().unwrap());
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.57"]
|
||||
fn msrv_1_57() {
|
||||
let _ = "".replace('a', "1.57").replace('b', "1.57");
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.58"]
|
||||
fn msrv_1_58() {
|
||||
let _ = "".replace(['a', 'b'], "1.58");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::collapsible_str_replace)]
|
||||
|
||||
fn get_filter() -> char {
|
||||
|
@ -74,3 +75,13 @@ fn main() {
|
|||
.replace('u', iter.next().unwrap())
|
||||
.replace('s', iter.next().unwrap());
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.57"]
|
||||
fn msrv_1_57() {
|
||||
let _ = "".replace('a', "1.57").replace('b', "1.57");
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.58"]
|
||||
fn msrv_1_58() {
|
||||
let _ = "".replace('a', "1.58").replace('b', "1.58");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:19:27
|
||||
--> $DIR/collapsible_str_replace.rs:20:27
|
||||
|
|
||||
LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
|
||||
|
@ -7,19 +7,19 @@ LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
|
|||
= note: `-D clippy::collapsible-str-replace` implied by `-D warnings`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:21:27
|
||||
--> $DIR/collapsible_str_replace.rs:22:27
|
||||
|
|
||||
LL | let _ = "hesuo worpd".replace('s', l).replace('u', l);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:23:27
|
||||
--> $DIR/collapsible_str_replace.rs:24:27
|
||||
|
|
||||
LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:26:10
|
||||
--> $DIR/collapsible_str_replace.rs:27:10
|
||||
|
|
||||
LL | .replace('s', "l")
|
||||
| __________^
|
||||
|
@ -29,58 +29,64 @@ LL | | .replace('d', "l");
|
|||
| |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:31:27
|
||||
--> $DIR/collapsible_str_replace.rs:32:27
|
||||
|
|
||||
LL | let _ = "hesuo world".replace(s, "l").replace('u', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:33:27
|
||||
--> $DIR/collapsible_str_replace.rs:34:27
|
||||
|
|
||||
LL | let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:35:27
|
||||
--> $DIR/collapsible_str_replace.rs:36:27
|
||||
|
|
||||
LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:37:27
|
||||
--> $DIR/collapsible_str_replace.rs:38:27
|
||||
|
|
||||
LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:39:27
|
||||
--> $DIR/collapsible_str_replace.rs:40:27
|
||||
|
|
||||
LL | let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:41:45
|
||||
--> $DIR/collapsible_str_replace.rs:42:45
|
||||
|
|
||||
LL | let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:44:47
|
||||
--> $DIR/collapsible_str_replace.rs:45:47
|
||||
|
|
||||
LL | let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:46:28
|
||||
--> $DIR/collapsible_str_replace.rs:47:28
|
||||
|
|
||||
LL | let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")`
|
||||
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:48:27
|
||||
--> $DIR/collapsible_str_replace.rs:49:27
|
||||
|
|
||||
LL | let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: used consecutive `str::replace` call
|
||||
--> $DIR/collapsible_str_replace.rs:86:16
|
||||
|
|
||||
LL | let _ = "".replace('a', "1.58").replace('b', "1.58");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['a', 'b'], "1.58")`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
|
|
@ -189,3 +189,33 @@ mod issue_7920 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod issue_10058 {
|
||||
pub fn test() {
|
||||
// should not lint since we are increasing counter potentially more than once in the loop
|
||||
let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
|
||||
let mut counter = 0;
|
||||
for value in values {
|
||||
counter += 1;
|
||||
|
||||
if value == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test2() {
|
||||
// should not lint since we are increasing counter potentially more than once in the loop
|
||||
let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
|
||||
let mut counter = 0;
|
||||
for value in values {
|
||||
counter += 1;
|
||||
|
||||
if value != 0 {
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![warn(clippy::from_over_into)]
|
||||
#![allow(unused)]
|
||||
|
||||
|
@ -81,4 +82,10 @@ fn msrv_1_41() {
|
|||
}
|
||||
}
|
||||
|
||||
type Opaque = impl Sized;
|
||||
struct IntoOpaque;
|
||||
impl Into<Opaque> for IntoOpaque {
|
||||
fn into(self) -> Opaque {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![warn(clippy::from_over_into)]
|
||||
#![allow(unused)]
|
||||
|
||||
|
@ -81,4 +82,10 @@ fn msrv_1_41() {
|
|||
}
|
||||
}
|
||||
|
||||
type Opaque = impl Sized;
|
||||
struct IntoOpaque;
|
||||
impl Into<Opaque> for IntoOpaque {
|
||||
fn into(self) -> Opaque {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into.rs:9:1
|
||||
--> $DIR/from_over_into.rs:10:1
|
||||
|
|
||||
LL | impl Into<StringWrapper> for String {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -13,7 +13,7 @@ LL ~ StringWrapper(val)
|
|||
|
|
||||
|
||||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into.rs:17:1
|
||||
--> $DIR/from_over_into.rs:18:1
|
||||
|
|
||||
LL | impl Into<SelfType> for String {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -26,7 +26,7 @@ LL ~ SelfType(String::new())
|
|||
|
|
||||
|
||||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into.rs:32:1
|
||||
--> $DIR/from_over_into.rs:33:1
|
||||
|
|
||||
LL | impl Into<SelfKeywords> for X {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -41,7 +41,7 @@ LL ~ let _: X = val;
|
|||
|
|
||||
|
||||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into.rs:44:1
|
||||
--> $DIR/from_over_into.rs:45:1
|
||||
|
|
||||
LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -59,7 +59,7 @@ LL ~ val.0
|
|||
|
|
||||
|
||||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into.rs:77:5
|
||||
--> $DIR/from_over_into.rs:78:5
|
||||
|
|
||||
LL | impl<T> Into<FromOverInto<T>> for Vec<T> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -65,7 +65,7 @@ fn main() {
|
|||
42;
|
||||
1;
|
||||
42;
|
||||
&x;
|
||||
x;
|
||||
x;
|
||||
|
||||
let mut a = A(String::new());
|
||||
|
@ -112,6 +112,10 @@ fn main() {
|
|||
2 * { a };
|
||||
(({ a } + 4));
|
||||
1;
|
||||
|
||||
// Issue #9904
|
||||
let x = 0i32;
|
||||
let _: i32 = x;
|
||||
}
|
||||
|
||||
pub fn decide(a: bool, b: bool) -> u32 {
|
||||
|
|
|
@ -112,6 +112,10 @@ fn main() {
|
|||
2 * (0 + { a });
|
||||
1 * ({ a } + 4);
|
||||
1 * 1;
|
||||
|
||||
// Issue #9904
|
||||
let x = 0i32;
|
||||
let _: i32 = &x + 0;
|
||||
}
|
||||
|
||||
pub fn decide(a: bool, b: bool) -> u32 {
|
||||
|
|
|
@ -70,7 +70,7 @@ error: this operation has no effect
|
|||
--> $DIR/identity_op.rs:68:5
|
||||
|
|
||||
LL | &x >> 0;
|
||||
| ^^^^^^^ help: consider reducing it to: `&x`
|
||||
| ^^^^^^^ help: consider reducing it to: `x`
|
||||
|
||||
error: this operation has no effect
|
||||
--> $DIR/identity_op.rs:69:5
|
||||
|
@ -229,10 +229,16 @@ LL | 1 * 1;
|
|||
| ^^^^^ help: consider reducing it to: `1`
|
||||
|
||||
error: this operation has no effect
|
||||
--> $DIR/identity_op.rs:118:5
|
||||
--> $DIR/identity_op.rs:118:18
|
||||
|
|
||||
LL | let _: i32 = &x + 0;
|
||||
| ^^^^^^ help: consider reducing it to: `x`
|
||||
|
||||
error: this operation has no effect
|
||||
--> $DIR/identity_op.rs:122:5
|
||||
|
|
||||
LL | 0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if a { 1 } else { 2 })`
|
||||
|
||||
error: aborting due to 39 previous errors
|
||||
error: aborting due to 40 previous errors
|
||||
|
||||
|
|
|
@ -115,4 +115,14 @@ fn main() {
|
|||
let pathbuf_ref = &pathbuf_ref;
|
||||
let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
|
||||
let _ = (**pathbuf_ref).clone();
|
||||
|
||||
struct NoClone;
|
||||
impl ToOwned for NoClone {
|
||||
type Owned = Self;
|
||||
fn to_owned(&self) -> Self {
|
||||
NoClone
|
||||
}
|
||||
}
|
||||
let no_clone = &NoClone;
|
||||
let _ = no_clone.to_owned();
|
||||
}
|
||||
|
|
|
@ -115,4 +115,14 @@ fn main() {
|
|||
let pathbuf_ref = &pathbuf_ref;
|
||||
let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
|
||||
let _ = pathbuf_ref.to_path_buf();
|
||||
|
||||
struct NoClone;
|
||||
impl ToOwned for NoClone {
|
||||
type Owned = Self;
|
||||
fn to_owned(&self) -> Self {
|
||||
NoClone
|
||||
}
|
||||
}
|
||||
let no_clone = &NoClone;
|
||||
let _ = no_clone.to_owned();
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
|
||||
|
||||
const ARR: [i32; 2] = [1, 2];
|
||||
const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
|
||||
const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
||||
|
||||
const fn idx() -> usize {
|
||||
|
@ -27,8 +27,8 @@ fn main() {
|
|||
x[3]; // Ok, should not produce stderr.
|
||||
x[const { idx() }]; // Ok, should not produce stderr.
|
||||
x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
|
||||
const { &ARR[idx()] }; // Ok, should not produce stderr.
|
||||
const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
|
||||
const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
|
||||
let y = &x;
|
||||
y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
|
||||
|
|
|
@ -1,13 +1,32 @@
|
|||
error: indexing may panic
|
||||
--> $DIR/indexing_slicing_index.rs:9:20
|
||||
|
|
||||
LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
= note: the suggestion might not be applicable in constant blocks
|
||||
= note: `-D clippy::indexing-slicing` implied by `-D warnings`
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/indexing_slicing_index.rs:10:24
|
||||
|
|
||||
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
= note: the suggestion might not be applicable in constant blocks
|
||||
|
||||
error[E0080]: evaluation of `main::{constant#3}` failed
|
||||
--> $DIR/indexing_slicing_index.rs:31:14
|
||||
|
|
||||
LL | const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
|
||||
LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
||||
|
||||
note: erroneous constant used
|
||||
--> $DIR/indexing_slicing_index.rs:31:5
|
||||
|
|
||||
LL | const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
|
||||
LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: indexing may panic
|
||||
|
@ -17,7 +36,24 @@ LL | x[index];
|
|||
| ^^^^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
= note: `-D clippy::indexing-slicing` implied by `-D warnings`
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/indexing_slicing_index.rs:30:14
|
||||
|
|
||||
LL | const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
= note: the suggestion might not be applicable in constant blocks
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/indexing_slicing_index.rs:31:14
|
||||
|
|
||||
LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using `.get(n)` or `.get_mut(n)` instead
|
||||
= note: the suggestion might not be applicable in constant blocks
|
||||
|
||||
error: indexing may panic
|
||||
--> $DIR/indexing_slicing_index.rs:38:5
|
||||
|
@ -65,6 +101,6 @@ error[E0080]: evaluation of constant value failed
|
|||
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
|
||||
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#![warn(clippy::len_zero)]
|
||||
#![allow(dead_code, unused, clippy::len_without_is_empty)]
|
||||
|
||||
extern crate core;
|
||||
use core::ops::Deref;
|
||||
|
||||
pub struct One;
|
||||
struct Wither;
|
||||
|
||||
|
@ -56,6 +59,26 @@ impl WithIsEmpty for Wither {
|
|||
}
|
||||
}
|
||||
|
||||
struct DerefToDerefToString;
|
||||
|
||||
impl Deref for DerefToDerefToString {
|
||||
type Target = DerefToString;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&DerefToString {}
|
||||
}
|
||||
}
|
||||
|
||||
struct DerefToString;
|
||||
|
||||
impl Deref for DerefToString {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
"Hello, world!"
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = [1, 2];
|
||||
if x.is_empty() {
|
||||
|
@ -64,6 +87,23 @@ fn main() {
|
|||
|
||||
if "".is_empty() {}
|
||||
|
||||
let s = "Hello, world!";
|
||||
let s1 = &s;
|
||||
let s2 = &s1;
|
||||
let s3 = &s2;
|
||||
let s4 = &s3;
|
||||
let s5 = &s4;
|
||||
let s6 = &s5;
|
||||
println!("{}", s1.is_empty());
|
||||
println!("{}", s2.is_empty());
|
||||
println!("{}", s3.is_empty());
|
||||
println!("{}", s4.is_empty());
|
||||
println!("{}", s5.is_empty());
|
||||
println!("{}", (s6).is_empty());
|
||||
|
||||
let d2s = DerefToDerefToString {};
|
||||
println!("{}", (**d2s).is_empty());
|
||||
|
||||
let y = One;
|
||||
if y.len() == 0 {
|
||||
// No error; `One` does not have `.is_empty()`.
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#![warn(clippy::len_zero)]
|
||||
#![allow(dead_code, unused, clippy::len_without_is_empty)]
|
||||
|
||||
extern crate core;
|
||||
use core::ops::Deref;
|
||||
|
||||
pub struct One;
|
||||
struct Wither;
|
||||
|
||||
|
@ -56,6 +59,26 @@ impl WithIsEmpty for Wither {
|
|||
}
|
||||
}
|
||||
|
||||
struct DerefToDerefToString;
|
||||
|
||||
impl Deref for DerefToDerefToString {
|
||||
type Target = DerefToString;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&DerefToString {}
|
||||
}
|
||||
}
|
||||
|
||||
struct DerefToString;
|
||||
|
||||
impl Deref for DerefToString {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
"Hello, world!"
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = [1, 2];
|
||||
if x.len() == 0 {
|
||||
|
@ -64,6 +87,23 @@ fn main() {
|
|||
|
||||
if "".len() == 0 {}
|
||||
|
||||
let s = "Hello, world!";
|
||||
let s1 = &s;
|
||||
let s2 = &s1;
|
||||
let s3 = &s2;
|
||||
let s4 = &s3;
|
||||
let s5 = &s4;
|
||||
let s6 = &s5;
|
||||
println!("{}", *s1 == "");
|
||||
println!("{}", **s2 == "");
|
||||
println!("{}", ***s3 == "");
|
||||
println!("{}", ****s4 == "");
|
||||
println!("{}", *****s5 == "");
|
||||
println!("{}", ******(s6) == "");
|
||||
|
||||
let d2s = DerefToDerefToString {};
|
||||
println!("{}", &**d2s == "");
|
||||
|
||||
let y = One;
|
||||
if y.len() == 0 {
|
||||
// No error; `One` does not have `.is_empty()`.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:61:8
|
||||
--> $DIR/len_zero.rs:84:8
|
||||
|
|
||||
LL | if x.len() == 0 {
|
||||
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
|
||||
|
@ -7,82 +7,126 @@ LL | if x.len() == 0 {
|
|||
= note: `-D clippy::len-zero` implied by `-D warnings`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:65:8
|
||||
--> $DIR/len_zero.rs:88:8
|
||||
|
|
||||
LL | if "".len() == 0 {}
|
||||
| ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
|
||||
|
||||
error: comparison to empty slice
|
||||
--> $DIR/len_zero.rs:97:20
|
||||
|
|
||||
LL | println!("{}", *s1 == "");
|
||||
| ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
|
||||
|
|
||||
= note: `-D clippy::comparison-to-empty` implied by `-D warnings`
|
||||
|
||||
error: comparison to empty slice
|
||||
--> $DIR/len_zero.rs:98:20
|
||||
|
|
||||
LL | println!("{}", **s2 == "");
|
||||
| ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
|
||||
|
||||
error: comparison to empty slice
|
||||
--> $DIR/len_zero.rs:99:20
|
||||
|
|
||||
LL | println!("{}", ***s3 == "");
|
||||
| ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
|
||||
|
||||
error: comparison to empty slice
|
||||
--> $DIR/len_zero.rs:100:20
|
||||
|
|
||||
LL | println!("{}", ****s4 == "");
|
||||
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
|
||||
|
||||
error: comparison to empty slice
|
||||
--> $DIR/len_zero.rs:101:20
|
||||
|
|
||||
LL | println!("{}", *****s5 == "");
|
||||
| ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
|
||||
|
||||
error: comparison to empty slice
|
||||
--> $DIR/len_zero.rs:102:20
|
||||
|
|
||||
LL | println!("{}", ******(s6) == "");
|
||||
| ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
|
||||
|
||||
error: comparison to empty slice
|
||||
--> $DIR/len_zero.rs:105:20
|
||||
|
|
||||
LL | println!("{}", &**d2s == "");
|
||||
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:80:8
|
||||
--> $DIR/len_zero.rs:120:8
|
||||
|
|
||||
LL | if has_is_empty.len() == 0 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:83:8
|
||||
--> $DIR/len_zero.rs:123:8
|
||||
|
|
||||
LL | if has_is_empty.len() != 0 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:86:8
|
||||
--> $DIR/len_zero.rs:126:8
|
||||
|
|
||||
LL | if has_is_empty.len() > 0 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to one
|
||||
--> $DIR/len_zero.rs:89:8
|
||||
--> $DIR/len_zero.rs:129:8
|
||||
|
|
||||
LL | if has_is_empty.len() < 1 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to one
|
||||
--> $DIR/len_zero.rs:92:8
|
||||
--> $DIR/len_zero.rs:132:8
|
||||
|
|
||||
LL | if has_is_empty.len() >= 1 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:103:8
|
||||
--> $DIR/len_zero.rs:143:8
|
||||
|
|
||||
LL | if 0 == has_is_empty.len() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:106:8
|
||||
--> $DIR/len_zero.rs:146:8
|
||||
|
|
||||
LL | if 0 != has_is_empty.len() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:109:8
|
||||
--> $DIR/len_zero.rs:149:8
|
||||
|
|
||||
LL | if 0 < has_is_empty.len() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to one
|
||||
--> $DIR/len_zero.rs:112:8
|
||||
--> $DIR/len_zero.rs:152:8
|
||||
|
|
||||
LL | if 1 <= has_is_empty.len() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to one
|
||||
--> $DIR/len_zero.rs:115:8
|
||||
--> $DIR/len_zero.rs:155:8
|
||||
|
|
||||
LL | if 1 > has_is_empty.len() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:129:8
|
||||
--> $DIR/len_zero.rs:169:8
|
||||
|
|
||||
LL | if with_is_empty.len() == 0 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
|
||||
|
||||
error: length comparison to zero
|
||||
--> $DIR/len_zero.rs:142:8
|
||||
--> $DIR/len_zero.rs:182:8
|
||||
|
|
||||
LL | if b.len() != 0 {}
|
||||
| ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: aborting due to 21 previous errors
|
||||
|
||||
|
|
|
@ -62,6 +62,11 @@ fn main() {
|
|||
panic!("panic5");
|
||||
}
|
||||
assert!(!a.is_empty(), "with expansion {}", one!());
|
||||
if a.is_empty() {
|
||||
let _ = 0;
|
||||
} else if a.len() == 1 {
|
||||
panic!("panic6");
|
||||
}
|
||||
}
|
||||
|
||||
fn issue7730(a: u8) {
|
||||
|
|
|
@ -50,6 +50,11 @@ fn main() {
|
|||
assert!(!(b.is_empty() || a.is_empty()), "panic4");
|
||||
assert!(!(a.is_empty() || !b.is_empty()), "panic5");
|
||||
assert!(!a.is_empty(), "with expansion {}", one!());
|
||||
if a.is_empty() {
|
||||
let _ = 0;
|
||||
} else if a.len() == 1 {
|
||||
panic!("panic6");
|
||||
}
|
||||
}
|
||||
|
||||
fn issue7730(a: u8) {
|
||||
|
|
|
@ -65,7 +65,7 @@ LL | | }
|
|||
| |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
|
||||
|
||||
error: only a `panic!` in `if`-then statement
|
||||
--> $DIR/manual_assert.rs:73:5
|
||||
--> $DIR/manual_assert.rs:78:5
|
||||
|
|
||||
LL | / if a > 2 {
|
||||
LL | | // comment
|
||||
|
|
|
@ -66,6 +66,11 @@ fn main() {
|
|||
if a.is_empty() {
|
||||
panic!("with expansion {}", one!())
|
||||
}
|
||||
if a.is_empty() {
|
||||
let _ = 0;
|
||||
} else if a.len() == 1 {
|
||||
panic!("panic6");
|
||||
}
|
||||
}
|
||||
|
||||
fn issue7730(a: u8) {
|
||||
|
|
|
@ -15,6 +15,19 @@ fn main() {
|
|||
assert!('x'.is_ascii_alphabetic());
|
||||
|
||||
assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
|
||||
|
||||
b'0'.is_ascii_digit();
|
||||
b'a'.is_ascii_lowercase();
|
||||
b'A'.is_ascii_uppercase();
|
||||
|
||||
'0'.is_ascii_digit();
|
||||
'a'.is_ascii_lowercase();
|
||||
'A'.is_ascii_uppercase();
|
||||
|
||||
let cool_letter = &'g';
|
||||
cool_letter.is_ascii_digit();
|
||||
cool_letter.is_ascii_lowercase();
|
||||
cool_letter.is_ascii_uppercase();
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.23"]
|
||||
|
|
|
@ -15,6 +15,19 @@ fn main() {
|
|||
assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
||||
|
||||
assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
|
||||
|
||||
(b'0'..=b'9').contains(&b'0');
|
||||
(b'a'..=b'z').contains(&b'a');
|
||||
(b'A'..=b'Z').contains(&b'A');
|
||||
|
||||
('0'..='9').contains(&'0');
|
||||
('a'..='z').contains(&'a');
|
||||
('A'..='Z').contains(&'A');
|
||||
|
||||
let cool_letter = &'g';
|
||||
('0'..='9').contains(cool_letter);
|
||||
('a'..='z').contains(cool_letter);
|
||||
('A'..='Z').contains(cool_letter);
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.23"]
|
||||
|
|
|
@ -43,28 +43,82 @@ LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:29:13
|
||||
--> $DIR/manual_is_ascii_check.rs:19:5
|
||||
|
|
||||
LL | (b'0'..=b'9').contains(&b'0');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'0'.is_ascii_digit()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:20:5
|
||||
|
|
||||
LL | (b'a'..=b'z').contains(&b'a');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'a'.is_ascii_lowercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:21:5
|
||||
|
|
||||
LL | (b'A'..=b'Z').contains(&b'A');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'A'.is_ascii_uppercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:23:5
|
||||
|
|
||||
LL | ('0'..='9').contains(&'0');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'0'.is_ascii_digit()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:24:5
|
||||
|
|
||||
LL | ('a'..='z').contains(&'a');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'a'.is_ascii_lowercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:25:5
|
||||
|
|
||||
LL | ('A'..='Z').contains(&'A');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'A'.is_ascii_uppercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:28:5
|
||||
|
|
||||
LL | ('0'..='9').contains(cool_letter);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:29:5
|
||||
|
|
||||
LL | ('a'..='z').contains(cool_letter);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:30:5
|
||||
|
|
||||
LL | ('A'..='Z').contains(cool_letter);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:42:13
|
||||
|
|
||||
LL | assert!(matches!(b'1', b'0'..=b'9'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:30:13
|
||||
--> $DIR/manual_is_ascii_check.rs:43:13
|
||||
|
|
||||
LL | assert!(matches!('X', 'A'..='Z'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:31:13
|
||||
--> $DIR/manual_is_ascii_check.rs:44:13
|
||||
|
|
||||
LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:41:23
|
||||
--> $DIR/manual_is_ascii_check.rs:54:23
|
||||
|
|
||||
LL | const FOO: bool = matches!('x', '0'..='9');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
|
|
|
@ -64,6 +64,13 @@ fn fire() {
|
|||
Ok(v) => v,
|
||||
Err(()) => return,
|
||||
};
|
||||
|
||||
let f = Variant::Bar(1);
|
||||
|
||||
let _value = match f {
|
||||
Variant::Bar(_) | Variant::Baz(_) => (),
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
|
||||
fn not_fire() {
|
||||
|
|
|
@ -25,7 +25,7 @@ LL | / let v = match h() {
|
|||
LL | | (Some(_), Some(_)) | (None, None) => continue,
|
||||
LL | | (Some(v), None) | (None, Some(v)) => v,
|
||||
LL | | };
|
||||
| |__________^ help: consider writing: `let (Some(v), None) | (None, Some(v)) = h() else { continue };`
|
||||
| |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else_match.rs:49:9
|
||||
|
@ -34,7 +34,7 @@ LL | / let v = match build_enum() {
|
|||
LL | | _ => continue,
|
||||
LL | | Variant::Bar(v) | Variant::Baz(v) => v,
|
||||
LL | | };
|
||||
| |__________^ help: consider writing: `let Variant::Bar(v) | Variant::Baz(v) = build_enum() else { continue };`
|
||||
| |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else_match.rs:57:5
|
||||
|
@ -54,5 +54,14 @@ LL | | Err(()) => return,
|
|||
LL | | };
|
||||
| |______^ help: consider writing: `let Ok(v) = f().map_err(|_| ()) else { return };`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else_match.rs:70:5
|
||||
|
|
||||
LL | / let _value = match f {
|
||||
LL | | Variant::Bar(_) | Variant::Baz(_) => (),
|
||||
LL | | _ => return,
|
||||
LL | | };
|
||||
| |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// edition:2018
|
||||
|
||||
#![warn(clippy::needless_parens_on_range_literals)]
|
||||
#![allow(clippy::almost_complete_letter_range)]
|
||||
#![allow(clippy::almost_complete_range)]
|
||||
|
||||
fn main() {
|
||||
let _ = 'a'..='z';
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// edition:2018
|
||||
|
||||
#![warn(clippy::needless_parens_on_range_literals)]
|
||||
#![allow(clippy::almost_complete_letter_range)]
|
||||
#![allow(clippy::almost_complete_range)]
|
||||
|
||||
fn main() {
|
||||
let _ = ('a')..=('z');
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
#![warn(clippy::new_ret_no_self)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
@ -400,3 +401,25 @@ mod issue7344 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod issue10041 {
|
||||
struct Bomb;
|
||||
|
||||
impl Bomb {
|
||||
// Hidden <Rhs = Self> default generic paramter.
|
||||
pub fn new() -> impl PartialOrd {
|
||||
0i32
|
||||
}
|
||||
}
|
||||
|
||||
// TAIT with self-referencing bounds
|
||||
type X = impl std::ops::Add<Output = X>;
|
||||
|
||||
struct Bomb2;
|
||||
|
||||
impl Bomb2 {
|
||||
pub fn new() -> X {
|
||||
0i32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:49:5
|
||||
--> $DIR/new_ret_no_self.rs:50:5
|
||||
|
|
||||
LL | / pub fn new(_: String) -> impl R<Item = u32> {
|
||||
LL | | S3
|
||||
|
@ -9,7 +9,7 @@ LL | | }
|
|||
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:81:5
|
||||
--> $DIR/new_ret_no_self.rs:82:5
|
||||
|
|
||||
LL | / pub fn new() -> u32 {
|
||||
LL | | unimplemented!();
|
||||
|
@ -17,7 +17,7 @@ LL | | }
|
|||
| |_____^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:90:5
|
||||
--> $DIR/new_ret_no_self.rs:91:5
|
||||
|
|
||||
LL | / pub fn new(_: String) -> u32 {
|
||||
LL | | unimplemented!();
|
||||
|
@ -25,7 +25,7 @@ LL | | }
|
|||
| |_____^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:126:5
|
||||
--> $DIR/new_ret_no_self.rs:127:5
|
||||
|
|
||||
LL | / pub fn new() -> (u32, u32) {
|
||||
LL | | unimplemented!();
|
||||
|
@ -33,7 +33,7 @@ LL | | }
|
|||
| |_____^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:153:5
|
||||
--> $DIR/new_ret_no_self.rs:154:5
|
||||
|
|
||||
LL | / pub fn new() -> *mut V {
|
||||
LL | | unimplemented!();
|
||||
|
@ -41,7 +41,7 @@ LL | | }
|
|||
| |_____^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:171:5
|
||||
--> $DIR/new_ret_no_self.rs:172:5
|
||||
|
|
||||
LL | / pub fn new() -> Option<u32> {
|
||||
LL | | unimplemented!();
|
||||
|
@ -49,19 +49,19 @@ LL | | }
|
|||
| |_____^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:224:9
|
||||
--> $DIR/new_ret_no_self.rs:225:9
|
||||
|
|
||||
LL | fn new() -> String;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:236:9
|
||||
--> $DIR/new_ret_no_self.rs:237:9
|
||||
|
|
||||
LL | fn new(_: String) -> String;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:271:9
|
||||
--> $DIR/new_ret_no_self.rs:272:9
|
||||
|
|
||||
LL | / fn new() -> (u32, u32) {
|
||||
LL | | unimplemented!();
|
||||
|
@ -69,7 +69,7 @@ LL | | }
|
|||
| |_________^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:298:9
|
||||
--> $DIR/new_ret_no_self.rs:299:9
|
||||
|
|
||||
LL | / fn new() -> *mut V {
|
||||
LL | | unimplemented!();
|
||||
|
@ -77,7 +77,7 @@ LL | | }
|
|||
| |_________^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:368:9
|
||||
--> $DIR/new_ret_no_self.rs:369:9
|
||||
|
|
||||
LL | / fn new(t: T) -> impl Into<i32> {
|
||||
LL | | 1
|
||||
|
@ -85,12 +85,28 @@ LL | | }
|
|||
| |_________^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:389:9
|
||||
--> $DIR/new_ret_no_self.rs:390:9
|
||||
|
|
||||
LL | / fn new(t: T) -> impl Trait2<(), i32> {
|
||||
LL | | unimplemented!()
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:410:9
|
||||
|
|
||||
LL | / pub fn new() -> impl PartialOrd {
|
||||
LL | | 0i32
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:421:9
|
||||
|
|
||||
LL | / pub fn new() -> X {
|
||||
LL | | 0i32
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
|
|
@ -39,8 +39,14 @@ static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static
|
|||
|
||||
static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
|
||||
|
||||
static mut STATIC_MUT_SLICE: &mut [u32] = &mut [0];
|
||||
|
||||
fn main() {
|
||||
let false_positive: &'static str = "test";
|
||||
|
||||
unsafe {
|
||||
STATIC_MUT_SLICE[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue