diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 6448b2d4068..1bc457a9479 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 23912bb3ed6..903ee938d9d 100644 --- a/CHANGELOG.md +++ b/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 diff --git a/Cargo.toml b/Cargo.toml index fe425a2fb99..f8cb4b7219c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/book/src/README.md b/book/src/README.md index 6248d588a89..23867df8efe 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -1,6 +1,6 @@ # Clippy -[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto) +[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto) [![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license) A collection of lints to catch common mistakes and improve your diff --git a/build.rs b/build.rs index b5484bec3c8..b79d09b0dd2 100644 --- a/build.rs +++ b/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!(); } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index aedff24c12c..a9f69b1ba63 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -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" diff --git a/clippy_lints/src/almost_complete_letter_range.rs b/clippy_lints/src/almost_complete_range.rs similarity index 85% rename from clippy_lints/src/almost_complete_letter_range.rs rename to clippy_lints/src/almost_complete_range.rs index 52beaf504a4..42e14b5cd94 100644 --- a/clippy_lints/src/almost_complete_letter_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -10,8 +10,8 @@ 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 @@ /// 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( diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 36daceabe0b..91900542af8 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -30,7 +30,7 @@ /// ```rust /// let x: Box = 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()" diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index c6d505c4a18..161e3a698e9 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -641,7 +641,7 @@ /// ```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" diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index e4d76f07d6b..3cd7d1d7e72 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -35,7 +35,7 @@ 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 @@ 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, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 31183266acf..7b43d8ccc67 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -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() }, diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 3f0b165f2b6..cf3483d4c00 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -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, })))) diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 68122b4cef5..1971cab64ef 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -47,7 +47,7 @@ /// value: usize, /// } /// ``` - #[clippy::version = "1.65.0"] + #[clippy::version = "1.66.0"] pub DISALLOWED_MACROS, style, "use of a disallowed macro" diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 111b624f529..69f7c152fc4 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -2,7 +2,8 @@ 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 @@ /// /// 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; } diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 0634b2798fe..a92f7548ff2 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -10,7 +10,7 @@ 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 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { && 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, diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index bf1351829c6..6e19343931e 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -31,7 +31,7 @@ /// /// 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" diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 4cd7dff4cfd..eebfb753a0c 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -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 @@ "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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { (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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { } } - 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); + } + }); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 73841f9aa9a..e88d1764a24 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -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 @@ 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, ); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7b17d8a156d..39850d59803 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -66,7 +66,7 @@ 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 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::::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::::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` } diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index b6f4cf7bbb3..28ee24309cc 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -25,7 +25,6 @@ pub(super) struct IncrementVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, // context reference states: HirIdMap, // incremented variables depth: u32, // depth of conditional expressions - done: bool, } impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { @@ -34,7 +33,6 @@ pub(super) fn new(cx: &'a LateContext<'tcx>) -> Self { cx, states: HirIdMap::default(), depth: 0, - done: false, } } @@ -51,10 +49,6 @@ pub(super) fn into_results(self) -> impl Iterator { 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 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { 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); } diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index b8ed9b9ec18..4277455a3a2 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -2,7 +2,7 @@ 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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { 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); diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 5ab049d8d13..d9ef7dffa02 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -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 @@ /// 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 @@ /// 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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { 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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { 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) => { diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 874d36ca9f4..9c6f8b43c07 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -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); }, ); diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index c1e6c82487d..72cdb9c1736 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -70,7 +70,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { && 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); diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 429cdc1918d..06ecbce4e70 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -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; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d2913680cbb..561e4336593 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3059,7 +3059,7 @@ /// let map: HashMap = HashMap::new(); /// let values = map.values().collect::>(); /// ``` - #[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 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { 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); } }, diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs index 7e3bed1e41a..660b7049cce 100644 --- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs +++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs @@ -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 && diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 516dee20f8b..9f4beb92b9d 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -9,12 +9,14 @@ }; 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 @@ "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 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { 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); + } } } } diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs index 20b82d81a2a..4fbc8398e37 100644 --- a/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -5,25 +5,26 @@ 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, + allowed_binary: FxHashMap>, + allowed_unary: FxHashSet, // Used to check whether expressions are constants, such as in enum discriminants and consts const_span: Option, expr_span: Option, @@ -33,19 +34,55 @@ pub struct ArithmeticSideEffects { impl ArithmeticSideEffects { #[must_use] - pub fn new(mut allowed: FxHashSet) -> Self { - allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from)); + pub fn new(user_allowed_binary: Vec<[String; 2]>, user_allowed_unary: Vec) -> Self { + let mut allowed_binary: FxHashMap> = <_>::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 @@ fn manage_bin_ops<'tcx>( }; 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 @@ fn manage_unary_ops<'tcx>( 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; diff --git a/clippy_lints/src/operators/identity_op.rs b/clippy_lints/src/operators/identity_op.rs index b48d6c4e2e2..14a12da862e 100644 --- a/clippy_lints/src/operators/identity_op.rs +++ b/clippy_lints/src/operators/identity_op.rs @@ -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), _ => (), diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index b8a20d5ebe9..eba230da6c3 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -90,9 +90,6 @@ /// 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, diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index d612d249c2f..c2a8db7df03 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -84,7 +84,11 @@ fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { 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 { diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 3aa2490bc44..41f991a967b 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -66,7 +66,7 @@ fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) { 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, ""); - let sugg = format!("&{snip}"); + let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str()); span_lint_and_then( cx, REDUNDANT_STATIC_LIFETIMES, diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index 8e214218f23..72c25592609 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -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"), diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs new file mode 100644 index 00000000000..8f1d1490e1f --- /dev/null +++ b/clippy_lints/src/semicolon_block.rs @@ -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())], + ); + }, + ); +} diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index f4705481d4e..bc18cad6d38 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -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 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { 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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { && 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, + ); + } } } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index b6dc8cd7ab1..3e7d0028c0f 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -205,10 +205,49 @@ pub(crate) fn get_configuration_metadata() -> Vec { } 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 = <_>::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 = <_>::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 @@ pub(crate) fn get_configuration_metadata() -> Vec { /// /// 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. diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 680935f2329..9afe02c1e47 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -7,7 +7,7 @@ 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()); diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index fb9f4740ecc..ac6a566b9cd 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.67" +version = "0.1.68" edition = "2021" publish = false diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 652f8b4d3c5..43e2d1ec826 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -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 { diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index d13b34a66cc..77c5f115542 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -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, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 12a512f78a6..ba5bc9c3135 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -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 } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 6417f0f3c71..9ca50105ae5 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -20,7 +20,6 @@ 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"]; diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 8bf542ada04..e5d7da68281 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -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 { .. } => { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index a6bcb134d40..2773da70d78 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -16,8 +16,8 @@ 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 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` 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, + ) -> 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`, it will register a predicate of `T: Trait`, 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`, it will register a predicate of `::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`, it will register a predicate of `T: Trait`, 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`, it will register a predicate of `::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 `::Item` for `T` @@ -631,7 +647,9 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option 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 @@ fn helper<'tcx>( } } - Some(tcx.mk_alias_ty( - assoc_item.def_id, - substs, - )) + Some(tcx.mk_alias_ty(assoc_item.def_id, substs)) } helper( tcx, diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml index 082570f1fe5..c01e1062cb5 100644 --- a/declare_clippy_lint/Cargo.toml +++ b/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.67" +version = "0.1.68" edition = "2021" publish = false diff --git a/rust-toolchain b/rust-toolchain index 19fee38db46..8e21cef32ab 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -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"] diff --git a/rustc_tools_util/CHANGELOG.md b/rustc_tools_util/CHANGELOG.md new file mode 100644 index 00000000000..1b351da2e7b --- /dev/null +++ b/rustc_tools_util/CHANGELOG.md @@ -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` diff --git a/rustc_tools_util/Cargo.toml b/rustc_tools_util/Cargo.toml index 89c3d6aaa89..877049ae7d0 100644 --- a/rustc_tools_util/Cargo.toml +++ b/rustc_tools_util/Cargo.toml @@ -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" diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index e947f9c7e66..eefc661f963 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/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 diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 01d25c53126..4c1d8c3733d 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -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::().unwrap(); - let minor = env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap(); - let patch = env!("CARGO_PKG_VERSION_PATCH").parse::().unwrap(); - let crate_name = String::from(env!("CARGO_PKG_NAME")); + let major = std::env!("CARGO_PKG_VERSION_MAJOR").parse::().unwrap(); + let minor = std::env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap(); + let patch = std::env!("CARGO_PKG_VERSION_PATCH").parse::().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 { #[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 @@ fn test_struct_local() { #[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 @@ fn test_debug_local() { 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 }" ); } } diff --git a/src/driver.rs b/src/driver.rs index 9ec4df8e651..bcc096c570e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -19,7 +19,6 @@ 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; diff --git a/src/main.rs b/src/main.rs index d418d2daa31..7a78b32620d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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}; diff --git a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr index 2a240cc249b..3ca45404e44 100644 --- a/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr +++ b/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr @@ -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 diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs index e8a023ab176..36db9e54a22 100644 --- a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs +++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs @@ -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 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 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() {} diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr new file mode 100644 index 00000000000..ad89534aa1b --- /dev/null +++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr @@ -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 + diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml index e736256f29a..89cbea7ecfe 100644 --- a/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml +++ b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml @@ -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"] diff --git a/tests/ui-toml/suppress_lint_in_const/clippy.toml b/tests/ui-toml/suppress_lint_in_const/clippy.toml new file mode 100644 index 00000000000..1b9384d7e3e --- /dev/null +++ b/tests/ui-toml/suppress_lint_in_const/clippy.toml @@ -0,0 +1 @@ +suppress-restriction-lint-in-const = true diff --git a/tests/ui-toml/suppress_lint_in_const/test.rs b/tests/ui-toml/suppress_lint_in_const/test.rs new file mode 100644 index 00000000000..5a2df9f6c5d --- /dev/null +++ b/tests/ui-toml/suppress_lint_in_const/test.rs @@ -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 + } +} diff --git a/tests/ui-toml/suppress_lint_in_const/test.stderr b/tests/ui-toml/suppress_lint_in_const/test.stderr new file mode 100644 index 00000000000..bc178b7e131 --- /dev/null +++ b/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -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`. diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 01a5e962c94..a22c6a5a060 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -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 diff --git a/tests/ui/almost_complete_letter_range.stderr b/tests/ui/almost_complete_letter_range.stderr deleted file mode 100644 index 9abf6d6c5e7..00000000000 --- a/tests/ui/almost_complete_letter_range.stderr +++ /dev/null @@ -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 - diff --git a/tests/ui/almost_complete_letter_range.fixed b/tests/ui/almost_complete_range.fixed similarity index 56% rename from tests/ui/almost_complete_letter_range.fixed rename to tests/ui/almost_complete_range.fixed index adcbd4d5134..6046addf719 100644 --- a/tests/ui/almost_complete_letter_range.fixed +++ b/tests/ui/almost_complete_range.fixed @@ -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, }; } diff --git a/tests/ui/almost_complete_letter_range.rs b/tests/ui/almost_complete_range.rs similarity index 57% rename from tests/ui/almost_complete_letter_range.rs rename to tests/ui/almost_complete_range.rs index 9979316eca4..ae7e07ab872 100644 --- a/tests/ui/almost_complete_letter_range.rs +++ b/tests/ui/almost_complete_range.rs @@ -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, }; } diff --git a/tests/ui/almost_complete_range.stderr b/tests/ui/almost_complete_range.stderr new file mode 100644 index 00000000000..a7a53287850 --- /dev/null +++ b/tests/ui/almost_complete_range.stderr @@ -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 + diff --git a/tests/ui/arithmetic_side_effects.stderr b/tests/ui/arithmetic_side_effects.stderr index 0259a0824e7..9fe4b7cf28d 100644 --- a/tests/ui/arithmetic_side_effects.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -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 diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index ef3ca9aea38..1e5f20e8c39 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -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'; }; } diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed index 72a708b4073..925cbf25368 100644 --- a/tests/ui/cast_lossless_integer.fixed +++ b/tests/ui/cast_lossless_integer.fixed @@ -45,3 +45,9 @@ mod cast_lossless_in_impl { } } } + +#[derive(PartialEq, Debug)] +#[repr(i64)] +enum Test { + A = u32::MAX as i64 + 1, +} diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index 34bb47181e6..c82bd9108d2 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -45,3 +45,9 @@ pub const fn convert(x: u32) -> u64 { } } } + +#[derive(PartialEq, Debug)] +#[repr(i64)] +enum Test { + A = u32::MAX as i64 + 1, +} diff --git a/tests/ui/collapsible_str_replace.fixed b/tests/ui/collapsible_str_replace.fixed index 49fc9a9629e..9792ae9ed6b 100644 --- a/tests/ui/collapsible_str_replace.fixed +++ b/tests/ui/collapsible_str_replace.fixed @@ -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"); +} diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs index e3e25c4146f..baee185b79e 100644 --- a/tests/ui/collapsible_str_replace.rs +++ b/tests/ui/collapsible_str_replace.rs @@ -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"); +} diff --git a/tests/ui/collapsible_str_replace.stderr b/tests/ui/collapsible_str_replace.stderr index 8e3daf3b898..223358cf53f 100644 --- a/tests/ui/collapsible_str_replace.stderr +++ b/tests/ui/collapsible_str_replace.stderr @@ -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 diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index 6eddc01e2c4..46565a97f00 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -189,3 +189,33 @@ pub fn test() { } } } + +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; + } + } + } +} diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed index 125c9a69cd3..72d635c2ccd 100644 --- a/tests/ui/from_over_into.fixed +++ b/tests/ui/from_over_into.fixed @@ -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 for IntoOpaque { + fn into(self) -> Opaque {} +} + fn main() {} diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs index 5aa127bfabe..965f4d5d785 100644 --- a/tests/ui/from_over_into.rs +++ b/tests/ui/from_over_into.rs @@ -1,5 +1,6 @@ // run-rustfix +#![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] #![allow(unused)] @@ -81,4 +82,10 @@ fn into(self) -> FromOverInto { } } +type Opaque = impl Sized; +struct IntoOpaque; +impl Into for IntoOpaque { + fn into(self) -> Opaque {} +} + fn main() {} diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr index a1764a5ea12..3c4d011d6fb 100644 --- a/tests/ui/from_over_into.stderr +++ b/tests/ui/from_over_into.stderr @@ -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 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 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 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 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 Into> for Vec { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index e7b9a78c5db..cac69ef42c4 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -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 { diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index 9a435cdbb75..33201aad4f6 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -112,6 +112,10 @@ fn f(_: i32) { 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 { diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr index 1a104a20b84..3ba557d18b2 100644 --- a/tests/ui/identity_op.stderr +++ b/tests/ui/identity_op.stderr @@ -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 diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed index 33770fc2a2c..51b1afbe5ac 100644 --- a/tests/ui/implicit_clone.fixed +++ b/tests/ui/implicit_clone.fixed @@ -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(); } diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs index fc896525bd2..8a9027433d9 100644 --- a/tests/ui/implicit_clone.rs +++ b/tests/ui/implicit_clone.rs @@ -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(); } diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs index 4476e0eb922..26abc9edb5e 100644 --- a/tests/ui/indexing_slicing_index.rs +++ b/tests/ui/indexing_slicing_index.rs @@ -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 diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index d8b6e3f1262..8fd77913a3f 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -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`. diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index 1f3b8ac99b1..c1c0b5ae40f 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -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()`. diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index dc21de0001b..cc2eb05b6bf 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -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 @@ fn is_empty(&self) -> bool { } } +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()`. diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index 6c71f1beeac..b6f13780253 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -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 diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index c9a819ba535..638320dd6ee 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -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) { diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index 2f62de51cad..8c7e919bf62 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -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) { diff --git a/tests/ui/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr index 237638ee134..3555ac29243 100644 --- a/tests/ui/manual_assert.edition2021.stderr +++ b/tests/ui/manual_assert.edition2021.stderr @@ -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 diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 6a4cc2468d4..f037c5b8405 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -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) { diff --git a/tests/ui/manual_is_ascii_check.fixed b/tests/ui/manual_is_ascii_check.fixed index 231ba83b142..5b2b44c2fdb 100644 --- a/tests/ui/manual_is_ascii_check.fixed +++ b/tests/ui/manual_is_ascii_check.fixed @@ -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"] diff --git a/tests/ui/manual_is_ascii_check.rs b/tests/ui/manual_is_ascii_check.rs index 39ee6151c56..c9433f33a1b 100644 --- a/tests/ui/manual_is_ascii_check.rs +++ b/tests/ui/manual_is_ascii_check.rs @@ -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"] diff --git a/tests/ui/manual_is_ascii_check.stderr b/tests/ui/manual_is_ascii_check.stderr index 397cbe05c82..ee60188506d 100644 --- a/tests/ui/manual_is_ascii_check.stderr +++ b/tests/ui/manual_is_ascii_check.stderr @@ -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 diff --git a/tests/ui/manual_let_else_match.rs b/tests/ui/manual_let_else_match.rs index 93c86ca24fe..28caed9d79d 100644 --- a/tests/ui/manual_let_else_match.rs +++ b/tests/ui/manual_let_else_match.rs @@ -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() { diff --git a/tests/ui/manual_let_else_match.stderr b/tests/ui/manual_let_else_match.stderr index 38be5ac5454..cd5e9a9ac39 100644 --- a/tests/ui/manual_let_else_match.stderr +++ b/tests/ui/manual_let_else_match.stderr @@ -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 diff --git a/tests/ui/needless_parens_on_range_literals.fixed b/tests/ui/needless_parens_on_range_literals.fixed index 1bd75c806bc..f11330a8916 100644 --- a/tests/ui/needless_parens_on_range_literals.fixed +++ b/tests/ui/needless_parens_on_range_literals.fixed @@ -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'; diff --git a/tests/ui/needless_parens_on_range_literals.rs b/tests/ui/needless_parens_on_range_literals.rs index 7abb8a1adc1..671c0009e23 100644 --- a/tests/ui/needless_parens_on_range_literals.rs +++ b/tests/ui/needless_parens_on_range_literals.rs @@ -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'); diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs index f69982d63a8..beec42f08bb 100644 --- a/tests/ui/new_ret_no_self.rs +++ b/tests/ui/new_ret_no_self.rs @@ -1,3 +1,4 @@ +#![feature(type_alias_impl_trait)] #![warn(clippy::new_ret_no_self)] #![allow(dead_code)] @@ -400,3 +401,25 @@ fn new<'b: 'a>(s: &'b str) -> impl Into> { } } } + +mod issue10041 { + struct Bomb; + + impl Bomb { + // Hidden default generic paramter. + pub fn new() -> impl PartialOrd { + 0i32 + } + } + + // TAIT with self-referencing bounds + type X = impl std::ops::Add; + + struct Bomb2; + + impl Bomb2 { + pub fn new() -> X { + 0i32 + } + } +} diff --git a/tests/ui/new_ret_no_self.stderr b/tests/ui/new_ret_no_self.stderr index bc13be47927..2eaebfb5cac 100644 --- a/tests/ui/new_ret_no_self.stderr +++ b/tests/ui/new_ret_no_self.stderr @@ -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 { 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 { 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 { 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 diff --git a/tests/ui/redundant_static_lifetimes.fixed b/tests/ui/redundant_static_lifetimes.fixed index 4c5846fe837..bca777a890c 100644 --- a/tests/ui/redundant_static_lifetimes.fixed +++ b/tests/ui/redundant_static_lifetimes.fixed @@ -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 { diff --git a/tests/ui/redundant_static_lifetimes.rs b/tests/ui/redundant_static_lifetimes.rs index 64a66be1a83..afe7644816d 100644 --- a/tests/ui/redundant_static_lifetimes.rs +++ b/tests/ui/redundant_static_lifetimes.rs @@ -39,8 +39,14 @@ static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. +static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0]; + fn main() { let false_positive: &'static str = "test"; + + unsafe { + STATIC_MUT_SLICE[0] = 0; + } } trait Bar { diff --git a/tests/ui/redundant_static_lifetimes.stderr b/tests/ui/redundant_static_lifetimes.stderr index 0938ebf783f..b2cbd2d9d01 100644 --- a/tests/ui/redundant_static_lifetimes.stderr +++ b/tests/ui/redundant_static_lifetimes.stderr @@ -97,10 +97,16 @@ LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removin | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: statics have by default a `'static` lifetime - --> $DIR/redundant_static_lifetimes.rs:65:16 + --> $DIR/redundant_static_lifetimes.rs:42:31 + | +LL | static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0]; + | -^^^^^^^---------- help: consider removing `'static`: `&mut [u32]` + +error: statics have by default a `'static` lifetime + --> $DIR/redundant_static_lifetimes.rs:71:16 | LL | static V: &'static u8 = &17; | -^^^^^^^--- help: consider removing `'static`: `&u8` -error: aborting due to 17 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 689928f0479..2f76b575296 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -4,6 +4,7 @@ // run-rustfix +#![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] @@ -37,6 +38,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::almost_complete_range)] #![warn(clippy::disallowed_names)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_if_conditions)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index b74aa650ffd..699c0ff464e 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -4,6 +4,7 @@ // run-rustfix +#![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] @@ -37,6 +38,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::almost_complete_letter_range)] #![warn(clippy::blacklisted_name)] #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 622a32c5908..9af58dc75a6 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,244 +1,250 @@ -error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:40:9 +error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` + --> $DIR/rename.rs:41:9 | -LL | #![warn(clippy::blacklisted_name)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` +LL | #![warn(clippy::almost_complete_letter_range)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` | = note: `-D renamed-and-removed-lints` implied by `-D warnings` +error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` + --> $DIR/rename.rs:42:9 + | +LL | #![warn(clippy::blacklisted_name)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` + error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 40 previous errors +error: aborting due to 41 previous errors diff --git a/tests/ui/seek_to_start_instead_of_rewind.fixed b/tests/ui/seek_to_start_instead_of_rewind.fixed index 9d0d1124c46..713cff604a1 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -70,6 +70,12 @@ fn seek_to_end(t: &mut T) { t.seek(SeekFrom::End(0)); } +// This should NOT trigger clippy warning because +// expr is used here +fn seek_to_start_in_let(t: &mut T) { + let a = t.seek(SeekFrom::Start(0)).unwrap(); +} + fn main() { let mut f = OpenOptions::new() .write(true) diff --git a/tests/ui/seek_to_start_instead_of_rewind.rs b/tests/ui/seek_to_start_instead_of_rewind.rs index c5bc57cc3a7..467003a1a66 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/tests/ui/seek_to_start_instead_of_rewind.rs @@ -70,6 +70,12 @@ fn seek_to_end(t: &mut T) { t.seek(SeekFrom::End(0)); } +// This should NOT trigger clippy warning because +// expr is used here +fn seek_to_start_in_let(t: &mut T) { + let a = t.seek(SeekFrom::Start(0)).unwrap(); +} + fn main() { let mut f = OpenOptions::new() .write(true) diff --git a/tests/ui/seek_to_start_instead_of_rewind.stderr b/tests/ui/seek_to_start_instead_of_rewind.stderr index 6cce025359f..342ec00fe72 100644 --- a/tests/ui/seek_to_start_instead_of_rewind.stderr +++ b/tests/ui/seek_to_start_instead_of_rewind.stderr @@ -13,7 +13,7 @@ LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` error: used `seek` to go to the start of the stream - --> $DIR/seek_to_start_instead_of_rewind.rs:128:7 + --> $DIR/seek_to_start_instead_of_rewind.rs:134:7 | LL | f.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` diff --git a/tests/ui/semicolon_inside_block.fixed b/tests/ui/semicolon_inside_block.fixed new file mode 100644 index 00000000000..42e97e1ca35 --- /dev/null +++ b/tests/ui/semicolon_inside_block.fixed @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()); } + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui/semicolon_inside_block.rs b/tests/ui/semicolon_inside_block.rs new file mode 100644 index 00000000000..f40848f702e --- /dev/null +++ b/tests/ui/semicolon_inside_block.rs @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui/semicolon_inside_block.stderr b/tests/ui/semicolon_inside_block.stderr new file mode 100644 index 00000000000..48d3690e2bd --- /dev/null +++ b/tests/ui/semicolon_inside_block.stderr @@ -0,0 +1,54 @@ +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/semicolon_inside_block.rs:39:5 + | +LL | { unit_fn_block() }; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` +help: put the `;` here + | +LL - { unit_fn_block() }; +LL + { unit_fn_block(); } + | + +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/semicolon_inside_block.rs:40:5 + | +LL | unsafe { unit_fn_block() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: put the `;` here + | +LL - unsafe { unit_fn_block() }; +LL + unsafe { unit_fn_block(); } + | + +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/semicolon_inside_block.rs:48:5 + | +LL | / { +LL | | unit_fn_block(); +LL | | unit_fn_block() +LL | | }; + | |______^ + | +help: put the `;` here + | +LL ~ unit_fn_block(); +LL ~ } + | + +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/semicolon_inside_block.rs:61:5 + | +LL | { m!(()) }; + | ^^^^^^^^^^^ + | +help: put the `;` here + | +LL - { m!(()) }; +LL + { m!(()); } + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/semicolon_outside_block.fixed b/tests/ui/semicolon_outside_block.fixed new file mode 100644 index 00000000000..091eaa7518e --- /dev/null +++ b/tests/ui/semicolon_outside_block.fixed @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()) }; + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui/semicolon_outside_block.rs b/tests/ui/semicolon_outside_block.rs new file mode 100644 index 00000000000..7ce46431fac --- /dev/null +++ b/tests/ui/semicolon_outside_block.rs @@ -0,0 +1,85 @@ +// run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/tests/ui/semicolon_outside_block.stderr b/tests/ui/semicolon_outside_block.stderr new file mode 100644 index 00000000000..dcc102e6099 --- /dev/null +++ b/tests/ui/semicolon_outside_block.stderr @@ -0,0 +1,54 @@ +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:42:5 + | +LL | { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` +help: put the `;` here + | +LL - { unit_fn_block(); } +LL + { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:43:5 + | +LL | unsafe { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: put the `;` here + | +LL - unsafe { unit_fn_block(); } +LL + unsafe { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:52:5 + | +LL | / { +LL | | unit_fn_block(); +LL | | unit_fn_block(); +LL | | } + | |_____^ + | +help: put the `;` here + | +LL ~ unit_fn_block() +LL ~ }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:62:5 + | +LL | { m!(()); } + | ^^^^^^^^^^^ + | +help: put the `;` here + | +LL - { m!(()); } +LL + { m!(()) }; + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index df2256e4f97..506187fc125 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -25,6 +25,12 @@ fn str_lit_as_bytes() { let includestr = include_bytes!("string_lit_as_bytes.rs"); let _ = b"string with newline\t\n"; + + let _ = match "x".as_bytes() { + b"xx" => 0, + [b'x', ..] => 1, + _ => 2, + }; } fn main() {} diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index c6bf8f732ed..2c339f1ddb8 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -25,6 +25,12 @@ fn str_lit_as_bytes() { let includestr = include_str!("string_lit_as_bytes.rs").as_bytes(); let _ = "string with newline\t\n".as_bytes(); + + let _ = match "x".as_bytes() { + b"xx" => 0, + [b'x', ..] => 1, + _ => 2, + }; } fn main() {} diff --git a/tests/ui/uninlined_format_args_panic.edition2018.fixed b/tests/ui/uninlined_format_args_panic.edition2018.fixed index 96cc0877960..52b5343c351 100644 --- a/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -26,4 +26,7 @@ fn main() { panic!("p4 {var}"); } } + + assert!(var == 1, "p5 {}", var); + debug_assert!(var == 1, "p6 {}", var); } diff --git a/tests/ui/uninlined_format_args_panic.edition2021.fixed b/tests/ui/uninlined_format_args_panic.edition2021.fixed index faf8ca4d3a7..ee72065e28a 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -26,4 +26,7 @@ fn main() { panic!("p4 {var}"); } } + + assert!(var == 1, "p5 {var}"); + debug_assert!(var == 1, "p6 {var}"); } diff --git a/tests/ui/uninlined_format_args_panic.edition2021.stderr b/tests/ui/uninlined_format_args_panic.edition2021.stderr index 0f09c45f413..fc7b125080e 100644 --- a/tests/ui/uninlined_format_args_panic.edition2021.stderr +++ b/tests/ui/uninlined_format_args_panic.edition2021.stderr @@ -47,5 +47,29 @@ LL - panic!("p3 {var}", var = var); LL + panic!("p3 {var}"); | -error: aborting due to 4 previous errors +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args_panic.rs:30:5 + | +LL | assert!(var == 1, "p5 {}", var); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - assert!(var == 1, "p5 {}", var); +LL + assert!(var == 1, "p5 {var}"); + | + +error: variables can be used directly in the `format!` string + --> $DIR/uninlined_format_args_panic.rs:31:5 + | +LL | debug_assert!(var == 1, "p6 {}", var); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: change this to + | +LL - debug_assert!(var == 1, "p6 {}", var); +LL + debug_assert!(var == 1, "p6 {var}"); + | + +error: aborting due to 6 previous errors diff --git a/tests/ui/uninlined_format_args_panic.rs b/tests/ui/uninlined_format_args_panic.rs index 6421c5bbed2..b4a0a0f496e 100644 --- a/tests/ui/uninlined_format_args_panic.rs +++ b/tests/ui/uninlined_format_args_panic.rs @@ -26,4 +26,7 @@ fn main() { panic!("p4 {var}"); } } + + assert!(var == 1, "p5 {}", var); + debug_assert!(var == 1, "p6 {}", var); } diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index ddeda795f81..345f6d604c4 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -454,3 +454,23 @@ mod issue_9771b { Key(v.to_vec()) } } + +// This is a watered down version of the code in: https://github.com/oxigraph/rio +// The ICE is triggered by the call to `to_owned` on this line: +// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116 +mod issue_10021 { + #![allow(unused)] + + pub struct Iri(T); + + impl> Iri { + pub fn parse(iri: T) -> Result { + unimplemented!() + } + } + + pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> { + let base_iri = Iri::parse(url.to_owned())?; + Ok(()) + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 95d2576733c..7eb53df39e5 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -454,3 +454,23 @@ pub fn from(c: &[u8]) -> Key> { Key(v.to_vec()) } } + +// This is a watered down version of the code in: https://github.com/oxigraph/rio +// The ICE is triggered by the call to `to_owned` on this line: +// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116 +mod issue_10021 { + #![allow(unused)] + + pub struct Iri(T); + + impl> Iri { + pub fn parse(iri: T) -> Result { + unimplemented!() + } + } + + pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> { + let base_iri = Iri::parse(url.to_owned())?; + Ok(()) + } +} diff --git a/tests/ui/zero_ptr_no_std.fixed b/tests/ui/zero_ptr_no_std.fixed new file mode 100644 index 00000000000..8906c776977 --- /dev/null +++ b/tests/ui/zero_ptr_no_std.fixed @@ -0,0 +1,21 @@ +// run-rustfix + +#![feature(lang_items, start, libc)] +#![no_std] +#![deny(clippy::zero_ptr)] + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + let _ = core::ptr::null::(); + let _ = core::ptr::null_mut::(); + let _: *const u8 = core::ptr::null(); + 0 +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} diff --git a/tests/ui/zero_ptr_no_std.rs b/tests/ui/zero_ptr_no_std.rs new file mode 100644 index 00000000000..379c1b18d29 --- /dev/null +++ b/tests/ui/zero_ptr_no_std.rs @@ -0,0 +1,21 @@ +// run-rustfix + +#![feature(lang_items, start, libc)] +#![no_std] +#![deny(clippy::zero_ptr)] + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + let _ = 0 as *const usize; + let _ = 0 as *mut f64; + let _: *const u8 = 0 as *const _; + 0 +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} diff --git a/tests/ui/zero_ptr_no_std.stderr b/tests/ui/zero_ptr_no_std.stderr new file mode 100644 index 00000000000..d92bb4a6528 --- /dev/null +++ b/tests/ui/zero_ptr_no_std.stderr @@ -0,0 +1,26 @@ +error: `0 as *const _` detected + --> $DIR/zero_ptr_no_std.rs:9:13 + | +LL | let _ = 0 as *const usize; + | ^^^^^^^^^^^^^^^^^ help: try: `core::ptr::null::()` + | +note: the lint level is defined here + --> $DIR/zero_ptr_no_std.rs:5:9 + | +LL | #![deny(clippy::zero_ptr)] + | ^^^^^^^^^^^^^^^^ + +error: `0 as *mut _` detected + --> $DIR/zero_ptr_no_std.rs:10:13 + | +LL | let _ = 0 as *mut f64; + | ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::()` + +error: `0 as *const _` detected + --> $DIR/zero_ptr_no_std.rs:11:24 + | +LL | let _: *const u8 = 0 as *const _; + | ^^^^^^^^^^^^^ help: try: `core::ptr::null()` + +error: aborting due to 3 previous errors + diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs index 7a85386a3df..c721e9969c9 100644 --- a/tests/versioncheck.rs +++ b/tests/versioncheck.rs @@ -2,7 +2,6 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::single_match_else)] -use rustc_tools_util::VersionInfo; use std::fs; #[test] diff --git a/triagebot.toml b/triagebot.toml index acb476ee696..6f50ef932e1 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,7 +1,7 @@ [relabel] allow-unauthenticated = [ "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*", - "good-first-issue" + "good-first-issue", "beta-nominated" ] # Allows shortcuts like `@rustbot ready`