From 86811e9b1ba28abd8ba00ece1670c7cfd1284817 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 7 Oct 2021 00:14:06 +0200 Subject: [PATCH 001/100] make test module detection more strict --- clippy_utils/src/lib.rs | 42 ++++++++++++-------------------- tests/ui/wildcard_imports.fixed | 8 ++++++ tests/ui/wildcard_imports.rs | 8 ++++++ tests/ui/wildcard_imports.stderr | 8 +++++- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 00cf8a4d077..673830eea8a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -252,11 +252,7 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem /// Returns `true` if this `span` was expanded by any macro. #[must_use] pub fn in_macro(span: Span) -> bool { - if span.from_expansion() { - !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) - } else { - false - } + span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..)) } pub fn is_unit_expr(expr: &Expr<'_>) -> bool { @@ -1286,10 +1282,9 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool } let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id)); if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { - value == v - } else { - false + return value == v; } + false } /// Checks whether the given expression is a constant literal of the given value. @@ -1316,7 +1311,7 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// Returns the pre-expansion span if is this comes from an expansion of the /// macro `name`. -/// See also `is_direct_expn_of`. +/// See also [`is_direct_expn_of`]. #[must_use] pub fn is_expn_of(mut span: Span, name: &str) -> Option { loop { @@ -1339,13 +1334,13 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option { /// Returns the pre-expansion span if the span directly comes from an expansion /// of the macro `name`. -/// The difference with `is_expn_of` is that in -/// ```rust,ignore +/// The difference with [`is_expn_of`] is that in +/// ```rust +/// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } } /// foo!(bar!(42)); /// ``` /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only -/// `bar!` by -/// `is_direct_expn_of`. +/// from `bar!` by `is_direct_expn_of`. #[must_use] pub fn is_direct_expn_of(span: Span, name: &str) -> Option { if span.from_expansion() { @@ -1468,11 +1463,9 @@ pub fn is_self(slf: &Param<'_>) -> bool { } pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { - if_chain! { - if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind; - if let Res::SelfTy(..) = path.res; - then { - return true + if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind { + if let Res::SelfTy(..) = path.res { + return true; } } false @@ -2064,15 +2057,12 @@ macro_rules! unwrap_cargo_metadata { } pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { - if_chain! { - if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind; - if let Res::Def(_, def_id) = path.res; - then { - cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr) - } else { - false + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + if let Res::Def(_, def_id) = path.res { + return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr); } } + false } /// Checks whether item either has `test` attribute applied, or @@ -2084,7 +2074,7 @@ pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { } } - matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test") + matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") } macro_rules! op_utils { diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index ee9c9045fff..98bc1e80731 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -230,4 +230,12 @@ mod super_imports { let _ = foofoo(); } } + + mod attestation_should_be_replaced { + use super::foofoo; + + fn with_explicit() { + let _ = foofoo(); + } + } } diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index efaa8f9ef66..4ef61f9245b 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -231,4 +231,12 @@ fn with_super_explicit() { let _ = foofoo(); } } + + mod attestation_should_be_replaced { + use super::*; + + fn with_explicit() { + let _ = foofoo(); + } + } } diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 66267dd27b8..d7af0c046e8 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -122,5 +122,11 @@ error: usage of wildcard import LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` -error: aborting due to 20 previous errors +error: usage of wildcard import + --> $DIR/wildcard_imports.rs:236:13 + | +LL | use super::*; + | ^^^^^^^^ help: try: `super::foofoo` + +error: aborting due to 21 previous errors From 64f8b9d0eac0b3c25c74462bfbe5086feb4264e8 Mon Sep 17 00:00:00 2001 From: dswij Date: Thu, 7 Oct 2021 16:39:13 +0800 Subject: [PATCH 002/100] Make `shadow_reuse` suggestion less verbose --- clippy_lints/src/shadow.rs | 6 +--- tests/ui/shadow.rs | 5 ++++ tests/ui/shadow.stderr | 60 +++++++++++++++++++++++--------------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 2ca7c18800e..64841f33cc3 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -162,11 +162,7 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) (SHADOW_SAME, msg) }, Some(expr) if is_local_used(cx, expr, shadowed) => { - let msg = format!( - "`{}` is shadowed by `{}` which reuses the original value", - snippet(cx, pat.span, "_"), - snippet(cx, expr.span, "..") - ); + let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_")); (SHADOW_REUSE, msg) }, _ => { diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 02e838456d0..55caef59f7f 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -17,6 +17,11 @@ fn shadow_reuse() -> Option<()> { let x = foo(x); let x = || x; let x = Some(1).map(|_| x)?; + let y = 1; + let y = match y { + 1 => 2, + _ => 3, + }; None } diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 8b60e072c93..feed6e1ba8b 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -47,7 +47,7 @@ note: previous binding is here LL | let x = &mut x; | ^ -error: `x` is shadowed by `x.0` which reuses the original value +error: `x` is shadowed --> $DIR/shadow.rs:13:9 | LL | let x = x.0; @@ -60,7 +60,7 @@ note: previous binding is here LL | let x = ([[0]], ()); | ^ -error: `x` is shadowed by `x[0]` which reuses the original value +error: `x` is shadowed --> $DIR/shadow.rs:14:9 | LL | let x = x[0]; @@ -72,7 +72,7 @@ note: previous binding is here LL | let x = x.0; | ^ -error: `x` is shadowed by `x` which reuses the original value +error: `x` is shadowed --> $DIR/shadow.rs:15:10 | LL | let [x] = x; @@ -84,7 +84,7 @@ note: previous binding is here LL | let x = x[0]; | ^ -error: `x` is shadowed by `Some(x)` which reuses the original value +error: `x` is shadowed --> $DIR/shadow.rs:16:9 | LL | let x = Some(x); @@ -96,7 +96,7 @@ note: previous binding is here LL | let [x] = x; | ^ -error: `x` is shadowed by `foo(x)` which reuses the original value +error: `x` is shadowed --> $DIR/shadow.rs:17:9 | LL | let x = foo(x); @@ -108,7 +108,7 @@ note: previous binding is here LL | let x = Some(x); | ^ -error: `x` is shadowed by `|| x` which reuses the original value +error: `x` is shadowed --> $DIR/shadow.rs:18:9 | LL | let x = || x; @@ -120,7 +120,7 @@ note: previous binding is here LL | let x = foo(x); | ^ -error: `x` is shadowed by `Some(1).map(|_| x)?` which reuses the original value +error: `x` is shadowed --> $DIR/shadow.rs:19:9 | LL | let x = Some(1).map(|_| x)?; @@ -132,102 +132,114 @@ note: previous binding is here LL | let x = || x; | ^ +error: `y` is shadowed + --> $DIR/shadow.rs:21:9 + | +LL | let y = match y { + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:20:9 + | +LL | let y = 1; + | ^ + error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:25:9 + --> $DIR/shadow.rs:30:9 | LL | let x = 2; | ^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` note: previous binding is here - --> $DIR/shadow.rs:24:9 + --> $DIR/shadow.rs:29:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:30:13 + --> $DIR/shadow.rs:35:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:29:10 + --> $DIR/shadow.rs:34:10 | LL | fn f(x: u32) { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:35:14 + --> $DIR/shadow.rs:40:14 | LL | Some(x) => { | ^ | note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:37:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:36:17 + --> $DIR/shadow.rs:41:17 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:35:14 + --> $DIR/shadow.rs:40:14 | LL | Some(x) => { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:40:17 + --> $DIR/shadow.rs:45:17 | LL | if let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:37:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:41:20 + --> $DIR/shadow.rs:46:20 | LL | while let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:37:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:42:15 + --> $DIR/shadow.rs:47:15 | LL | let _ = |[x]: [u32; 1]| { | ^ | note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:37:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:43:13 + --> $DIR/shadow.rs:48:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:42:15 + --> $DIR/shadow.rs:47:15 | LL | let _ = |[x]: [u32; 1]| { | ^ -error: aborting due to 19 previous errors +error: aborting due to 20 previous errors From 5cf4984872e1ac047b4e2df52fe0f6faa82716c3 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 7 Oct 2021 11:21:30 +0200 Subject: [PATCH 003/100] Merge commit 'b7f3f7f6082679da2da9a0b3faf1b5adef3afd3b' into clippyup --- CHANGELOG.md | 2 + clippy_dev/src/lib.rs | 523 +----- clippy_dev/src/update_lints.rs | 675 +++++++- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/casts/cast_precision_loss.rs | 2 +- clippy_lints/src/derivable_impls.rs | 1 + clippy_lints/src/derive.rs | 4 +- clippy_lints/src/doc.rs | 26 +- clippy_lints/src/equatable_if_let.rs | 100 ++ clippy_lints/src/erasing_op.rs | 2 +- clippy_lints/src/escape.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/identity_op.rs | 14 +- clippy_lints/src/if_then_panic.rs | 14 +- clippy_lints/src/implicit_hasher.rs | 20 +- clippy_lints/src/integer_division.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 161 +- clippy_lints/src/len_zero.rs | 12 +- clippy_lints/src/lib.deprecated.rs | 70 + clippy_lints/src/lib.register_all.rs | 304 ++++ clippy_lints/src/lib.register_cargo.rs | 11 + clippy_lints/src/lib.register_complexity.rs | 94 ++ clippy_lints/src/lib.register_correctness.rs | 73 + clippy_lints/src/lib.register_internal.rs | 18 + clippy_lints/src/lib.register_lints.rs | 510 ++++++ clippy_lints/src/lib.register_nursery.rs | 30 + clippy_lints/src/lib.register_pedantic.rs | 100 ++ clippy_lints/src/lib.register_perf.rs | 27 + clippy_lints/src/lib.register_restriction.rs | 65 + clippy_lints/src/lib.register_style.rs | 114 ++ clippy_lints/src/lib.register_suspicious.rs | 20 + clippy_lints/src/lib.rs | 1411 +---------------- clippy_lints/src/loops/mut_range_bound.rs | 2 +- clippy_lints/src/loops/needless_range_loop.rs | 2 +- clippy_lints/src/loops/never_loop.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 4 +- clippy_lints/src/map_unit_fn.rs | 15 +- clippy_lints/src/matches.rs | 3 +- clippy_lints/src/methods/mod.rs | 5 +- clippy_lints/src/methods/or_fun_call.rs | 14 +- clippy_lints/src/methods/suspicious_map.rs | 2 +- .../src/methods/unnecessary_filter_map.rs | 3 +- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/needless_bool.rs | 2 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/new_without_default.rs | 2 +- .../src/non_send_fields_in_send_ty.rs | 238 +++ .../src/overflow_check_conditional.rs | 31 +- clippy_lints/src/redundant_pub_crate.rs | 36 +- clippy_lints/src/repeat_once.rs | 2 +- clippy_lints/src/shadow.rs | 441 ++---- clippy_lints/src/transmuting_null.rs | 4 +- clippy_lints/src/types/option_option.rs | 4 +- clippy_lints/src/utils/conf.rs | 4 + clippy_lints/src/utils/internal_lints.rs | 12 +- clippy_lints/src/zero_div_zero.rs | 2 +- clippy_utils/src/lib.rs | 15 +- clippy_utils/src/numeric_literal.rs | 15 +- clippy_utils/src/paths.rs | 6 + clippy_utils/src/sugg.rs | 2 +- clippy_utils/src/ty.rs | 10 +- clippy_utils/src/usage.rs | 2 +- rust-toolchain | 2 +- tests/compile-test.rs | 4 +- .../clippy.toml | 1 + .../strict_non_send_fields_in_send_ty/test.rs | 43 + .../test.stderr | 91 ++ .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/approx_const.rs | 2 +- .../branches_sharing_code/shared_at_bottom.rs | 2 +- tests/ui/collapsible_else_if.fixed | 2 +- tests/ui/collapsible_else_if.rs | 2 +- tests/ui/collapsible_if.fixed | 2 +- tests/ui/collapsible_if.rs | 2 +- tests/ui/collapsible_match.rs | 7 +- tests/ui/collapsible_match.stderr | 40 +- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/def_id_nocore.rs | 1 + tests/ui/def_id_nocore.stderr | 2 +- tests/ui/derivable_impls.rs | 33 + tests/ui/derivable_impls.stderr | 14 +- tests/ui/doc/doc.rs | 5 + tests/ui/doc_unsafe.rs | 21 +- tests/ui/doc_unsafe.stderr | 14 +- tests/ui/equatable_if_let.fixed | 69 + tests/ui/equatable_if_let.rs | 69 + tests/ui/equatable_if_let.stderr | 64 + tests/ui/excessive_precision.fixed | 6 + tests/ui/excessive_precision.rs | 6 + tests/ui/excessive_precision.stderr | 14 +- tests/ui/for_loop_fixable.fixed | 7 +- tests/ui/for_loop_fixable.rs | 7 +- tests/ui/for_loop_fixable.stderr | 30 +- tests/ui/for_loop_unfixable.rs | 9 +- tests/ui/for_loop_unfixable.stderr | 2 +- tests/ui/if_same_then_else2.rs | 1 + tests/ui/if_same_then_else2.stderr | 24 +- tests/ui/if_then_panic.fixed | 6 + tests/ui/if_then_panic.rs | 16 + tests/ui/if_then_panic.stderr | 42 +- tests/ui/implicit_hasher.rs | 4 + tests/ui/implicit_hasher.stderr | 35 +- tests/ui/integer_arithmetic.rs | 9 +- tests/ui/integer_arithmetic.stderr | 54 +- tests/ui/large_enum_variant.rs | 18 + tests/ui/large_enum_variant.stderr | 63 +- tests/ui/map_clone.fixed | 14 +- tests/ui/map_clone.rs | 14 +- tests/ui/match_expr_like_matches_macro.fixed | 2 +- tests/ui/match_expr_like_matches_macro.rs | 2 +- tests/ui/match_overlapping_arm.rs | 2 +- tests/ui/match_ref_pats.rs | 1 + tests/ui/match_ref_pats.stderr | 16 +- tests/ui/modulo_arithmetic_float.rs | 9 +- tests/ui/modulo_arithmetic_float.stderr | 20 +- tests/ui/modulo_arithmetic_integral.rs | 9 +- tests/ui/modulo_arithmetic_integral.stderr | 34 +- tests/ui/modulo_arithmetic_integral_const.rs | 9 +- .../modulo_arithmetic_integral_const.stderr | 34 +- tests/ui/needless_bool/fixable.fixed | 1 + tests/ui/needless_bool/fixable.rs | 1 + tests/ui/needless_bool/fixable.stderr | 24 +- tests/ui/needless_return.fixed | 7 +- tests/ui/needless_return.rs | 7 +- tests/ui/needless_return.stderr | 64 +- tests/ui/non_send_fields_in_send_ty.rs | 127 ++ tests/ui/non_send_fields_in_send_ty.stderr | 171 ++ tests/ui/option_if_let_else.fixed | 2 +- tests/ui/option_if_let_else.rs | 2 +- ...edundant_pattern_matching_drop_order.fixed | 2 +- .../redundant_pattern_matching_drop_order.rs | 2 +- .../redundant_pattern_matching_option.fixed | 1 + tests/ui/redundant_pattern_matching_option.rs | 1 + .../redundant_pattern_matching_option.stderr | 38 +- .../ui/redundant_pattern_matching_poll.fixed | 1 + tests/ui/redundant_pattern_matching_poll.rs | 1 + .../ui/redundant_pattern_matching_poll.stderr | 36 +- tests/ui/shadow.rs | 125 +- tests/ui/shadow.stderr | 265 +++- tests/ui/suspicious_map.stderr | 4 +- tests/ui/while_let_on_iterator.fixed | 8 +- tests/ui/while_let_on_iterator.rs | 8 +- tests/ui/while_let_on_iterator.stderr | 42 +- util/etc/pre-commit.sh | 1 + 147 files changed, 4288 insertions(+), 2969 deletions(-) create mode 100644 clippy_lints/src/equatable_if_let.rs create mode 100644 clippy_lints/src/lib.deprecated.rs create mode 100644 clippy_lints/src/lib.register_all.rs create mode 100644 clippy_lints/src/lib.register_cargo.rs create mode 100644 clippy_lints/src/lib.register_complexity.rs create mode 100644 clippy_lints/src/lib.register_correctness.rs create mode 100644 clippy_lints/src/lib.register_internal.rs create mode 100644 clippy_lints/src/lib.register_lints.rs create mode 100644 clippy_lints/src/lib.register_nursery.rs create mode 100644 clippy_lints/src/lib.register_pedantic.rs create mode 100644 clippy_lints/src/lib.register_perf.rs create mode 100644 clippy_lints/src/lib.register_restriction.rs create mode 100644 clippy_lints/src/lib.register_style.rs create mode 100644 clippy_lints/src/lib.register_suspicious.rs create mode 100644 clippy_lints/src/non_send_fields_in_send_ty.rs create mode 100644 tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml create mode 100644 tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs create mode 100644 tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr create mode 100644 tests/ui/equatable_if_let.fixed create mode 100644 tests/ui/equatable_if_let.rs create mode 100644 tests/ui/equatable_if_let.stderr create mode 100644 tests/ui/non_send_fields_in_send_ty.rs create mode 100644 tests/ui/non_send_fields_in_send_ty.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ea0f9ab9d..7fdb300c977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2695,6 +2695,7 @@ Released 2018-09-13 [`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use [`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names [`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op +[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision @@ -2898,6 +2899,7 @@ Released 2018-09-13 [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions +[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool [`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options [`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index e05db7af586..5538f62c8e7 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -3,14 +3,7 @@ // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] -use itertools::Itertools; -use regex::Regex; -use std::collections::HashMap; -use std::ffi::OsStr; -use std::fs; -use std::lazy::SyncLazy; -use std::path::{Path, PathBuf}; -use walkdir::WalkDir; +use std::path::PathBuf; pub mod bless; pub mod fmt; @@ -19,323 +12,6 @@ pub mod setup; pub mod update_lints; -static DEC_CLIPPY_LINT_RE: SyncLazy = SyncLazy::new(|| { - Regex::new( - r#"(?x) - declare_clippy_lint!\s*[\{(] - (?:\s+///.*)* - \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* - (?P[a-z_]+)\s*,\s* - "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] -"#, - ) - .unwrap() -}); - -static DEC_DEPRECATED_LINT_RE: SyncLazy = SyncLazy::new(|| { - Regex::new( - r#"(?x) - declare_deprecated_lint!\s*[{(]\s* - (?:\s+///.*)* - \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* - "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] -"#, - ) - .unwrap() -}); -static NL_ESCAPE_RE: SyncLazy = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap()); - -pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; - -/// Lint data parsed from the Clippy source code. -#[derive(Clone, PartialEq, Debug)] -pub struct Lint { - pub name: String, - pub group: String, - pub desc: String, - pub deprecation: Option, - pub module: String, -} - -impl Lint { - #[must_use] - pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self { - Self { - name: name.to_lowercase(), - group: group.to_string(), - desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(), - deprecation: deprecation.map(ToString::to_string), - module: module.to_string(), - } - } - - /// Returns all non-deprecated lints and non-internal lints - #[must_use] - pub fn usable_lints(lints: &[Self]) -> Vec { - lints - .iter() - .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal")) - .cloned() - .collect() - } - - /// Returns all internal lints (not `internal_warn` lints) - #[must_use] - pub fn internal_lints(lints: &[Self]) -> Vec { - lints.iter().filter(|l| l.group == "internal").cloned().collect() - } - - /// Returns all deprecated lints - #[must_use] - pub fn deprecated_lints(lints: &[Self]) -> Vec { - lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect() - } - - /// Returns the lints in a `HashMap`, grouped by the different lint groups - #[must_use] - pub fn by_lint_group(lints: impl Iterator) -> HashMap> { - lints.map(|lint| (lint.group.to_string(), lint)).into_group_map() - } -} - -/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`. -#[must_use] -pub fn gen_lint_group_list<'a>(lints: impl Iterator) -> Vec { - lints - .map(|l| format!(" LintId::of({}::{}),", l.module, l.name.to_uppercase())) - .sorted() - .collect::>() -} - -/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`. -#[must_use] -pub fn gen_modules_list<'a>(lints: impl Iterator) -> Vec { - lints - .map(|l| &l.module) - .unique() - .map(|module| format!("mod {};", module)) - .sorted() - .collect::>() -} - -/// Generates the list of lint links at the bottom of the README -#[must_use] -pub fn gen_changelog_lint_list<'a>(lints: impl Iterator) -> Vec { - lints - .sorted_by_key(|l| &l.name) - .map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name)) - .collect() -} - -/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`. -#[must_use] -pub fn gen_deprecated<'a>(lints: impl Iterator) -> Vec { - lints - .flat_map(|l| { - l.deprecation - .clone() - .map(|depr_text| { - vec![ - " store.register_removed(".to_string(), - format!(" \"clippy::{}\",", l.name), - format!(" \"{}\",", depr_text), - " );".to_string(), - ] - }) - .expect("only deprecated lints should be passed") - }) - .collect::>() -} - -#[must_use] -pub fn gen_register_lint_list<'a>( - internal_lints: impl Iterator, - usable_lints: impl Iterator, -) -> Vec { - let header = " store.register_lints(&[".to_string(); - let footer = " ]);".to_string(); - let internal_lints = internal_lints - .sorted_by_key(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) - .map(|l| { - format!( - " #[cfg(feature = \"internal-lints\")]\n {}::{},", - l.module, - l.name.to_uppercase() - ) - }); - let other_lints = usable_lints - .sorted_by_key(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) - .map(|l| format!(" {}::{},", l.module, l.name.to_uppercase())) - .sorted(); - let mut lint_list = vec![header]; - lint_list.extend(internal_lints); - lint_list.extend(other_lints); - lint_list.push(footer); - lint_list -} - -/// Gathers all files in `src/clippy_lints` and gathers all lints inside -pub fn gather_all() -> impl Iterator { - lint_files().flat_map(|f| gather_from_file(&f)) -} - -fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator { - let content = fs::read_to_string(dir_entry.path()).unwrap(); - let path = dir_entry.path(); - let filename = path.file_stem().unwrap(); - let path_buf = path.with_file_name(filename); - let mut rel_path = path_buf - .strip_prefix(clippy_project_root().join("clippy_lints/src")) - .expect("only files in `clippy_lints/src` should be looked at"); - // If the lints are stored in mod.rs, we get the module name from - // the containing directory: - if filename == "mod" { - rel_path = rel_path.parent().unwrap(); - } - - let module = rel_path - .components() - .map(|c| c.as_os_str().to_str().unwrap()) - .collect::>() - .join("::"); - - parse_contents(&content, &module) -} - -fn parse_contents(content: &str, module: &str) -> impl Iterator { - let lints = DEC_CLIPPY_LINT_RE - .captures_iter(content) - .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, module)); - let deprecated = DEC_DEPRECATED_LINT_RE - .captures_iter(content) - .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), module)); - // Removing the `.collect::>().into_iter()` causes some lifetime issues due to the map - lints.chain(deprecated).collect::>().into_iter() -} - -/// Collects all .rs files in the `clippy_lints/src` directory -fn lint_files() -> impl Iterator { - // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories. - // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`. - let path = clippy_project_root().join("clippy_lints/src"); - WalkDir::new(path) - .into_iter() - .filter_map(Result::ok) - .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) -} - -/// Whether a file has had its text changed or not -#[derive(PartialEq, Debug)] -pub struct FileChange { - pub changed: bool, - pub new_lines: String, -} - -/// Replaces a region in a file delimited by two lines matching regexes. -/// -/// `path` is the relative path to the file on which you want to perform the replacement. -/// -/// See `replace_region_in_text` for documentation of the other options. -/// -/// # Panics -/// -/// Panics if the path could not read or then written -pub fn replace_region_in_file( - path: &Path, - start: &str, - end: &str, - replace_start: bool, - write_back: bool, - replacements: F, -) -> FileChange -where - F: FnOnce() -> Vec, -{ - let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.display(), e)); - let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements); - - if write_back { - if let Err(e) = fs::write(path, file_change.new_lines.as_bytes()) { - panic!("Cannot write to {}: {}", path.display(), e); - } - } - file_change -} - -/// Replaces a region in a text delimited by two lines matching regexes. -/// -/// * `text` is the input text on which you want to perform the replacement -/// * `start` is a `&str` that describes the delimiter line before the region you want to replace. -/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. -/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen. -/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. -/// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end` -/// delimiter line is never replaced. -/// * `replacements` is a closure that has to return a `Vec` which contains the new text. -/// -/// If you want to perform the replacement on files instead of already parsed text, -/// use `replace_region_in_file`. -/// -/// # Example -/// -/// ``` -/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end"; -/// let result = -/// clippy_dev::replace_region_in_text(the_text, "replace_start", "replace_end", false, || { -/// vec!["a different".to_string(), "text".to_string()] -/// }) -/// .new_lines; -/// assert_eq!("replace_start\na different\ntext\nreplace_end", result); -/// ``` -/// -/// # Panics -/// -/// Panics if start or end is not valid regex -pub fn replace_region_in_text(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange -where - F: FnOnce() -> Vec, -{ - let replace_it = replacements(); - let mut in_old_region = false; - let mut found = false; - let mut new_lines = vec![]; - let start = Regex::new(start).unwrap(); - let end = Regex::new(end).unwrap(); - - for line in text.lines() { - if in_old_region { - if end.is_match(line) { - in_old_region = false; - new_lines.extend(replace_it.clone()); - new_lines.push(line.to_string()); - } - } else if start.is_match(line) { - if !replace_start { - new_lines.push(line.to_string()); - } - in_old_region = true; - found = true; - } else { - new_lines.push(line.to_string()); - } - } - - if !found { - // This happens if the provided regex in `clippy_dev/src/main.rs` does not match in the - // given text or file. Most likely this is an error on the programmer's side and the Regex - // is incorrect. - eprintln!("error: regex \n{:?}\ndoesn't match. You may have to update it.", start); - std::process::exit(1); - } - - let mut new_lines = new_lines.join("\n"); - if text.ends_with('\n') { - new_lines.push('\n'); - } - let changed = new_lines != text; - FileChange { changed, new_lines } -} - /// Returns the path to the Clippy project directory /// /// # Panics @@ -360,200 +36,3 @@ pub fn clippy_project_root() -> PathBuf { } panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); } - -#[test] -fn test_parse_contents() { - let result: Vec = parse_contents( - r#" -declare_clippy_lint! { - pub PTR_ARG, - style, - "really long \ - text" -} - -declare_clippy_lint!{ - pub DOC_MARKDOWN, - pedantic, - "single line" -} - -/// some doc comment -declare_deprecated_lint! { - pub SHOULD_ASSERT_EQ, - "`assert!()` will be more flexible with RFC 2011" -} - "#, - "module_name", - ) - .collect(); - - let expected = vec![ - Lint::new("ptr_arg", "style", "really long text", None, "module_name"), - Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"), - Lint::new( - "should_assert_eq", - "Deprecated", - "`assert!()` will be more flexible with RFC 2011", - Some("`assert!()` will be more flexible with RFC 2011"), - "module_name", - ), - ]; - assert_eq!(expected, result); -} - -#[test] -fn test_replace_region() { - let text = "\nabc\n123\n789\ndef\nghi"; - let expected = FileChange { - changed: true, - new_lines: "\nabc\nhello world\ndef\nghi".to_string(), - }; - let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || { - vec!["hello world".to_string()] - }); - assert_eq!(expected, result); -} - -#[test] -fn test_replace_region_with_start() { - let text = "\nabc\n123\n789\ndef\nghi"; - let expected = FileChange { - changed: true, - new_lines: "\nhello world\ndef\nghi".to_string(), - }; - let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || { - vec!["hello world".to_string()] - }); - assert_eq!(expected, result); -} - -#[test] -fn test_replace_region_no_changes() { - let text = "123\n456\n789"; - let expected = FileChange { - changed: false, - new_lines: "123\n456\n789".to_string(), - }; - let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new); - assert_eq!(expected, result); -} - -#[test] -fn test_usable_lints() { - let lints = vec![ - Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"), - Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"), - ]; - let expected = vec![Lint::new( - "should_assert_eq2", - "Not Deprecated", - "abc", - None, - "module_name", - )]; - assert_eq!(expected, Lint::usable_lints(&lints)); -} - -#[test] -fn test_by_lint_group() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), - Lint::new("incorrect_match", "group1", "abc", None, "module_name"), - ]; - let mut expected: HashMap> = HashMap::new(); - expected.insert( - "group1".to_string(), - vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("incorrect_match", "group1", "abc", None, "module_name"), - ], - ); - expected.insert( - "group2".to_string(), - vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")], - ); - assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); -} - -#[test] -fn test_gen_changelog_lint_list() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), - ]; - let expected = vec![ - format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()), - format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()), - ]; - assert_eq!(expected, gen_changelog_lint_list(lints.iter())); -} - -#[test] -fn test_gen_deprecated() { - let lints = vec![ - Lint::new( - "should_assert_eq", - "group1", - "abc", - Some("has been superseded by should_assert_eq2"), - "module_name", - ), - Lint::new( - "another_deprecated", - "group2", - "abc", - Some("will be removed"), - "module_name", - ), - ]; - let expected: Vec = vec![ - " store.register_removed(", - " \"clippy::should_assert_eq\",", - " \"has been superseded by should_assert_eq2\",", - " );", - " store.register_removed(", - " \"clippy::another_deprecated\",", - " \"will be removed\",", - " );", - ] - .into_iter() - .map(String::from) - .collect(); - assert_eq!(expected, gen_deprecated(lints.iter())); -} - -#[test] -#[should_panic] -fn test_gen_deprecated_fail() { - let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")]; - let _deprecated_lints = gen_deprecated(lints.iter()); -} - -#[test] -fn test_gen_modules_list() { - let lints = vec![ - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"), - ]; - let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()]; - assert_eq!(expected, gen_modules_list(lints.iter())); -} - -#[test] -fn test_gen_lint_group_list() { - let lints = vec![ - Lint::new("abc", "group1", "abc", None, "module_name"), - Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), - Lint::new("internal", "internal_style", "abc", None, "module_name"), - ]; - let expected = vec![ - " LintId::of(module_name::ABC),".to_string(), - " LintId::of(module_name::INTERNAL),".to_string(), - " LintId::of(module_name::SHOULD_ASSERT_EQ),".to_string(), - ]; - assert_eq!(expected, gen_lint_group_list(lints.iter())); -} diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index db467c26f15..10d859988f6 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -1,8 +1,45 @@ -use crate::{ - gather_all, gen_changelog_lint_list, gen_deprecated, gen_lint_group_list, gen_modules_list, gen_register_lint_list, - replace_region_in_file, Lint, DOCS_LINK, -}; +use itertools::Itertools; +use regex::Regex; +use std::collections::HashMap; +use std::ffi::OsStr; +use std::fs; +use std::lazy::SyncLazy; use std::path::Path; +use walkdir::WalkDir; + +use crate::clippy_project_root; + +const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\ + // Use that command to update this file and do not edit by hand.\n\ + // Manual edits will be overwritten.\n\n"; + +static DEC_CLIPPY_LINT_RE: SyncLazy = SyncLazy::new(|| { + Regex::new( + r#"(?x) + declare_clippy_lint!\s*[\{(] + (?:\s+///.*)* + \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* + (?P[a-z_]+)\s*,\s* + "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] +"#, + ) + .unwrap() +}); + +static DEC_DEPRECATED_LINT_RE: SyncLazy = SyncLazy::new(|| { + Regex::new( + r#"(?x) + declare_deprecated_lint!\s*[{(]\s* + (?:\s+///.*)* + \s+pub\s+(?P[A-Z_][A-Z_0-9]*)\s*,\s* + "(?P(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] +"#, + ) + .unwrap() +}); +static NL_ESCAPE_RE: SyncLazy = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap()); + +static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; #[derive(Clone, Copy, PartialEq)] pub enum UpdateMode { @@ -10,6 +47,15 @@ pub enum UpdateMode { Change, } +/// Runs the `update_lints` command. +/// +/// This updates various generated values from the lint source code. +/// +/// `update_mode` indicates if the files should be updated or if updates should be checked for. +/// +/// # Panics +/// +/// Panics if a file path could not read from or then written to #[allow(clippy::too_many_lines)] pub fn run(update_mode: UpdateMode) { let lint_list: Vec = gather_all().collect(); @@ -52,26 +98,7 @@ pub fn run(update_mode: UpdateMode) { ) .changed; - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - "begin deprecated lints", - "end deprecated lints", - false, - update_mode == UpdateMode::Change, - || gen_deprecated(deprecated_lints.iter()), - ) - .changed; - - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - "begin register lints", - "end register lints", - false, - update_mode == UpdateMode::Change, - || gen_register_lint_list(internal_lints.iter(), usable_lints.iter()), - ) - .changed; - + // This has to be in lib.rs, otherwise rustfmt doesn't work file_change |= replace_region_in_file( Path::new("clippy_lints/src/lib.rs"), "begin lints modules", @@ -82,46 +109,37 @@ pub fn run(update_mode: UpdateMode) { ) .changed; - // Generate lists of lints in the clippy::all lint group - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - r#"store.register_group\(true, "clippy::all""#, - r#"\]\);"#, - false, - update_mode == UpdateMode::Change, - || { - // clippy::all should only include the following lint groups: - let all_group_lints = usable_lints.iter().filter(|l| { - matches!( - &*l.group, - "correctness" | "suspicious" | "style" | "complexity" | "perf" - ) - }); - - gen_lint_group_list(all_group_lints) - }, - ) - .changed; - - // Generate the list of lints for all other lint groups - for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { - file_change |= replace_region_in_file( - Path::new("clippy_lints/src/lib.rs"), - &format!("store.register_group\\(true, \"clippy::{}\"", lint_group), - r#"\]\);"#, - false, - update_mode == UpdateMode::Change, - || gen_lint_group_list(lints.iter()), - ) - .changed; + if file_change && update_mode == UpdateMode::Check { + exit_with_failure(); } - if update_mode == UpdateMode::Check && file_change { - println!( - "Not all lints defined properly. \ - Please run `cargo dev update_lints` to make sure all lints are defined properly." + process_file( + "clippy_lints/src/lib.register_lints.rs", + update_mode, + &gen_register_lint_list(internal_lints.iter(), usable_lints.iter()), + ); + process_file( + "clippy_lints/src/lib.deprecated.rs", + update_mode, + &gen_deprecated(deprecated_lints.iter()), + ); + + let all_group_lints = usable_lints.iter().filter(|l| { + matches!( + &*l.group, + "correctness" | "suspicious" | "style" | "complexity" | "perf" + ) + }); + let content = gen_lint_group_list("all", all_group_lints); + process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content); + + for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { + let content = gen_lint_group_list(&lint_group, lints.iter()); + process_file( + &format!("clippy_lints/src/lib.register_{}.rs", lint_group), + update_mode, + &content, ); - std::process::exit(1); } } @@ -150,3 +168,538 @@ pub fn print_lints() { fn round_to_fifty(count: usize) -> usize { count / 50 * 50 } + +fn process_file(path: impl AsRef, update_mode: UpdateMode, content: &str) { + if update_mode == UpdateMode::Check { + let old_content = + fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.as_ref().display(), e)); + if content != old_content { + exit_with_failure(); + } + } else { + fs::write(&path, content.as_bytes()) + .unwrap_or_else(|e| panic!("Cannot write to {}: {}", path.as_ref().display(), e)); + } +} + +fn exit_with_failure() { + println!( + "Not all lints defined properly. \ + Please run `cargo dev update_lints` to make sure all lints are defined properly." + ); + std::process::exit(1); +} + +/// Lint data parsed from the Clippy source code. +#[derive(Clone, PartialEq, Debug)] +struct Lint { + name: String, + group: String, + desc: String, + deprecation: Option, + module: String, +} + +impl Lint { + #[must_use] + fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self { + Self { + name: name.to_lowercase(), + group: group.to_string(), + desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(), + deprecation: deprecation.map(ToString::to_string), + module: module.to_string(), + } + } + + /// Returns all non-deprecated lints and non-internal lints + #[must_use] + fn usable_lints(lints: &[Self]) -> Vec { + lints + .iter() + .filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal")) + .cloned() + .collect() + } + + /// Returns all internal lints (not `internal_warn` lints) + #[must_use] + fn internal_lints(lints: &[Self]) -> Vec { + lints.iter().filter(|l| l.group == "internal").cloned().collect() + } + + /// Returns all deprecated lints + #[must_use] + fn deprecated_lints(lints: &[Self]) -> Vec { + lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect() + } + + /// Returns the lints in a `HashMap`, grouped by the different lint groups + #[must_use] + fn by_lint_group(lints: impl Iterator) -> HashMap> { + lints.map(|lint| (lint.group.to_string(), lint)).into_group_map() + } +} + +/// Generates the code for registering a group +fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator) -> String { + let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect(); + details.sort_unstable(); + + let mut output = GENERATED_FILE_COMMENT.to_string(); + + output.push_str(&format!( + "store.register_group(true, \"clippy::{0}\", Some(\"clippy_{0}\"), vec![\n", + group_name + )); + for (module, name) in details { + output.push_str(&format!(" LintId::of({}::{}),\n", module, name)); + } + output.push_str("])\n"); + + output +} + +/// Generates the module declarations for `lints` +#[must_use] +fn gen_modules_list<'a>(lints: impl Iterator) -> Vec { + lints + .map(|l| &l.module) + .unique() + .map(|module| format!("mod {};", module)) + .sorted() + .collect::>() +} + +/// Generates the list of lint links at the bottom of the CHANGELOG +#[must_use] +fn gen_changelog_lint_list<'a>(lints: impl Iterator) -> Vec { + lints + .sorted_by_key(|l| &l.name) + .map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name)) + .collect() +} + +/// Generates the `register_removed` code +#[must_use] +fn gen_deprecated<'a>(lints: impl Iterator) -> String { + let mut output = GENERATED_FILE_COMMENT.to_string(); + output.push_str("{\n"); + for Lint { name, deprecation, .. } in lints { + output.push_str(&format!( + concat!( + " store.register_removed(\n", + " \"clippy::{}\",\n", + " \"{}\",\n", + " );\n" + ), + name, + deprecation.as_ref().expect("`lints` are deprecated") + )); + } + output.push_str("}\n"); + + output +} + +/// Generates the code for registering lints +#[must_use] +fn gen_register_lint_list<'a>( + internal_lints: impl Iterator, + usable_lints: impl Iterator, +) -> String { + let mut details: Vec<_> = internal_lints + .map(|l| (false, &l.module, l.name.to_uppercase())) + .chain(usable_lints.map(|l| (true, &l.module, l.name.to_uppercase()))) + .collect(); + details.sort_unstable(); + + let mut output = GENERATED_FILE_COMMENT.to_string(); + output.push_str("store.register_lints(&[\n"); + + for (is_public, module_name, lint_name) in details { + if !is_public { + output.push_str(" #[cfg(feature = \"internal-lints\")]\n"); + } + output.push_str(&format!(" {}::{},\n", module_name, lint_name)); + } + output.push_str("])\n"); + + output +} + +/// Gathers all files in `src/clippy_lints` and gathers all lints inside +fn gather_all() -> impl Iterator { + lint_files().flat_map(|f| gather_from_file(&f)) +} + +fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator { + let content = fs::read_to_string(dir_entry.path()).unwrap(); + let path = dir_entry.path(); + let filename = path.file_stem().unwrap(); + let path_buf = path.with_file_name(filename); + let mut rel_path = path_buf + .strip_prefix(clippy_project_root().join("clippy_lints/src")) + .expect("only files in `clippy_lints/src` should be looked at"); + // If the lints are stored in mod.rs, we get the module name from + // the containing directory: + if filename == "mod" { + rel_path = rel_path.parent().unwrap(); + } + + let module = rel_path + .components() + .map(|c| c.as_os_str().to_str().unwrap()) + .collect::>() + .join("::"); + + parse_contents(&content, &module) +} + +fn parse_contents(content: &str, module: &str) -> impl Iterator { + let lints = DEC_CLIPPY_LINT_RE + .captures_iter(content) + .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, module)); + let deprecated = DEC_DEPRECATED_LINT_RE + .captures_iter(content) + .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), module)); + // Removing the `.collect::>().into_iter()` causes some lifetime issues due to the map + lints.chain(deprecated).collect::>().into_iter() +} + +/// Collects all .rs files in the `clippy_lints/src` directory +fn lint_files() -> impl Iterator { + // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories. + // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`. + let path = clippy_project_root().join("clippy_lints/src"); + WalkDir::new(path) + .into_iter() + .filter_map(Result::ok) + .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) +} + +/// Whether a file has had its text changed or not +#[derive(PartialEq, Debug)] +struct FileChange { + changed: bool, + new_lines: String, +} + +/// Replaces a region in a file delimited by two lines matching regexes. +/// +/// `path` is the relative path to the file on which you want to perform the replacement. +/// +/// See `replace_region_in_text` for documentation of the other options. +/// +/// # Panics +/// +/// Panics if the path could not read or then written +fn replace_region_in_file( + path: &Path, + start: &str, + end: &str, + replace_start: bool, + write_back: bool, + replacements: F, +) -> FileChange +where + F: FnOnce() -> Vec, +{ + let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.display(), e)); + let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements); + + if write_back { + if let Err(e) = fs::write(path, file_change.new_lines.as_bytes()) { + panic!("Cannot write to {}: {}", path.display(), e); + } + } + file_change +} + +/// Replaces a region in a text delimited by two lines matching regexes. +/// +/// * `text` is the input text on which you want to perform the replacement +/// * `start` is a `&str` that describes the delimiter line before the region you want to replace. +/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. +/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen. +/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. +/// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end` +/// delimiter line is never replaced. +/// * `replacements` is a closure that has to return a `Vec` which contains the new text. +/// +/// If you want to perform the replacement on files instead of already parsed text, +/// use `replace_region_in_file`. +/// +/// # Example +/// +/// ```ignore +/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end"; +/// let result = +/// replace_region_in_text(the_text, "replace_start", "replace_end", false, || { +/// vec!["a different".to_string(), "text".to_string()] +/// }) +/// .new_lines; +/// assert_eq!("replace_start\na different\ntext\nreplace_end", result); +/// ``` +/// +/// # Panics +/// +/// Panics if start or end is not valid regex +fn replace_region_in_text(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange +where + F: FnOnce() -> Vec, +{ + let replace_it = replacements(); + let mut in_old_region = false; + let mut found = false; + let mut new_lines = vec![]; + let start = Regex::new(start).unwrap(); + let end = Regex::new(end).unwrap(); + + for line in text.lines() { + if in_old_region { + if end.is_match(line) { + in_old_region = false; + new_lines.extend(replace_it.clone()); + new_lines.push(line.to_string()); + } + } else if start.is_match(line) { + if !replace_start { + new_lines.push(line.to_string()); + } + in_old_region = true; + found = true; + } else { + new_lines.push(line.to_string()); + } + } + + if !found { + // This happens if the provided regex in `clippy_dev/src/main.rs` does not match in the + // given text or file. Most likely this is an error on the programmer's side and the Regex + // is incorrect. + eprintln!("error: regex \n{:?}\ndoesn't match. You may have to update it.", start); + std::process::exit(1); + } + + let mut new_lines = new_lines.join("\n"); + if text.ends_with('\n') { + new_lines.push('\n'); + } + let changed = new_lines != text; + FileChange { changed, new_lines } +} + +#[test] +fn test_parse_contents() { + let result: Vec = parse_contents( + r#" +declare_clippy_lint! { + pub PTR_ARG, + style, + "really long \ + text" +} + +declare_clippy_lint!{ + pub DOC_MARKDOWN, + pedantic, + "single line" +} + +/// some doc comment +declare_deprecated_lint! { + pub SHOULD_ASSERT_EQ, + "`assert!()` will be more flexible with RFC 2011" +} + "#, + "module_name", + ) + .collect(); + + let expected = vec![ + Lint::new("ptr_arg", "style", "really long text", None, "module_name"), + Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"), + Lint::new( + "should_assert_eq", + "Deprecated", + "`assert!()` will be more flexible with RFC 2011", + Some("`assert!()` will be more flexible with RFC 2011"), + "module_name", + ), + ]; + assert_eq!(expected, result); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_replace_region() { + let text = "\nabc\n123\n789\ndef\nghi"; + let expected = FileChange { + changed: true, + new_lines: "\nabc\nhello world\ndef\nghi".to_string(), + }; + let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || { + vec!["hello world".to_string()] + }); + assert_eq!(expected, result); + } + + #[test] + fn test_replace_region_with_start() { + let text = "\nabc\n123\n789\ndef\nghi"; + let expected = FileChange { + changed: true, + new_lines: "\nhello world\ndef\nghi".to_string(), + }; + let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || { + vec!["hello world".to_string()] + }); + assert_eq!(expected, result); + } + + #[test] + fn test_replace_region_no_changes() { + let text = "123\n456\n789"; + let expected = FileChange { + changed: false, + new_lines: "123\n456\n789".to_string(), + }; + let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new); + assert_eq!(expected, result); + } + + #[test] + fn test_usable_lints() { + let lints = vec![ + Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"), + Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"), + ]; + let expected = vec![Lint::new( + "should_assert_eq2", + "Not Deprecated", + "abc", + None, + "module_name", + )]; + assert_eq!(expected, Lint::usable_lints(&lints)); + } + + #[test] + fn test_by_lint_group() { + let lints = vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), + Lint::new("incorrect_match", "group1", "abc", None, "module_name"), + ]; + let mut expected: HashMap> = HashMap::new(); + expected.insert( + "group1".to_string(), + vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("incorrect_match", "group1", "abc", None, "module_name"), + ], + ); + expected.insert( + "group2".to_string(), + vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")], + ); + assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); + } + + #[test] + fn test_gen_changelog_lint_list() { + let lints = vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), + ]; + let expected = vec![ + format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()), + format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()), + ]; + assert_eq!(expected, gen_changelog_lint_list(lints.iter())); + } + + #[test] + fn test_gen_deprecated() { + let lints = vec![ + Lint::new( + "should_assert_eq", + "group1", + "abc", + Some("has been superseded by should_assert_eq2"), + "module_name", + ), + Lint::new( + "another_deprecated", + "group2", + "abc", + Some("will be removed"), + "module_name", + ), + ]; + + let expected = GENERATED_FILE_COMMENT.to_string() + + &[ + "{", + " store.register_removed(", + " \"clippy::should_assert_eq\",", + " \"has been superseded by should_assert_eq2\",", + " );", + " store.register_removed(", + " \"clippy::another_deprecated\",", + " \"will be removed\",", + " );", + "}", + ] + .join("\n") + + "\n"; + + assert_eq!(expected, gen_deprecated(lints.iter())); + } + + #[test] + #[should_panic] + fn test_gen_deprecated_fail() { + let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")]; + let _deprecated_lints = gen_deprecated(lints.iter()); + } + + #[test] + fn test_gen_modules_list() { + let lints = vec![ + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"), + ]; + let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()]; + assert_eq!(expected, gen_modules_list(lints.iter())); + } + + #[test] + fn test_gen_lint_group_list() { + let lints = vec![ + Lint::new("abc", "group1", "abc", None, "module_name"), + Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), + Lint::new("internal", "internal_style", "abc", None, "module_name"), + ]; + let expected = GENERATED_FILE_COMMENT.to_string() + + &[ + "store.register_group(true, \"clippy::group1\", Some(\"clippy_group1\"), vec![", + " LintId::of(module_name::ABC),", + " LintId::of(module_name::INTERNAL),", + " LintId::of(module_name::SHOULD_ASSERT_EQ),", + "])", + ] + .join("\n") + + "\n"; + + let result = gen_lint_group_list("group1", lints.iter()); + + assert_eq!(expected, result); + } +} diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 2ef7dcc1775..6f8b645dd70 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -563,7 +563,7 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip; // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 - if let AttrStyle::Outer = attr.style; + if attr.style == AttrStyle::Outer; then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 0cc79c8b6e8..28615b9217c 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -16,7 +16,7 @@ /// The Mutex types found in std::sync and parking_lot /// are not designed to operate in an async context across await points. /// - /// There are two potential solutions. One is to use an asynx-aware Mutex + /// There are two potential solutions. One is to use an async-aware Mutex /// type. Many asynchronous foundation crates provide such a Mutex type. The /// other solution is to ensure the mutex is unlocked before calling await, /// either by introducing a scope or an explicit call to Drop::drop. diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index 63ac8fd2dd2..334e1646cd4 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca } let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { + let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) { 32 } else { 64 diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 15252ef96cd..fdef0abe970 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -83,6 +83,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if !attrs.iter().any(|attr| attr.doc_str().is_some()); if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); if !child_attrs.iter().any(|attr| attr.doc_str().is_some()); + if adt_def.is_struct(); then { if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() { diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 8416b8440df..24ac5917dcb 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -393,7 +393,7 @@ fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: Body if_chain! { if let Some(header) = kind.header(); - if let Unsafety::Unsafe = header.unsafety; + if header.unsafety == Unsafety::Unsafe; then { self.has_unsafe = true; } @@ -408,7 +408,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { } if let ExprKind::Block(block, _) = expr.kind { - if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { self.has_unsafe = true; } } diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 33ed6273ad2..9840affbf6f 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -236,7 +236,17 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { hir::ItemKind::Impl(ref impl_) => { self.in_trait_impl = impl_.of_trait.is_some(); }, - _ => {}, + hir::ItemKind::Trait(_, unsafety, ..) => { + if !headers.safety && unsafety == hir::Unsafety::Unsafe { + span_lint( + cx, + MISSING_SAFETY_DOC, + item.span, + "docs for unsafe trait missing `# Safety` section", + ); + } + }, + _ => (), } } @@ -396,6 +406,15 @@ struct DocHeaders { } fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &'a [Attribute]) -> DocHeaders { + use pulldown_cmark::{BrokenLink, CowStr, Options}; + /// We don't want the parser to choke on intra doc links. Since we don't + /// actually care about rendering them, just pretend that all broken links are + /// point to a fake address. + #[allow(clippy::unnecessary_wraps)] // we're following a type signature + fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> { + Some(("fake".into(), "fake".into())) + } + let mut doc = String::new(); let mut spans = vec![]; @@ -430,7 +449,10 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs }; } - let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter(); + let mut cb = fake_broken_link_callback; + + let parser = + pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter(); // Iterate over all `Events` and combine consecutive events into one let events = parser.coalesce(|previous, current| { use pulldown_cmark::Event::Text; diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs new file mode 100644 index 00000000000..0c6ba91c943 --- /dev/null +++ b/clippy_lints/src/equatable_if_let.rs @@ -0,0 +1,100 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::implements_trait; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for pattern matchings that can be expressed using equality. + /// + /// ### Why is this bad? + /// + /// * It reads better and has less cognitive load because equality won't cause binding. + /// * It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely + /// criticized for increasing the cognitive load of reading the code. + /// * Equality is a simple bool expression and can be merged with `&&` and `||` and + /// reuse if blocks + /// + /// ### Example + /// ```rust,ignore + /// if let Some(2) = x { + /// do_thing(); + /// } + /// ``` + /// Should be written + /// ```rust,ignore + /// if x == Some(2) { + /// do_thing(); + /// } + /// ``` + pub EQUATABLE_IF_LET, + nursery, + "using pattern matching instead of equality" +} + +declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]); + +/// detects if pattern matches just one thing +fn unary_pattern(pat: &Pat<'_>) -> bool { + fn array_rec(pats: &[Pat<'_>]) -> bool { + pats.iter().all(unary_pattern) + } + match &pat.kind { + PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => { + false + }, + PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a), + PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), + PatKind::Path(_) | PatKind::Lit(_) => true, + } +} + +fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool { + if let Some(def_id) = cx.tcx.lang_items().eq_trait() { + implements_trait(cx, ty, def_id, &[other.into()]) + } else { + false + } +} + +impl<'tcx> LateLintPass<'tcx> for PatternEquality { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if let ExprKind::Let(pat, exp, _) = expr.kind; + if unary_pattern(pat); + let exp_ty = cx.typeck_results().expr_ty(exp); + let pat_ty = cx.typeck_results().pat_ty(pat); + if is_structural_partial_eq(cx, exp_ty, pat_ty); + then { + + let mut applicability = Applicability::MachineApplicable; + let pat_str = match pat.kind { + PatKind::Struct(..) => format!( + "({})", + snippet_with_applicability(cx, pat.span, "..", &mut applicability), + ), + _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(), + }; + span_lint_and_sugg( + cx, + EQUATABLE_IF_LET, + expr.span, + "this pattern matching can be expressed using equality", + "try", + format!( + "{} == {}", + snippet_with_applicability(cx, exp.span, "..", &mut applicability), + pat_str, + ), + applicability, + ); + } + } + } +} diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 026d14d0ea2..d0944c37cf5 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -47,7 +47,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { } fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) { - if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), e) { + if constant_simple(cx, cx.typeck_results(), e) == Some(Constant::Int(0)) { span_lint( cx, ERASING_OP, diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 090be73af3b..75b1c882c23 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -90,7 +90,7 @@ fn check_fn( for trait_item in items { if trait_item.id.hir_id() == hir_id { // be sure we have `self` parameter in this function - if let AssocItemKind::Fn { has_self: true } = trait_item.kind { + if trait_item.kind == (AssocItemKind::Fn { has_self: true }) { trait_self_ty = Some( TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()) .self_ty() diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 9df92cc5b64..765a6c7585a 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -116,7 +116,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Some(mut snippet) = snippet_opt(cx, callee.span) { if_chain! { if let ty::Closure(_, substs) = callee_ty.peel_refs().kind(); - if let ClosureKind::FnMut = substs.as_closure().kind(); + if substs.as_closure().kind() == ClosureKind::FnMut; if get_enclosing_loop_or_closure(cx.tcx, expr).is_some() || UsedAfterExprVisitor::is_found(cx, callee); diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 8714ce90164..1b56dd4b081 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -141,7 +141,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) { match typ.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let sig = typ.fn_sig(self.cx.tcx); - if let ty::Never = self.cx.tcx.erase_late_bound_regions(sig).output().kind() { + if self.cx.tcx.erase_late_bound_regions(sig).output().kind() == &ty::Never { self.report_diverging_sub_expr(e); } }, diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 129a8475e1c..8df7f91ce59 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -112,7 +112,7 @@ fn is_display_arg(expr: &Expr<'_>) -> bool { if let ExprKind::Call(_, [_, fmt]) = expr.kind; if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind; if let [.., t, _] = path.segments; - if t.ident.name.as_str() == "Display"; + if t.ident.name == sym::Display; then { true } else { false } } } diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 5feb0ce8dec..73bdd67ff5d 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,5 +1,4 @@ use clippy_utils::source::snippet; -use if_chain::if_chain; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -62,16 +61,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool { // `1 << 0` is a common pattern in bit manipulation code - if_chain! { - if let BinOpKind::Shl = cmp.node; - if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), right); - if let Some(Constant::Int(1)) = constant_simple(cx, cx.typeck_results(), left); - then { - return true; - } - } - - false + cmp.node == BinOpKind::Shl + && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0)) + && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)) } #[allow(clippy::cast_possible_wrap)] diff --git a/clippy_lints/src/if_then_panic.rs b/clippy_lints/src/if_then_panic.rs index ee575c81a8b..10bca59e6d0 100644 --- a/clippy_lints/src/if_then_panic.rs +++ b/clippy_lints/src/if_then_panic.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::PanicExpn; -use clippy_utils::is_expn_of; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{is_expn_of, sugg}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -74,12 +74,14 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { }; let mut applicability = Applicability::MachineApplicable; let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); - - let cond_sugg = - if let ExprKind::DropTemps(Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..}) = cond.kind { - snippet_with_applicability(cx, not_expr.span, "..", &mut applicability).to_string() + let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind { + if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e { + sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string() + } else { + format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par().to_string()) + } } else { - format!("!{}", snippet_with_applicability(cx, cond.span, "..", &mut applicability)) + format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par().to_string()) }; span_lint_and_sugg( diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 9da06d1418e..81eb51e6f7c 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -167,12 +167,20 @@ fn suggestion<'tcx>( continue; } let generics_suggestion_span = generics.span.substitute_dummy({ - let pos = snippet_opt(cx, item.span.until(body.params[0].pat.span)) - .and_then(|snip| { - let i = snip.find("fn")?; - Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32)) - }) - .expect("failed to create span for type parameters"); + let pos = snippet_opt( + cx, + Span::new( + item.span.lo(), + body.params[0].pat.span.lo(), + item.span.ctxt(), + item.span.parent(), + ), + ) + .and_then(|snip| { + let i = snip.find("fn")?; + Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32)) + }) + .expect("failed to create span for type parameters"); Span::new(pos, pos, item.span.ctxt(), item.span.parent()) }); diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index a0e6f12b812..c962e814fa5 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -48,7 +48,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool { if_chain! { if let hir::ExprKind::Binary(binop, left, right) = &expr.kind; - if let hir::BinOpKind::Div = &binop.node; + if binop.node == hir::BinOpKind::Div; then { let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right)); return left_ty.is_integral() && right_ty.is_integral(); diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index e4b8e754628..392166237be 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,13 +1,14 @@ //! lint when there is a large size difference between variants on an enum use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind, VariantData}; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does @@ -58,6 +59,17 @@ pub fn new(maximum_size_difference_allowed: u64) -> Self { } } +struct FieldInfo { + ind: usize, + size: u64, +} + +struct VariantInfo { + ind: usize, + size: u64, + fields_size: Vec, +} + impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]); impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { @@ -68,72 +80,95 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Enum(ref def, _) = item.kind { let ty = cx.tcx.type_of(item.def_id); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); - - let mut largest_variant: Option<(_, _)> = None; - let mut second_variant: Option<(_, _)> = None; - - for (i, variant) in adt.variants.iter().enumerate() { - let size: u64 = variant - .fields - .iter() - .filter_map(|f| { - let ty = cx.tcx.type_of(f.did); - // don't count generics by filtering out everything - // that does not have a layout - cx.layout_of(ty).ok().map(|l| l.size.bytes()) - }) - .sum(); - - let grouped = (size, (i, variant)); - - if grouped.0 >= largest_variant.map_or(0, |x| x.0) { - second_variant = largest_variant; - largest_variant = Some(grouped); - } + if adt.variants.len() <= 1 { + return; } + let mut variants_size: Vec = adt + .variants + .iter() + .enumerate() + .map(|(i, variant)| { + let mut fields_size = Vec::new(); + let size: u64 = variant + .fields + .iter() + .enumerate() + .filter_map(|(i, f)| { + let ty = cx.tcx.type_of(f.did); + // don't count generics by filtering out everything + // that does not have a layout + cx.layout_of(ty).ok().map(|l| { + let size = l.size.bytes(); + fields_size.push(FieldInfo { ind: i, size }); + size + }) + }) + .sum(); + VariantInfo { + ind: i, + size, + fields_size, + } + }) + .collect(); - if let (Some(largest), Some(second)) = (largest_variant, second_variant) { - let difference = largest.0 - second.0; + variants_size.sort_by(|a, b| (b.size.cmp(&a.size))); - if difference > self.maximum_size_difference_allowed { - let (i, variant) = largest.1; + let mut difference = variants_size[0].size - variants_size[1].size; + if difference > self.maximum_size_difference_allowed { + let help_text = "consider boxing the large fields to reduce the total size of the enum"; + span_lint_and_then( + cx, + LARGE_ENUM_VARIANT, + def.variants[variants_size[0].ind].span, + "large size difference between variants", + |diag| { + diag.span_label( + def.variants[variants_size[0].ind].span, + &format!("this variant is {} bytes", variants_size[0].size), + ); + diag.span_note( + def.variants[variants_size[1].ind].span, + &format!("and the second-largest variant is {} bytes:", variants_size[1].size), + ); - let help_text = "consider boxing the large fields to reduce the total size of the enum"; - span_lint_and_then( - cx, - LARGE_ENUM_VARIANT, - def.variants[i].span, - "large size difference between variants", - |diag| { - diag.span_label( - def.variants[(largest.1).0].span, - &format!("this variant is {} bytes", largest.0), - ); - diag.span_note( - def.variants[(second.1).0].span, - &format!("and the second-largest variant is {} bytes:", second.0), - ); - if variant.fields.len() == 1 { - let span = match def.variants[i].data { - VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) => { - fields[0].ty.span - }, - VariantData::Unit(..) => unreachable!(), - }; - if let Some(snip) = snippet_opt(cx, span) { - diag.span_suggestion( - span, - help_text, - format!("Box<{}>", snip), - Applicability::MaybeIncorrect, - ); - return; + let fields = def.variants[variants_size[0].ind].data.fields(); + variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size))); + let mut applicability = Applicability::MaybeIncorrect; + let sugg: Vec<(Span, String)> = variants_size[0] + .fields_size + .iter() + .rev() + .map_while(|val| { + if difference > self.maximum_size_difference_allowed { + difference = difference.saturating_sub(val.size); + Some(( + fields[val.ind].ty.span, + format!( + "Box<{}>", + snippet_with_applicability( + cx, + fields[val.ind].ty.span, + "..", + &mut applicability + ) + .into_owned() + ), + )) + } else { + None } - } - diag.span_help(def.variants[i].span, help_text); - }, - ); - } + }) + .collect(); + + if !sugg.is_empty() { + diag.multipart_suggestion(help_text, sugg, Applicability::MaybeIncorrect); + return; + } + + diag.span_help(def.variants[variants_size[0].ind].span, help_text); + }, + ); } } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index de46e50a68a..f336fb9d42f 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -455,14 +455,10 @@ fn is_empty_array(expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if let ty::AssocKind::Fn = item.kind { - if item.ident.name.as_str() == "is_empty" { - let sig = cx.tcx.fn_sig(item.def_id); - let ty = sig.skip_binder(); - ty.inputs().len() == 1 - } else { - false - } + if item.kind == ty::AssocKind::Fn && item.ident.name.as_str() == "is_empty" { + let sig = cx.tcx.fn_sig(item.def_id); + let ty = sig.skip_binder(); + ty.inputs().len() == 1 } else { false } diff --git a/clippy_lints/src/lib.deprecated.rs b/clippy_lints/src/lib.deprecated.rs new file mode 100644 index 00000000000..80bde1b1138 --- /dev/null +++ b/clippy_lints/src/lib.deprecated.rs @@ -0,0 +1,70 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +{ + store.register_removed( + "clippy::should_assert_eq", + "`assert!()` will be more flexible with RFC 2011", + ); + store.register_removed( + "clippy::extend_from_slice", + "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", + ); + store.register_removed( + "clippy::range_step_by_zero", + "`iterator.step_by(0)` panics nowadays", + ); + store.register_removed( + "clippy::unstable_as_slice", + "`Vec::as_slice` has been stabilized in 1.7", + ); + store.register_removed( + "clippy::unstable_as_mut_slice", + "`Vec::as_mut_slice` has been stabilized in 1.7", + ); + store.register_removed( + "clippy::misaligned_transmute", + "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", + ); + store.register_removed( + "clippy::assign_ops", + "using compound assignment operators (e.g., `+=`) is harmless", + ); + store.register_removed( + "clippy::if_let_redundant_pattern_matching", + "this lint has been changed to redundant_pattern_matching", + ); + store.register_removed( + "clippy::unsafe_vector_initialization", + "the replacement suggested by this lint had substantially different behavior", + ); + store.register_removed( + "clippy::unused_collect", + "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint", + ); + store.register_removed( + "clippy::replace_consts", + "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants", + ); + store.register_removed( + "clippy::regex_macro", + "the regex! macro has been removed from the regex crate in 2018", + ); + store.register_removed( + "clippy::find_map", + "this lint has been replaced by `manual_find_map`, a more specific lint", + ); + store.register_removed( + "clippy::filter_map", + "this lint has been replaced by `manual_filter_map`, a more specific lint", + ); + store.register_removed( + "clippy::pub_enum_variant_names", + "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items", + ); + store.register_removed( + "clippy::wrong_pub_self_convention", + "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items", + ); +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs new file mode 100644 index 00000000000..3e6e0244754 --- /dev/null +++ b/clippy_lints/src/lib.register_all.rs @@ -0,0 +1,304 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::all", Some("clippy_all"), vec![ + LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), + LintId::of(approx_const::APPROX_CONSTANT), + LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assign_ops::ASSIGN_OP_PATTERN), + LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), + LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(attrs::DEPRECATED_CFG_ATTR), + LintId::of(attrs::DEPRECATED_SEMVER), + LintId::of(attrs::MISMATCHED_TARGET_OS), + LintId::of(attrs::USELESS_ATTRIBUTE), + LintId::of(bit_mask::BAD_BIT_MASK), + LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(blacklisted_name::BLACKLISTED_NAME), + LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), + LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), + LintId::of(booleans::LOGIC_BUG), + LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CAST_REF_TO_MUT), + LintId::of(casts::CHAR_LIT_AS_U8), + LintId::of(casts::FN_TO_NUMERIC_CAST), + LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(casts::UNNECESSARY_CAST), + LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), + LintId::of(collapsible_if::COLLAPSIBLE_IF), + LintId::of(collapsible_match::COLLAPSIBLE_MATCH), + LintId::of(comparison_chain::COMPARISON_CHAIN), + LintId::of(copies::IFS_SAME_COND), + LintId::of(copies::IF_SAME_THEN_ELSE), + LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(derivable_impls::DERIVABLE_IMPLS), + LintId::of(derive::DERIVE_HASH_XOR_EQ), + LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), + LintId::of(doc::MISSING_SAFETY_DOC), + LintId::of(doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(double_comparison::DOUBLE_COMPARISONS), + LintId::of(double_parens::DOUBLE_PARENS), + LintId::of(drop_forget_ref::DROP_COPY), + LintId::of(drop_forget_ref::DROP_REF), + LintId::of(drop_forget_ref::FORGET_COPY), + LintId::of(drop_forget_ref::FORGET_REF), + LintId::of(duration_subsec::DURATION_SUBSEC), + LintId::of(entry::MAP_ENTRY), + LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(enum_variants::ENUM_VARIANT_NAMES), + LintId::of(enum_variants::MODULE_INCEPTION), + LintId::of(eq_op::EQ_OP), + LintId::of(eq_op::OP_REF), + LintId::of(erasing_op::ERASING_OP), + LintId::of(escape::BOXED_LOCAL), + LintId::of(eta_reduction::REDUNDANT_CLOSURE), + LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(explicit_write::EXPLICIT_WRITE), + LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(float_literal::EXCESSIVE_PRECISION), + LintId::of(format::USELESS_FORMAT), + LintId::of(formatting::POSSIBLE_MISSING_COMMA), + LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(from_over_into::FROM_OVER_INTO), + LintId::of(from_str_radix_10::FROM_STR_RADIX_10), + LintId::of(functions::DOUBLE_MUST_USE), + LintId::of(functions::MUST_USE_UNIT), + LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(functions::RESULT_UNIT_ERR), + LintId::of(functions::TOO_MANY_ARGUMENTS), + LintId::of(get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(identity_op::IDENTITY_OP), + LintId::of(if_let_mutex::IF_LET_MUTEX), + LintId::of(if_then_panic::IF_THEN_PANIC), + LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(infinite_iter::INFINITE_ITER), + LintId::of(inherent_to_string::INHERENT_TO_STRING), + LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(int_plus_one::INT_PLUS_ONE), + LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), + LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(len_zero::COMPARISON_TO_EMPTY), + LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(len_zero::LEN_ZERO), + LintId::of(let_underscore::LET_UNDERSCORE_LOCK), + LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(lifetimes::NEEDLESS_LIFETIMES), + LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), + LintId::of(loops::EMPTY_LOOP), + LintId::of(loops::EXPLICIT_COUNTER_LOOP), + LintId::of(loops::FOR_KV_MAP), + LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), + LintId::of(loops::ITER_NEXT_LOOP), + LintId::of(loops::MANUAL_FLATTEN), + LintId::of(loops::MANUAL_MEMCPY), + LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(loops::NEEDLESS_RANGE_LOOP), + LintId::of(loops::NEVER_LOOP), + LintId::of(loops::SAME_ITEM_PUSH), + LintId::of(loops::SINGLE_ELEMENT_LOOP), + LintId::of(loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(loops::WHILE_LET_LOOP), + LintId::of(loops::WHILE_LET_ON_ITERATOR), + LintId::of(main_recursion::MAIN_RECURSION), + LintId::of(manual_async_fn::MANUAL_ASYNC_FN), + LintId::of(manual_map::MANUAL_MAP), + LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(manual_strip::MANUAL_STRIP), + LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), + LintId::of(map_clone::MAP_CLONE), + LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(match_result_ok::MATCH_RESULT_OK), + LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(matches::MATCH_AS_REF), + LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), + LintId::of(matches::MATCH_OVERLAPPING_ARM), + LintId::of(matches::MATCH_REF_PATS), + LintId::of(matches::MATCH_SINGLE_BINDING), + LintId::of(matches::REDUNDANT_PATTERN_MATCHING), + LintId::of(matches::SINGLE_MATCH), + LintId::of(matches::WILDCARD_IN_OR_PATTERNS), + LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), + LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_NTH), + LintId::of(methods::CHARS_LAST_CMP), + LintId::of(methods::CHARS_NEXT_CMP), + LintId::of(methods::CLONE_DOUBLE_REF), + LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::EXTEND_WITH_DRAIN), + LintId::of(methods::FILTER_MAP_IDENTITY), + LintId::of(methods::FILTER_NEXT), + LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::INSPECT_FOR_EACH), + LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::ITER_CLONED_COLLECT), + LintId::of(methods::ITER_COUNT), + LintId::of(methods::ITER_NEXT_SLICE), + LintId::of(methods::ITER_NTH), + LintId::of(methods::ITER_NTH_ZERO), + LintId::of(methods::ITER_SKIP_NEXT), + LintId::of(methods::MANUAL_FILTER_MAP), + LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MANUAL_SPLIT_ONCE), + LintId::of(methods::MANUAL_STR_REPEAT), + LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OK_EXPECT), + LintId::of(methods::OPTION_AS_REF_DEREF), + LintId::of(methods::OPTION_FILTER_MAP), + LintId::of(methods::OPTION_MAP_OR_NONE), + LintId::of(methods::OR_FUN_CALL), + LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), + LintId::of(methods::SEARCH_IS_SOME), + LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(methods::SINGLE_CHAR_ADD_STR), + LintId::of(methods::SINGLE_CHAR_PATTERN), + LintId::of(methods::SKIP_WHILE_NEXT), + LintId::of(methods::STRING_EXTEND_CHARS), + LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::SUSPICIOUS_SPLITN), + LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNNECESSARY_FILTER_MAP), + LintId::of(methods::UNNECESSARY_FOLD), + LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), + LintId::of(methods::USELESS_ASREF), + LintId::of(methods::WRONG_SELF_CONVENTION), + LintId::of(methods::ZST_OFFSET), + LintId::of(minmax::MIN_MAX), + LintId::of(misc::CMP_NAN), + LintId::of(misc::CMP_OWNED), + LintId::of(misc::MODULO_ONE), + LintId::of(misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(misc::TOPLEVEL_REF_ARG), + LintId::of(misc::ZERO_PTR), + LintId::of(misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(misc_early::DOUBLE_NEG), + LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(misc_early::REDUNDANT_PATTERN), + LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), + LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(mutex_atomic::MUTEX_ATOMIC), + LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), + LintId::of(needless_bool::BOOL_COMPARISON), + LintId::of(needless_bool::NEEDLESS_BOOL), + LintId::of(needless_borrow::NEEDLESS_BORROW), + LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), + LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), + LintId::of(needless_update::NEEDLESS_UPDATE), + LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(neg_multiply::NEG_MULTIPLY), + LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(no_effect::NO_EFFECT), + LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), + LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), + LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(precedence::PRECEDENCE), + LintId::of(ptr::CMP_NULL), + LintId::of(ptr::INVALID_NULL_PTR_USAGE), + LintId::of(ptr::MUT_FROM_REF), + LintId::of(ptr::PTR_ARG), + LintId::of(ptr_eq::PTR_EQ), + LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(question_mark::QUESTION_MARK), + LintId::of(ranges::MANUAL_RANGE_CONTAINS), + LintId::of(ranges::RANGE_ZIP_WITH_LEN), + LintId::of(ranges::REVERSED_EMPTY_RANGES), + LintId::of(redundant_clone::REDUNDANT_CLONE), + LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), + LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(redundant_slicing::REDUNDANT_SLICING), + LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(reference::DEREF_ADDROF), + LintId::of(reference::REF_IN_DEREF), + LintId::of(regex::INVALID_REGEX), + LintId::of(repeat_once::REPEAT_ONCE), + LintId::of(returns::LET_AND_RETURN), + LintId::of(returns::NEEDLESS_RETURN), + LintId::of(self_assignment::SELF_ASSIGNMENT), + LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), + LintId::of(serde_api::SERDE_API_MISUSE), + LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), + LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), + LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), + LintId::of(swap::ALMOST_SWAPPED), + LintId::of(swap::MANUAL_SWAP), + LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), + LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), + LintId::of(transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), + LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), + LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(transmute::WRONG_TRANSMUTE), + LintId::of(transmuting_null::TRANSMUTING_NULL), + LintId::of(try_err::TRY_ERR), + LintId::of(types::BORROWED_BOX), + LintId::of(types::BOX_COLLECTION), + LintId::of(types::REDUNDANT_ALLOCATION), + LintId::of(types::TYPE_COMPLEXITY), + LintId::of(types::VEC_BOX), + LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), + LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(unit_types::UNIT_ARG), + LintId::of(unit_types::UNIT_CMP), + LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unused_unit::UNUSED_UNIT), + LintId::of(unwrap::PANICKING_UNWRAP), + LintId::of(unwrap::UNNECESSARY_UNWRAP), + LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), + LintId::of(useless_conversion::USELESS_CONVERSION), + LintId::of(vec::USELESS_VEC), + LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), + LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), + LintId::of(write::PRINTLN_EMPTY_STRING), + LintId::of(write::PRINT_LITERAL), + LintId::of(write::PRINT_WITH_NEWLINE), + LintId::of(write::WRITELN_EMPTY_STRING), + LintId::of(write::WRITE_LITERAL), + LintId::of(write::WRITE_WITH_NEWLINE), + LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), +]) diff --git a/clippy_lints/src/lib.register_cargo.rs b/clippy_lints/src/lib.register_cargo.rs new file mode 100644 index 00000000000..1809f2cc7d4 --- /dev/null +++ b/clippy_lints/src/lib.register_cargo.rs @@ -0,0 +1,11 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![ + LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA), + LintId::of(feature_name::NEGATIVE_FEATURE_NAMES), + LintId::of(feature_name::REDUNDANT_FEATURE_NAMES), + LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), + LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES), +]) diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs new file mode 100644 index 00000000000..64b82fc0faa --- /dev/null +++ b/clippy_lints/src/lib.register_complexity.rs @@ -0,0 +1,94 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ + LintId::of(attrs::DEPRECATED_CFG_ATTR), + LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CHAR_LIT_AS_U8), + LintId::of(casts::UNNECESSARY_CAST), + LintId::of(derivable_impls::DERIVABLE_IMPLS), + LintId::of(double_comparison::DOUBLE_COMPARISONS), + LintId::of(double_parens::DOUBLE_PARENS), + LintId::of(duration_subsec::DURATION_SUBSEC), + LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), + LintId::of(explicit_write::EXPLICIT_WRITE), + LintId::of(format::USELESS_FORMAT), + LintId::of(functions::TOO_MANY_ARGUMENTS), + LintId::of(get_last_with_len::GET_LAST_WITH_LEN), + LintId::of(identity_op::IDENTITY_OP), + LintId::of(int_plus_one::INT_PLUS_ONE), + LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), + LintId::of(lifetimes::NEEDLESS_LIFETIMES), + LintId::of(loops::EXPLICIT_COUNTER_LOOP), + LintId::of(loops::MANUAL_FLATTEN), + LintId::of(loops::SINGLE_ELEMENT_LOOP), + LintId::of(loops::WHILE_LET_LOOP), + LintId::of(manual_strip::MANUAL_STRIP), + LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), + LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), + LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), + LintId::of(matches::MATCH_AS_REF), + LintId::of(matches::MATCH_SINGLE_BINDING), + LintId::of(matches::WILDCARD_IN_OR_PATTERNS), + LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::FILTER_MAP_IDENTITY), + LintId::of(methods::FILTER_NEXT), + LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::INSPECT_FOR_EACH), + LintId::of(methods::ITER_COUNT), + LintId::of(methods::MANUAL_FILTER_MAP), + LintId::of(methods::MANUAL_FIND_MAP), + LintId::of(methods::MANUAL_SPLIT_ONCE), + LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::OPTION_AS_REF_DEREF), + LintId::of(methods::OPTION_FILTER_MAP), + LintId::of(methods::SEARCH_IS_SOME), + LintId::of(methods::SKIP_WHILE_NEXT), + LintId::of(methods::UNNECESSARY_FILTER_MAP), + LintId::of(methods::USELESS_ASREF), + LintId::of(misc::SHORT_CIRCUIT_STATEMENT), + LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), + LintId::of(misc_early::ZERO_PREFIXED_LITERAL), + LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), + LintId::of(needless_bool::BOOL_COMPARISON), + LintId::of(needless_bool::NEEDLESS_BOOL), + LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), + LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), + LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), + LintId::of(needless_update::NEEDLESS_UPDATE), + LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), + LintId::of(no_effect::NO_EFFECT), + LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), + LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(precedence::PRECEDENCE), + LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), + LintId::of(ranges::RANGE_ZIP_WITH_LEN), + LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), + LintId::of(redundant_slicing::REDUNDANT_SLICING), + LintId::of(reference::DEREF_ADDROF), + LintId::of(reference::REF_IN_DEREF), + LintId::of(repeat_once::REPEAT_ONCE), + LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), + LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), + LintId::of(swap::MANUAL_SWAP), + LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), + LintId::of(transmute::CROSSPOINTER_TRANSMUTE), + LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), + LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), + LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), + LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), + LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), + LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(types::BORROWED_BOX), + LintId::of(types::TYPE_COMPLEXITY), + LintId::of(types::VEC_BOX), + LintId::of(unit_types::UNIT_ARG), + LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(unwrap::UNNECESSARY_UNWRAP), + LintId::of(useless_conversion::USELESS_CONVERSION), + LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), +]) diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs new file mode 100644 index 00000000000..e0ef7b3b8af --- /dev/null +++ b/clippy_lints/src/lib.register_correctness.rs @@ -0,0 +1,73 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ + LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), + LintId::of(approx_const::APPROX_CONSTANT), + LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), + LintId::of(attrs::DEPRECATED_SEMVER), + LintId::of(attrs::MISMATCHED_TARGET_OS), + LintId::of(attrs::USELESS_ATTRIBUTE), + LintId::of(bit_mask::BAD_BIT_MASK), + LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), + LintId::of(booleans::LOGIC_BUG), + LintId::of(casts::CAST_REF_TO_MUT), + LintId::of(copies::IFS_SAME_COND), + LintId::of(copies::IF_SAME_THEN_ELSE), + LintId::of(derive::DERIVE_HASH_XOR_EQ), + LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), + LintId::of(drop_forget_ref::DROP_COPY), + LintId::of(drop_forget_ref::DROP_REF), + LintId::of(drop_forget_ref::FORGET_COPY), + LintId::of(drop_forget_ref::FORGET_REF), + LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), + LintId::of(eq_op::EQ_OP), + LintId::of(erasing_op::ERASING_OP), + LintId::of(formatting::POSSIBLE_MISSING_COMMA), + LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(if_let_mutex::IF_LET_MUTEX), + LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), + LintId::of(infinite_iter::INFINITE_ITER), + LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), + LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(let_underscore::LET_UNDERSCORE_LOCK), + LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), + LintId::of(loops::ITER_NEXT_LOOP), + LintId::of(loops::NEVER_LOOP), + LintId::of(loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), + LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(methods::CLONE_DOUBLE_REF), + LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::SUSPICIOUS_SPLITN), + LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::ZST_OFFSET), + LintId::of(minmax::MIN_MAX), + LintId::of(misc::CMP_NAN), + LintId::of(misc::MODULO_ONE), + LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), + LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), + LintId::of(ptr::INVALID_NULL_PTR_USAGE), + LintId::of(ptr::MUT_FROM_REF), + LintId::of(ranges::REVERSED_EMPTY_RANGES), + LintId::of(regex::INVALID_REGEX), + LintId::of(self_assignment::SELF_ASSIGNMENT), + LintId::of(serde_api::SERDE_API_MISUSE), + LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), + LintId::of(swap::ALMOST_SWAPPED), + LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), + LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), + LintId::of(transmute::WRONG_TRANSMUTE), + LintId::of(transmuting_null::TRANSMUTING_NULL), + LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), + LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), + LintId::of(unit_types::UNIT_CMP), + LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), + LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unwrap::PANICKING_UNWRAP), + LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), +]) diff --git a/clippy_lints/src/lib.register_internal.rs b/clippy_lints/src/lib.register_internal.rs new file mode 100644 index 00000000000..c8c1e0262ab --- /dev/null +++ b/clippy_lints/src/lib.register_internal.rs @@ -0,0 +1,18 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ + LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL), + LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), + LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS), + LintId::of(utils::internal_lints::DEFAULT_LINT), + LintId::of(utils::internal_lints::IF_CHAIN_STYLE), + LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL), + LintId::of(utils::internal_lints::INVALID_PATHS), + LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS), + LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), + LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA), + LintId::of(utils::internal_lints::PRODUCE_ICE), + LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR), +]) diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs new file mode 100644 index 00000000000..2ba2b3da55c --- /dev/null +++ b/clippy_lints/src/lib.register_lints.rs @@ -0,0 +1,510 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_lints(&[ + #[cfg(feature = "internal-lints")] + utils::internal_lints::CLIPPY_LINTS_INTERNAL, + #[cfg(feature = "internal-lints")] + utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::COMPILER_LINT_FUNCTIONS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::DEFAULT_LINT, + #[cfg(feature = "internal-lints")] + utils::internal_lints::IF_CHAIN_STYLE, + #[cfg(feature = "internal-lints")] + utils::internal_lints::INTERNING_DEFINED_SYMBOL, + #[cfg(feature = "internal-lints")] + utils::internal_lints::INVALID_PATHS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::LINT_WITHOUT_LINT_PASS, + #[cfg(feature = "internal-lints")] + utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, + #[cfg(feature = "internal-lints")] + utils::internal_lints::OUTER_EXPN_EXPN_DATA, + #[cfg(feature = "internal-lints")] + utils::internal_lints::PRODUCE_ICE, + #[cfg(feature = "internal-lints")] + utils::internal_lints::UNNECESSARY_SYMBOL_STR, + absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, + approx_const::APPROX_CONSTANT, + arithmetic::FLOAT_ARITHMETIC, + arithmetic::INTEGER_ARITHMETIC, + as_conversions::AS_CONVERSIONS, + asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, + asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, + assertions_on_constants::ASSERTIONS_ON_CONSTANTS, + assign_ops::ASSIGN_OP_PATTERN, + assign_ops::MISREFACTORED_ASSIGN_OP, + async_yields_async::ASYNC_YIELDS_ASYNC, + attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, + attrs::DEPRECATED_CFG_ATTR, + attrs::DEPRECATED_SEMVER, + attrs::EMPTY_LINE_AFTER_OUTER_ATTR, + attrs::INLINE_ALWAYS, + attrs::MISMATCHED_TARGET_OS, + attrs::USELESS_ATTRIBUTE, + await_holding_invalid::AWAIT_HOLDING_LOCK, + await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, + bit_mask::BAD_BIT_MASK, + bit_mask::INEFFECTIVE_BIT_MASK, + bit_mask::VERBOSE_BIT_MASK, + blacklisted_name::BLACKLISTED_NAME, + blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, + bool_assert_comparison::BOOL_ASSERT_COMPARISON, + booleans::LOGIC_BUG, + booleans::NONMINIMAL_BOOL, + bytecount::NAIVE_BYTECOUNT, + cargo_common_metadata::CARGO_COMMON_METADATA, + case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + casts::CAST_LOSSLESS, + casts::CAST_POSSIBLE_TRUNCATION, + casts::CAST_POSSIBLE_WRAP, + casts::CAST_PRECISION_LOSS, + casts::CAST_PTR_ALIGNMENT, + casts::CAST_REF_TO_MUT, + casts::CAST_SIGN_LOSS, + casts::CHAR_LIT_AS_U8, + casts::FN_TO_NUMERIC_CAST, + casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, + casts::PTR_AS_PTR, + casts::UNNECESSARY_CAST, + checked_conversions::CHECKED_CONVERSIONS, + cognitive_complexity::COGNITIVE_COMPLEXITY, + collapsible_if::COLLAPSIBLE_ELSE_IF, + collapsible_if::COLLAPSIBLE_IF, + collapsible_match::COLLAPSIBLE_MATCH, + comparison_chain::COMPARISON_CHAIN, + copies::BRANCHES_SHARING_CODE, + copies::IFS_SAME_COND, + copies::IF_SAME_THEN_ELSE, + copies::SAME_FUNCTIONS_IN_IF_CONDITION, + copy_iterator::COPY_ITERATOR, + create_dir::CREATE_DIR, + dbg_macro::DBG_MACRO, + default::DEFAULT_TRAIT_ACCESS, + default::FIELD_REASSIGN_WITH_DEFAULT, + default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK, + dereference::EXPLICIT_DEREF_METHODS, + derivable_impls::DERIVABLE_IMPLS, + derive::DERIVE_HASH_XOR_EQ, + derive::DERIVE_ORD_XOR_PARTIAL_ORD, + derive::EXPL_IMPL_CLONE_ON_COPY, + derive::UNSAFE_DERIVE_DESERIALIZE, + disallowed_method::DISALLOWED_METHOD, + disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, + disallowed_type::DISALLOWED_TYPE, + doc::DOC_MARKDOWN, + doc::MISSING_ERRORS_DOC, + doc::MISSING_PANICS_DOC, + doc::MISSING_SAFETY_DOC, + doc::NEEDLESS_DOCTEST_MAIN, + double_comparison::DOUBLE_COMPARISONS, + double_parens::DOUBLE_PARENS, + drop_forget_ref::DROP_COPY, + drop_forget_ref::DROP_REF, + drop_forget_ref::FORGET_COPY, + drop_forget_ref::FORGET_REF, + duration_subsec::DURATION_SUBSEC, + else_if_without_else::ELSE_IF_WITHOUT_ELSE, + empty_enum::EMPTY_ENUM, + entry::MAP_ENTRY, + enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, + enum_variants::ENUM_VARIANT_NAMES, + enum_variants::MODULE_INCEPTION, + enum_variants::MODULE_NAME_REPETITIONS, + eq_op::EQ_OP, + eq_op::OP_REF, + equatable_if_let::EQUATABLE_IF_LET, + erasing_op::ERASING_OP, + escape::BOXED_LOCAL, + eta_reduction::REDUNDANT_CLOSURE, + eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, + eval_order_dependence::DIVERGING_SUB_EXPRESSION, + eval_order_dependence::EVAL_ORDER_DEPENDENCE, + excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, + excessive_bools::STRUCT_EXCESSIVE_BOOLS, + exhaustive_items::EXHAUSTIVE_ENUMS, + exhaustive_items::EXHAUSTIVE_STRUCTS, + exit::EXIT, + explicit_write::EXPLICIT_WRITE, + fallible_impl_from::FALLIBLE_IMPL_FROM, + feature_name::NEGATIVE_FEATURE_NAMES, + feature_name::REDUNDANT_FEATURE_NAMES, + float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, + float_literal::EXCESSIVE_PRECISION, + float_literal::LOSSY_FLOAT_LITERAL, + floating_point_arithmetic::IMPRECISE_FLOPS, + floating_point_arithmetic::SUBOPTIMAL_FLOPS, + format::USELESS_FORMAT, + formatting::POSSIBLE_MISSING_COMMA, + formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, + formatting::SUSPICIOUS_ELSE_FORMATTING, + formatting::SUSPICIOUS_UNARY_OP_FORMATTING, + from_over_into::FROM_OVER_INTO, + from_str_radix_10::FROM_STR_RADIX_10, + functions::DOUBLE_MUST_USE, + functions::MUST_USE_CANDIDATE, + functions::MUST_USE_UNIT, + functions::NOT_UNSAFE_PTR_ARG_DEREF, + functions::RESULT_UNIT_ERR, + functions::TOO_MANY_ARGUMENTS, + functions::TOO_MANY_LINES, + future_not_send::FUTURE_NOT_SEND, + get_last_with_len::GET_LAST_WITH_LEN, + identity_op::IDENTITY_OP, + if_let_mutex::IF_LET_MUTEX, + if_not_else::IF_NOT_ELSE, + if_then_panic::IF_THEN_PANIC, + if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, + implicit_hasher::IMPLICIT_HASHER, + implicit_return::IMPLICIT_RETURN, + implicit_saturating_sub::IMPLICIT_SATURATING_SUB, + inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR, + indexing_slicing::INDEXING_SLICING, + indexing_slicing::OUT_OF_BOUNDS_INDEXING, + infinite_iter::INFINITE_ITER, + infinite_iter::MAYBE_INFINITE_ITER, + inherent_impl::MULTIPLE_INHERENT_IMPL, + inherent_to_string::INHERENT_TO_STRING, + inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, + inline_fn_without_body::INLINE_FN_WITHOUT_BODY, + int_plus_one::INT_PLUS_ONE, + integer_division::INTEGER_DIVISION, + invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, + items_after_statements::ITEMS_AFTER_STATEMENTS, + iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, + large_const_arrays::LARGE_CONST_ARRAYS, + large_enum_variant::LARGE_ENUM_VARIANT, + large_stack_arrays::LARGE_STACK_ARRAYS, + len_zero::COMPARISON_TO_EMPTY, + len_zero::LEN_WITHOUT_IS_EMPTY, + len_zero::LEN_ZERO, + let_if_seq::USELESS_LET_IF_SEQ, + let_underscore::LET_UNDERSCORE_DROP, + let_underscore::LET_UNDERSCORE_LOCK, + let_underscore::LET_UNDERSCORE_MUST_USE, + lifetimes::EXTRA_UNUSED_LIFETIMES, + lifetimes::NEEDLESS_LIFETIMES, + literal_representation::DECIMAL_LITERAL_REPRESENTATION, + literal_representation::INCONSISTENT_DIGIT_GROUPING, + literal_representation::LARGE_DIGIT_GROUPS, + literal_representation::MISTYPED_LITERAL_SUFFIXES, + literal_representation::UNREADABLE_LITERAL, + literal_representation::UNUSUAL_BYTE_GROUPINGS, + loops::EMPTY_LOOP, + loops::EXPLICIT_COUNTER_LOOP, + loops::EXPLICIT_INTO_ITER_LOOP, + loops::EXPLICIT_ITER_LOOP, + loops::FOR_KV_MAP, + loops::FOR_LOOPS_OVER_FALLIBLES, + loops::ITER_NEXT_LOOP, + loops::MANUAL_FLATTEN, + loops::MANUAL_MEMCPY, + loops::MUT_RANGE_BOUND, + loops::NEEDLESS_COLLECT, + loops::NEEDLESS_RANGE_LOOP, + loops::NEVER_LOOP, + loops::SAME_ITEM_PUSH, + loops::SINGLE_ELEMENT_LOOP, + loops::WHILE_IMMUTABLE_CONDITION, + loops::WHILE_LET_LOOP, + loops::WHILE_LET_ON_ITERATOR, + macro_use::MACRO_USE_IMPORTS, + main_recursion::MAIN_RECURSION, + manual_async_fn::MANUAL_ASYNC_FN, + manual_map::MANUAL_MAP, + manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, + manual_ok_or::MANUAL_OK_OR, + manual_strip::MANUAL_STRIP, + manual_unwrap_or::MANUAL_UNWRAP_OR, + map_clone::MAP_CLONE, + map_err_ignore::MAP_ERR_IGNORE, + map_unit_fn::OPTION_MAP_UNIT_FN, + map_unit_fn::RESULT_MAP_UNIT_FN, + match_on_vec_items::MATCH_ON_VEC_ITEMS, + match_result_ok::MATCH_RESULT_OK, + matches::INFALLIBLE_DESTRUCTURING_MATCH, + matches::MATCH_AS_REF, + matches::MATCH_BOOL, + matches::MATCH_LIKE_MATCHES_MACRO, + matches::MATCH_OVERLAPPING_ARM, + matches::MATCH_REF_PATS, + matches::MATCH_SAME_ARMS, + matches::MATCH_SINGLE_BINDING, + matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + matches::MATCH_WILD_ERR_ARM, + matches::REDUNDANT_PATTERN_MATCHING, + matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, + matches::SINGLE_MATCH, + matches::SINGLE_MATCH_ELSE, + matches::WILDCARD_ENUM_MATCH_ARM, + matches::WILDCARD_IN_OR_PATTERNS, + mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, + mem_forget::MEM_FORGET, + mem_replace::MEM_REPLACE_OPTION_WITH_NONE, + mem_replace::MEM_REPLACE_WITH_DEFAULT, + mem_replace::MEM_REPLACE_WITH_UNINIT, + methods::BIND_INSTEAD_OF_MAP, + methods::BYTES_NTH, + methods::CHARS_LAST_CMP, + methods::CHARS_NEXT_CMP, + methods::CLONED_INSTEAD_OF_COPIED, + methods::CLONE_DOUBLE_REF, + methods::CLONE_ON_COPY, + methods::CLONE_ON_REF_PTR, + methods::EXPECT_FUN_CALL, + methods::EXPECT_USED, + methods::EXTEND_WITH_DRAIN, + methods::FILETYPE_IS_FILE, + methods::FILTER_MAP_IDENTITY, + methods::FILTER_MAP_NEXT, + methods::FILTER_NEXT, + methods::FLAT_MAP_IDENTITY, + methods::FLAT_MAP_OPTION, + methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_UNWRAP, + methods::IMPLICIT_CLONE, + methods::INEFFICIENT_TO_STRING, + methods::INSPECT_FOR_EACH, + methods::INTO_ITER_ON_REF, + methods::ITERATOR_STEP_BY_ZERO, + methods::ITER_CLONED_COLLECT, + methods::ITER_COUNT, + methods::ITER_NEXT_SLICE, + methods::ITER_NTH, + methods::ITER_NTH_ZERO, + methods::ITER_SKIP_NEXT, + methods::MANUAL_FILTER_MAP, + methods::MANUAL_FIND_MAP, + methods::MANUAL_SATURATING_ARITHMETIC, + methods::MANUAL_SPLIT_ONCE, + methods::MANUAL_STR_REPEAT, + methods::MAP_COLLECT_RESULT_UNIT, + methods::MAP_FLATTEN, + methods::MAP_IDENTITY, + methods::MAP_UNWRAP_OR, + methods::NEW_RET_NO_SELF, + methods::OK_EXPECT, + methods::OPTION_AS_REF_DEREF, + methods::OPTION_FILTER_MAP, + methods::OPTION_MAP_OR_NONE, + methods::OR_FUN_CALL, + methods::RESULT_MAP_OR_INTO_OPTION, + methods::SEARCH_IS_SOME, + methods::SHOULD_IMPLEMENT_TRAIT, + methods::SINGLE_CHAR_ADD_STR, + methods::SINGLE_CHAR_PATTERN, + methods::SKIP_WHILE_NEXT, + methods::STRING_EXTEND_CHARS, + methods::SUSPICIOUS_MAP, + methods::SUSPICIOUS_SPLITN, + methods::UNINIT_ASSUMED_INIT, + methods::UNNECESSARY_FILTER_MAP, + methods::UNNECESSARY_FOLD, + methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNWRAP_OR_ELSE_DEFAULT, + methods::UNWRAP_USED, + methods::USELESS_ASREF, + methods::WRONG_SELF_CONVENTION, + methods::ZST_OFFSET, + minmax::MIN_MAX, + misc::CMP_NAN, + misc::CMP_OWNED, + misc::FLOAT_CMP, + misc::FLOAT_CMP_CONST, + misc::MODULO_ONE, + misc::SHORT_CIRCUIT_STATEMENT, + misc::TOPLEVEL_REF_ARG, + misc::USED_UNDERSCORE_BINDING, + misc::ZERO_PTR, + misc_early::BUILTIN_TYPE_SHADOW, + misc_early::DOUBLE_NEG, + misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, + misc_early::MIXED_CASE_HEX_LITERALS, + misc_early::REDUNDANT_PATTERN, + misc_early::UNNEEDED_FIELD_PATTERN, + misc_early::UNNEEDED_WILDCARD_PATTERN, + misc_early::UNSEPARATED_LITERAL_SUFFIX, + misc_early::ZERO_PREFIXED_LITERAL, + missing_const_for_fn::MISSING_CONST_FOR_FN, + missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, + missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES, + missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, + module_style::MOD_MODULE_FILES, + module_style::SELF_NAMED_MODULE_FILES, + modulo_arithmetic::MODULO_ARITHMETIC, + multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, + mut_key::MUTABLE_KEY_TYPE, + mut_mut::MUT_MUT, + mut_mutex_lock::MUT_MUTEX_LOCK, + mut_reference::UNNECESSARY_MUT_PASSED, + mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, + mutex_atomic::MUTEX_ATOMIC, + mutex_atomic::MUTEX_INTEGER, + needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, + needless_bitwise_bool::NEEDLESS_BITWISE_BOOL, + needless_bool::BOOL_COMPARISON, + needless_bool::NEEDLESS_BOOL, + needless_borrow::NEEDLESS_BORROW, + needless_borrow::REF_BINDING_TO_REFERENCE, + needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, + needless_continue::NEEDLESS_CONTINUE, + needless_for_each::NEEDLESS_FOR_EACH, + needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF, + needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, + needless_question_mark::NEEDLESS_QUESTION_MARK, + needless_update::NEEDLESS_UPDATE, + neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, + neg_multiply::NEG_MULTIPLY, + new_without_default::NEW_WITHOUT_DEFAULT, + no_effect::NO_EFFECT, + no_effect::UNNECESSARY_OPERATION, + non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, + non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, + non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, + non_expressive_names::MANY_SINGLE_CHAR_NAMES, + non_expressive_names::SIMILAR_NAMES, + non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS, + non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY, + nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, + open_options::NONSENSICAL_OPEN_OPTIONS, + option_env_unwrap::OPTION_ENV_UNWRAP, + option_if_let_else::OPTION_IF_LET_ELSE, + overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, + panic_in_result_fn::PANIC_IN_RESULT_FN, + panic_unimplemented::PANIC, + panic_unimplemented::TODO, + panic_unimplemented::UNIMPLEMENTED, + panic_unimplemented::UNREACHABLE, + partialeq_ne_impl::PARTIALEQ_NE_IMPL, + pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, + pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, + path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, + pattern_type_mismatch::PATTERN_TYPE_MISMATCH, + precedence::PRECEDENCE, + ptr::CMP_NULL, + ptr::INVALID_NULL_PTR_USAGE, + ptr::MUT_FROM_REF, + ptr::PTR_ARG, + ptr_eq::PTR_EQ, + ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, + question_mark::QUESTION_MARK, + ranges::MANUAL_RANGE_CONTAINS, + ranges::RANGE_MINUS_ONE, + ranges::RANGE_PLUS_ONE, + ranges::RANGE_ZIP_WITH_LEN, + ranges::REVERSED_EMPTY_RANGES, + redundant_clone::REDUNDANT_CLONE, + redundant_closure_call::REDUNDANT_CLOSURE_CALL, + redundant_else::REDUNDANT_ELSE, + redundant_field_names::REDUNDANT_FIELD_NAMES, + redundant_pub_crate::REDUNDANT_PUB_CRATE, + redundant_slicing::REDUNDANT_SLICING, + redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, + ref_option_ref::REF_OPTION_REF, + reference::DEREF_ADDROF, + reference::REF_IN_DEREF, + regex::INVALID_REGEX, + regex::TRIVIAL_REGEX, + repeat_once::REPEAT_ONCE, + returns::LET_AND_RETURN, + returns::NEEDLESS_RETURN, + same_name_method::SAME_NAME_METHOD, + self_assignment::SELF_ASSIGNMENT, + self_named_constructors::SELF_NAMED_CONSTRUCTORS, + semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, + serde_api::SERDE_API_MISUSE, + shadow::SHADOW_REUSE, + shadow::SHADOW_SAME, + shadow::SHADOW_UNRELATED, + single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, + size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, + slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, + stable_sort_primitive::STABLE_SORT_PRIMITIVE, + strings::STRING_ADD, + strings::STRING_ADD_ASSIGN, + strings::STRING_FROM_UTF8_AS_BYTES, + strings::STRING_LIT_AS_BYTES, + strings::STRING_TO_STRING, + strings::STR_TO_STRING, + strlen_on_c_strings::STRLEN_ON_C_STRINGS, + suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, + suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, + suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, + swap::ALMOST_SWAPPED, + swap::MANUAL_SWAP, + tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, + temporary_assignment::TEMPORARY_ASSIGNMENT, + to_digit_is_some::TO_DIGIT_IS_SOME, + to_string_in_display::TO_STRING_IN_DISPLAY, + trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, + trait_bounds::TYPE_REPETITION_IN_BOUNDS, + transmute::CROSSPOINTER_TRANSMUTE, + transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, + transmute::TRANSMUTE_BYTES_TO_STR, + transmute::TRANSMUTE_FLOAT_TO_INT, + transmute::TRANSMUTE_INT_TO_BOOL, + transmute::TRANSMUTE_INT_TO_CHAR, + transmute::TRANSMUTE_INT_TO_FLOAT, + transmute::TRANSMUTE_PTR_TO_PTR, + transmute::TRANSMUTE_PTR_TO_REF, + transmute::UNSOUND_COLLECTION_TRANSMUTE, + transmute::USELESS_TRANSMUTE, + transmute::WRONG_TRANSMUTE, + transmuting_null::TRANSMUTING_NULL, + try_err::TRY_ERR, + types::BORROWED_BOX, + types::BOX_COLLECTION, + types::LINKEDLIST, + types::OPTION_OPTION, + types::RC_BUFFER, + types::RC_MUTEX, + types::REDUNDANT_ALLOCATION, + types::TYPE_COMPLEXITY, + types::VEC_BOX, + undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, + unicode::INVISIBLE_CHARACTERS, + unicode::NON_ASCII_LITERAL, + unicode::UNICODE_NOT_NFC, + unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, + unit_types::LET_UNIT_VALUE, + unit_types::UNIT_ARG, + unit_types::UNIT_CMP, + unnamed_address::FN_ADDRESS_COMPARISONS, + unnamed_address::VTABLE_ADDRESS_COMPARISONS, + unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, + unnecessary_sort_by::UNNECESSARY_SORT_BY, + unnecessary_wraps::UNNECESSARY_WRAPS, + unnested_or_patterns::UNNESTED_OR_PATTERNS, + unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + unused_async::UNUSED_ASYNC, + unused_io_amount::UNUSED_IO_AMOUNT, + unused_self::UNUSED_SELF, + unused_unit::UNUSED_UNIT, + unwrap::PANICKING_UNWRAP, + unwrap::UNNECESSARY_UNWRAP, + unwrap_in_result::UNWRAP_IN_RESULT, + upper_case_acronyms::UPPER_CASE_ACRONYMS, + use_self::USE_SELF, + useless_conversion::USELESS_CONVERSION, + vec::USELESS_VEC, + vec_init_then_push::VEC_INIT_THEN_PUSH, + vec_resize_to_zero::VEC_RESIZE_TO_ZERO, + verbose_file_reads::VERBOSE_FILE_READS, + wildcard_dependencies::WILDCARD_DEPENDENCIES, + wildcard_imports::ENUM_GLOB_USE, + wildcard_imports::WILDCARD_IMPORTS, + write::PRINTLN_EMPTY_STRING, + write::PRINT_LITERAL, + write::PRINT_STDERR, + write::PRINT_STDOUT, + write::PRINT_WITH_NEWLINE, + write::USE_DEBUG, + write::WRITELN_EMPTY_STRING, + write::WRITE_LITERAL, + write::WRITE_WITH_NEWLINE, + zero_div_zero::ZERO_DIVIDED_BY_ZERO, + zero_sized_map_values::ZERO_SIZED_MAP_VALUES, +]) diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs new file mode 100644 index 00000000000..96e0b421094 --- /dev/null +++ b/clippy_lints/src/lib.register_nursery.rs @@ -0,0 +1,30 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ + LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR), + LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY), + LintId::of(copies::BRANCHES_SHARING_CODE), + LintId::of(disallowed_method::DISALLOWED_METHOD), + LintId::of(disallowed_type::DISALLOWED_TYPE), + LintId::of(equatable_if_let::EQUATABLE_IF_LET), + LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), + LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS), + LintId::of(future_not_send::FUTURE_NOT_SEND), + LintId::of(let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), + LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), + LintId::of(mutex_atomic::MUTEX_INTEGER), + LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), + LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), + LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), + LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), + LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), + LintId::of(regex::TRIVIAL_REGEX), + LintId::of(strings::STRING_LIT_AS_BYTES), + LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), + LintId::of(transmute::USELESS_TRANSMUTE), + LintId::of(use_self::USE_SELF), +]) diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs new file mode 100644 index 00000000000..6533b94e82b --- /dev/null +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -0,0 +1,100 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ + LintId::of(attrs::INLINE_ALWAYS), + LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), + LintId::of(bit_mask::VERBOSE_BIT_MASK), + LintId::of(bytecount::NAIVE_BYTECOUNT), + LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), + LintId::of(casts::CAST_LOSSLESS), + LintId::of(casts::CAST_POSSIBLE_TRUNCATION), + LintId::of(casts::CAST_POSSIBLE_WRAP), + LintId::of(casts::CAST_PRECISION_LOSS), + LintId::of(casts::CAST_PTR_ALIGNMENT), + LintId::of(casts::CAST_SIGN_LOSS), + LintId::of(casts::PTR_AS_PTR), + LintId::of(checked_conversions::CHECKED_CONVERSIONS), + LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION), + LintId::of(copy_iterator::COPY_ITERATOR), + LintId::of(default::DEFAULT_TRAIT_ACCESS), + LintId::of(dereference::EXPLICIT_DEREF_METHODS), + LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY), + LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE), + LintId::of(doc::DOC_MARKDOWN), + LintId::of(doc::MISSING_ERRORS_DOC), + LintId::of(doc::MISSING_PANICS_DOC), + LintId::of(empty_enum::EMPTY_ENUM), + LintId::of(enum_variants::MODULE_NAME_REPETITIONS), + LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), + LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), + LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), + LintId::of(functions::MUST_USE_CANDIDATE), + LintId::of(functions::TOO_MANY_LINES), + LintId::of(if_not_else::IF_NOT_ELSE), + LintId::of(implicit_hasher::IMPLICIT_HASHER), + LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), + LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), + LintId::of(infinite_iter::MAYBE_INFINITE_ITER), + LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), + LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), + LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), + LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), + LintId::of(let_underscore::LET_UNDERSCORE_DROP), + LintId::of(literal_representation::LARGE_DIGIT_GROUPS), + LintId::of(literal_representation::UNREADABLE_LITERAL), + LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), + LintId::of(loops::EXPLICIT_ITER_LOOP), + LintId::of(macro_use::MACRO_USE_IMPORTS), + LintId::of(manual_ok_or::MANUAL_OK_OR), + LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), + LintId::of(matches::MATCH_BOOL), + LintId::of(matches::MATCH_SAME_ARMS), + LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), + LintId::of(matches::MATCH_WILD_ERR_ARM), + LintId::of(matches::SINGLE_MATCH_ELSE), + LintId::of(methods::CLONED_INSTEAD_OF_COPIED), + LintId::of(methods::FILTER_MAP_NEXT), + LintId::of(methods::FLAT_MAP_OPTION), + LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), + LintId::of(methods::IMPLICIT_CLONE), + LintId::of(methods::INEFFICIENT_TO_STRING), + LintId::of(methods::MAP_FLATTEN), + LintId::of(methods::MAP_UNWRAP_OR), + LintId::of(misc::FLOAT_CMP), + LintId::of(misc::USED_UNDERSCORE_BINDING), + LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), + LintId::of(mut_mut::MUT_MUT), + LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), + LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE), + LintId::of(needless_continue::NEEDLESS_CONTINUE), + LintId::of(needless_for_each::NEEDLESS_FOR_EACH), + LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), + LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), + LintId::of(non_expressive_names::SIMILAR_NAMES), + LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), + LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), + LintId::of(ranges::RANGE_MINUS_ONE), + LintId::of(ranges::RANGE_PLUS_ONE), + LintId::of(redundant_else::REDUNDANT_ELSE), + LintId::of(ref_option_ref::REF_OPTION_REF), + LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), + LintId::of(strings::STRING_ADD_ASSIGN), + LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), + LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS), + LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), + LintId::of(types::LINKEDLIST), + LintId::of(types::OPTION_OPTION), + LintId::of(unicode::NON_ASCII_LITERAL), + LintId::of(unicode::UNICODE_NOT_NFC), + LintId::of(unit_types::LET_UNIT_VALUE), + LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), + LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS), + LintId::of(unused_async::UNUSED_ASYNC), + LintId::of(unused_self::UNUSED_SELF), + LintId::of(wildcard_imports::ENUM_GLOB_USE), + LintId::of(wildcard_imports::WILDCARD_IMPORTS), + LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES), +]) diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs new file mode 100644 index 00000000000..5432345760b --- /dev/null +++ b/clippy_lints/src/lib.register_perf.rs @@ -0,0 +1,27 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ + LintId::of(entry::MAP_ENTRY), + LintId::of(escape::BOXED_LOCAL), + LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), + LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(loops::MANUAL_MEMCPY), + LintId::of(loops::NEEDLESS_COLLECT), + LintId::of(methods::EXPECT_FUN_CALL), + LintId::of(methods::EXTEND_WITH_DRAIN), + LintId::of(methods::ITER_NTH), + LintId::of(methods::MANUAL_STR_REPEAT), + LintId::of(methods::OR_FUN_CALL), + LintId::of(methods::SINGLE_CHAR_PATTERN), + LintId::of(misc::CMP_OWNED), + LintId::of(mutex_atomic::MUTEX_ATOMIC), + LintId::of(redundant_clone::REDUNDANT_CLONE), + LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(types::BOX_COLLECTION), + LintId::of(types::REDUNDANT_ALLOCATION), + LintId::of(vec::USELESS_VEC), + LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), +]) diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs new file mode 100644 index 00000000000..4463dea5fcb --- /dev/null +++ b/clippy_lints/src/lib.register_restriction.rs @@ -0,0 +1,65 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ + LintId::of(arithmetic::FLOAT_ARITHMETIC), + LintId::of(arithmetic::INTEGER_ARITHMETIC), + LintId::of(as_conversions::AS_CONVERSIONS), + LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), + LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), + LintId::of(create_dir::CREATE_DIR), + LintId::of(dbg_macro::DBG_MACRO), + LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK), + LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS), + LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE), + LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS), + LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS), + LintId::of(exit::EXIT), + LintId::of(float_literal::LOSSY_FLOAT_LITERAL), + LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE), + LintId::of(implicit_return::IMPLICIT_RETURN), + LintId::of(indexing_slicing::INDEXING_SLICING), + LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL), + LintId::of(integer_division::INTEGER_DIVISION), + LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), + LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), + LintId::of(map_err_ignore::MAP_ERR_IGNORE), + LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), + LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), + LintId::of(mem_forget::MEM_FORGET), + LintId::of(methods::CLONE_ON_REF_PTR), + LintId::of(methods::EXPECT_USED), + LintId::of(methods::FILETYPE_IS_FILE), + LintId::of(methods::GET_UNWRAP), + LintId::of(methods::UNWRAP_USED), + LintId::of(misc::FLOAT_CMP_CONST), + LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), + LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), + LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES), + LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), + LintId::of(module_style::MOD_MODULE_FILES), + LintId::of(module_style::SELF_NAMED_MODULE_FILES), + LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), + LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN), + LintId::of(panic_unimplemented::PANIC), + LintId::of(panic_unimplemented::TODO), + LintId::of(panic_unimplemented::UNIMPLEMENTED), + LintId::of(panic_unimplemented::UNREACHABLE), + LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH), + LintId::of(same_name_method::SAME_NAME_METHOD), + LintId::of(shadow::SHADOW_REUSE), + LintId::of(shadow::SHADOW_SAME), + LintId::of(shadow::SHADOW_UNRELATED), + LintId::of(strings::STRING_ADD), + LintId::of(strings::STRING_TO_STRING), + LintId::of(strings::STR_TO_STRING), + LintId::of(types::RC_BUFFER), + LintId::of(types::RC_MUTEX), + LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), + LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), + LintId::of(verbose_file_reads::VERBOSE_FILE_READS), + LintId::of(write::PRINT_STDERR), + LintId::of(write::PRINT_STDOUT), + LintId::of(write::USE_DEBUG), +]) diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs new file mode 100644 index 00000000000..a39c111c574 --- /dev/null +++ b/clippy_lints/src/lib.register_style.rs @@ -0,0 +1,114 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::style", Some("clippy_style"), vec![ + LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), + LintId::of(assign_ops::ASSIGN_OP_PATTERN), + LintId::of(blacklisted_name::BLACKLISTED_NAME), + LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), + LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), + LintId::of(casts::FN_TO_NUMERIC_CAST), + LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), + LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), + LintId::of(collapsible_if::COLLAPSIBLE_IF), + LintId::of(collapsible_match::COLLAPSIBLE_MATCH), + LintId::of(comparison_chain::COMPARISON_CHAIN), + LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), + LintId::of(doc::MISSING_SAFETY_DOC), + LintId::of(doc::NEEDLESS_DOCTEST_MAIN), + LintId::of(enum_variants::ENUM_VARIANT_NAMES), + LintId::of(enum_variants::MODULE_INCEPTION), + LintId::of(eq_op::OP_REF), + LintId::of(eta_reduction::REDUNDANT_CLOSURE), + LintId::of(float_literal::EXCESSIVE_PRECISION), + LintId::of(from_over_into::FROM_OVER_INTO), + LintId::of(from_str_radix_10::FROM_STR_RADIX_10), + LintId::of(functions::DOUBLE_MUST_USE), + LintId::of(functions::MUST_USE_UNIT), + LintId::of(functions::RESULT_UNIT_ERR), + LintId::of(if_then_panic::IF_THEN_PANIC), + LintId::of(inherent_to_string::INHERENT_TO_STRING), + LintId::of(len_zero::COMPARISON_TO_EMPTY), + LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), + LintId::of(len_zero::LEN_ZERO), + LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), + LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), + LintId::of(loops::FOR_KV_MAP), + LintId::of(loops::NEEDLESS_RANGE_LOOP), + LintId::of(loops::SAME_ITEM_PUSH), + LintId::of(loops::WHILE_LET_ON_ITERATOR), + LintId::of(main_recursion::MAIN_RECURSION), + LintId::of(manual_async_fn::MANUAL_ASYNC_FN), + LintId::of(manual_map::MANUAL_MAP), + LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), + LintId::of(map_clone::MAP_CLONE), + LintId::of(match_result_ok::MATCH_RESULT_OK), + LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), + LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), + LintId::of(matches::MATCH_OVERLAPPING_ARM), + LintId::of(matches::MATCH_REF_PATS), + LintId::of(matches::REDUNDANT_PATTERN_MATCHING), + LintId::of(matches::SINGLE_MATCH), + LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), + LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(methods::BYTES_NTH), + LintId::of(methods::CHARS_LAST_CMP), + LintId::of(methods::CHARS_NEXT_CMP), + LintId::of(methods::INTO_ITER_ON_REF), + LintId::of(methods::ITER_CLONED_COLLECT), + LintId::of(methods::ITER_NEXT_SLICE), + LintId::of(methods::ITER_NTH_ZERO), + LintId::of(methods::ITER_SKIP_NEXT), + LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::OK_EXPECT), + LintId::of(methods::OPTION_MAP_OR_NONE), + LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), + LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(methods::SINGLE_CHAR_ADD_STR), + LintId::of(methods::STRING_EXTEND_CHARS), + LintId::of(methods::UNNECESSARY_FOLD), + LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), + LintId::of(methods::WRONG_SELF_CONVENTION), + LintId::of(misc::TOPLEVEL_REF_ARG), + LintId::of(misc::ZERO_PTR), + LintId::of(misc_early::BUILTIN_TYPE_SHADOW), + LintId::of(misc_early::DOUBLE_NEG), + LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), + LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), + LintId::of(misc_early::REDUNDANT_PATTERN), + LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), + LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(needless_borrow::NEEDLESS_BORROW), + LintId::of(neg_multiply::NEG_MULTIPLY), + LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), + LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), + LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), + LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), + LintId::of(ptr::CMP_NULL), + LintId::of(ptr::PTR_ARG), + LintId::of(ptr_eq::PTR_EQ), + LintId::of(question_mark::QUESTION_MARK), + LintId::of(ranges::MANUAL_RANGE_CONTAINS), + LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), + LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), + LintId::of(returns::LET_AND_RETURN), + LintId::of(returns::NEEDLESS_RETURN), + LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), + LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), + LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), + LintId::of(try_err::TRY_ERR), + LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(unused_unit::UNUSED_UNIT), + LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), + LintId::of(write::PRINTLN_EMPTY_STRING), + LintId::of(write::PRINT_LITERAL), + LintId::of(write::PRINT_WITH_NEWLINE), + LintId::of(write::WRITELN_EMPTY_STRING), + LintId::of(write::WRITE_LITERAL), + LintId::of(write::WRITE_WITH_NEWLINE), +]) diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs new file mode 100644 index 00000000000..8859787fbc8 --- /dev/null +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -0,0 +1,20 @@ +// This file was generated by `cargo dev update_lints`. +// Use that command to update this file and do not edit by hand. +// Manual edits will be overwritten. + +store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![ + LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), + LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), + LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), + LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), + LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), + LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), + LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), + LintId::of(loops::EMPTY_LOOP), + LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), + LintId::of(loops::MUT_RANGE_BOUND), + LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), + LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), +]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 89724917482..9fc6a9e0ccc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -203,6 +203,7 @@ macro_rules! declare_clippy_lint { mod enum_clike; mod enum_variants; mod eq_op; +mod equatable_if_let; mod erasing_op; mod escape; mod eta_reduction; @@ -303,6 +304,7 @@ macro_rules! declare_clippy_lint { mod non_copy_const; mod non_expressive_names; mod non_octal_unix_permissions; +mod non_send_fields_in_send_ty; mod nonstandard_macro_braces; mod open_options; mod option_env_unwrap; @@ -438,1401 +440,23 @@ pub fn read_conf(sess: &Session) -> Conf { pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { register_removed_non_tool_lints(store); - // begin deprecated lints, do not remove this comment, it’s used in `update_lints` - store.register_removed( - "clippy::should_assert_eq", - "`assert!()` will be more flexible with RFC 2011", - ); - store.register_removed( - "clippy::extend_from_slice", - "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice", - ); - store.register_removed( - "clippy::range_step_by_zero", - "`iterator.step_by(0)` panics nowadays", - ); - store.register_removed( - "clippy::unstable_as_slice", - "`Vec::as_slice` has been stabilized in 1.7", - ); - store.register_removed( - "clippy::unstable_as_mut_slice", - "`Vec::as_mut_slice` has been stabilized in 1.7", - ); - store.register_removed( - "clippy::misaligned_transmute", - "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr", - ); - store.register_removed( - "clippy::assign_ops", - "using compound assignment operators (e.g., `+=`) is harmless", - ); - store.register_removed( - "clippy::if_let_redundant_pattern_matching", - "this lint has been changed to redundant_pattern_matching", - ); - store.register_removed( - "clippy::unsafe_vector_initialization", - "the replacement suggested by this lint had substantially different behavior", - ); - store.register_removed( - "clippy::unused_collect", - "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint", - ); - store.register_removed( - "clippy::replace_consts", - "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants", - ); - store.register_removed( - "clippy::regex_macro", - "the regex! macro has been removed from the regex crate in 2018", - ); - store.register_removed( - "clippy::find_map", - "this lint has been replaced by `manual_find_map`, a more specific lint", - ); - store.register_removed( - "clippy::filter_map", - "this lint has been replaced by `manual_filter_map`, a more specific lint", - ); - store.register_removed( - "clippy::pub_enum_variant_names", - "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items", - ); - store.register_removed( - "clippy::wrong_pub_self_convention", - "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items", - ); - // end deprecated lints, do not remove this comment, it’s used in `update_lints` + include!("lib.deprecated.rs"); - // begin register lints, do not remove this comment, it’s used in `update_lints` - store.register_lints(&[ - #[cfg(feature = "internal-lints")] - utils::internal_lints::CLIPPY_LINTS_INTERNAL, - #[cfg(feature = "internal-lints")] - utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::COMPILER_LINT_FUNCTIONS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::DEFAULT_LINT, - #[cfg(feature = "internal-lints")] - utils::internal_lints::IF_CHAIN_STYLE, - #[cfg(feature = "internal-lints")] - utils::internal_lints::INTERNING_DEFINED_SYMBOL, - #[cfg(feature = "internal-lints")] - utils::internal_lints::INVALID_PATHS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::LINT_WITHOUT_LINT_PASS, - #[cfg(feature = "internal-lints")] - utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM, - #[cfg(feature = "internal-lints")] - utils::internal_lints::OUTER_EXPN_EXPN_DATA, - #[cfg(feature = "internal-lints")] - utils::internal_lints::PRODUCE_ICE, - #[cfg(feature = "internal-lints")] - utils::internal_lints::UNNECESSARY_SYMBOL_STR, - absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, - approx_const::APPROX_CONSTANT, - arithmetic::FLOAT_ARITHMETIC, - arithmetic::INTEGER_ARITHMETIC, - as_conversions::AS_CONVERSIONS, - asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, - asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, - assertions_on_constants::ASSERTIONS_ON_CONSTANTS, - assign_ops::ASSIGN_OP_PATTERN, - assign_ops::MISREFACTORED_ASSIGN_OP, - async_yields_async::ASYNC_YIELDS_ASYNC, - attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, - attrs::DEPRECATED_CFG_ATTR, - attrs::DEPRECATED_SEMVER, - attrs::EMPTY_LINE_AFTER_OUTER_ATTR, - attrs::INLINE_ALWAYS, - attrs::MISMATCHED_TARGET_OS, - attrs::USELESS_ATTRIBUTE, - await_holding_invalid::AWAIT_HOLDING_LOCK, - await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, - bit_mask::BAD_BIT_MASK, - bit_mask::INEFFECTIVE_BIT_MASK, - bit_mask::VERBOSE_BIT_MASK, - blacklisted_name::BLACKLISTED_NAME, - blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, - bool_assert_comparison::BOOL_ASSERT_COMPARISON, - booleans::LOGIC_BUG, - booleans::NONMINIMAL_BOOL, - bytecount::NAIVE_BYTECOUNT, - cargo_common_metadata::CARGO_COMMON_METADATA, - case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - casts::CAST_LOSSLESS, - casts::CAST_POSSIBLE_TRUNCATION, - casts::CAST_POSSIBLE_WRAP, - casts::CAST_PRECISION_LOSS, - casts::CAST_PTR_ALIGNMENT, - casts::CAST_REF_TO_MUT, - casts::CAST_SIGN_LOSS, - casts::CHAR_LIT_AS_U8, - casts::FN_TO_NUMERIC_CAST, - casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - casts::PTR_AS_PTR, - casts::UNNECESSARY_CAST, - checked_conversions::CHECKED_CONVERSIONS, - cognitive_complexity::COGNITIVE_COMPLEXITY, - collapsible_if::COLLAPSIBLE_ELSE_IF, - collapsible_if::COLLAPSIBLE_IF, - collapsible_match::COLLAPSIBLE_MATCH, - comparison_chain::COMPARISON_CHAIN, - copies::BRANCHES_SHARING_CODE, - copies::IFS_SAME_COND, - copies::IF_SAME_THEN_ELSE, - copies::SAME_FUNCTIONS_IN_IF_CONDITION, - copy_iterator::COPY_ITERATOR, - create_dir::CREATE_DIR, - dbg_macro::DBG_MACRO, - default::DEFAULT_TRAIT_ACCESS, - default::FIELD_REASSIGN_WITH_DEFAULT, - default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK, - dereference::EXPLICIT_DEREF_METHODS, - derivable_impls::DERIVABLE_IMPLS, - derive::DERIVE_HASH_XOR_EQ, - derive::DERIVE_ORD_XOR_PARTIAL_ORD, - derive::EXPL_IMPL_CLONE_ON_COPY, - derive::UNSAFE_DERIVE_DESERIALIZE, - disallowed_method::DISALLOWED_METHOD, - disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, - disallowed_type::DISALLOWED_TYPE, - doc::DOC_MARKDOWN, - doc::MISSING_ERRORS_DOC, - doc::MISSING_PANICS_DOC, - doc::MISSING_SAFETY_DOC, - doc::NEEDLESS_DOCTEST_MAIN, - double_comparison::DOUBLE_COMPARISONS, - double_parens::DOUBLE_PARENS, - drop_forget_ref::DROP_COPY, - drop_forget_ref::DROP_REF, - drop_forget_ref::FORGET_COPY, - drop_forget_ref::FORGET_REF, - duration_subsec::DURATION_SUBSEC, - else_if_without_else::ELSE_IF_WITHOUT_ELSE, - empty_enum::EMPTY_ENUM, - entry::MAP_ENTRY, - enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT, - enum_variants::ENUM_VARIANT_NAMES, - enum_variants::MODULE_INCEPTION, - enum_variants::MODULE_NAME_REPETITIONS, - eq_op::EQ_OP, - eq_op::OP_REF, - erasing_op::ERASING_OP, - escape::BOXED_LOCAL, - eta_reduction::REDUNDANT_CLOSURE, - eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, - eval_order_dependence::DIVERGING_SUB_EXPRESSION, - eval_order_dependence::EVAL_ORDER_DEPENDENCE, - excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, - excessive_bools::STRUCT_EXCESSIVE_BOOLS, - exhaustive_items::EXHAUSTIVE_ENUMS, - exhaustive_items::EXHAUSTIVE_STRUCTS, - exit::EXIT, - explicit_write::EXPLICIT_WRITE, - fallible_impl_from::FALLIBLE_IMPL_FROM, - feature_name::NEGATIVE_FEATURE_NAMES, - feature_name::REDUNDANT_FEATURE_NAMES, - float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS, - float_literal::EXCESSIVE_PRECISION, - float_literal::LOSSY_FLOAT_LITERAL, - floating_point_arithmetic::IMPRECISE_FLOPS, - floating_point_arithmetic::SUBOPTIMAL_FLOPS, - format::USELESS_FORMAT, - formatting::POSSIBLE_MISSING_COMMA, - formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, - formatting::SUSPICIOUS_ELSE_FORMATTING, - formatting::SUSPICIOUS_UNARY_OP_FORMATTING, - from_over_into::FROM_OVER_INTO, - from_str_radix_10::FROM_STR_RADIX_10, - functions::DOUBLE_MUST_USE, - functions::MUST_USE_CANDIDATE, - functions::MUST_USE_UNIT, - functions::NOT_UNSAFE_PTR_ARG_DEREF, - functions::RESULT_UNIT_ERR, - functions::TOO_MANY_ARGUMENTS, - functions::TOO_MANY_LINES, - future_not_send::FUTURE_NOT_SEND, - get_last_with_len::GET_LAST_WITH_LEN, - identity_op::IDENTITY_OP, - if_let_mutex::IF_LET_MUTEX, - if_not_else::IF_NOT_ELSE, - if_then_panic::IF_THEN_PANIC, - if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, - implicit_hasher::IMPLICIT_HASHER, - implicit_return::IMPLICIT_RETURN, - implicit_saturating_sub::IMPLICIT_SATURATING_SUB, - inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR, - indexing_slicing::INDEXING_SLICING, - indexing_slicing::OUT_OF_BOUNDS_INDEXING, - infinite_iter::INFINITE_ITER, - infinite_iter::MAYBE_INFINITE_ITER, - inherent_impl::MULTIPLE_INHERENT_IMPL, - inherent_to_string::INHERENT_TO_STRING, - inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY, - inline_fn_without_body::INLINE_FN_WITHOUT_BODY, - int_plus_one::INT_PLUS_ONE, - integer_division::INTEGER_DIVISION, - invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS, - items_after_statements::ITEMS_AFTER_STATEMENTS, - iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, - large_const_arrays::LARGE_CONST_ARRAYS, - large_enum_variant::LARGE_ENUM_VARIANT, - large_stack_arrays::LARGE_STACK_ARRAYS, - len_zero::COMPARISON_TO_EMPTY, - len_zero::LEN_WITHOUT_IS_EMPTY, - len_zero::LEN_ZERO, - let_if_seq::USELESS_LET_IF_SEQ, - let_underscore::LET_UNDERSCORE_DROP, - let_underscore::LET_UNDERSCORE_LOCK, - let_underscore::LET_UNDERSCORE_MUST_USE, - lifetimes::EXTRA_UNUSED_LIFETIMES, - lifetimes::NEEDLESS_LIFETIMES, - literal_representation::DECIMAL_LITERAL_REPRESENTATION, - literal_representation::INCONSISTENT_DIGIT_GROUPING, - literal_representation::LARGE_DIGIT_GROUPS, - literal_representation::MISTYPED_LITERAL_SUFFIXES, - literal_representation::UNREADABLE_LITERAL, - literal_representation::UNUSUAL_BYTE_GROUPINGS, - loops::EMPTY_LOOP, - loops::EXPLICIT_COUNTER_LOOP, - loops::EXPLICIT_INTO_ITER_LOOP, - loops::EXPLICIT_ITER_LOOP, - loops::FOR_KV_MAP, - loops::FOR_LOOPS_OVER_FALLIBLES, - loops::ITER_NEXT_LOOP, - loops::MANUAL_FLATTEN, - loops::MANUAL_MEMCPY, - loops::MUT_RANGE_BOUND, - loops::NEEDLESS_COLLECT, - loops::NEEDLESS_RANGE_LOOP, - loops::NEVER_LOOP, - loops::SAME_ITEM_PUSH, - loops::SINGLE_ELEMENT_LOOP, - loops::WHILE_IMMUTABLE_CONDITION, - loops::WHILE_LET_LOOP, - loops::WHILE_LET_ON_ITERATOR, - macro_use::MACRO_USE_IMPORTS, - main_recursion::MAIN_RECURSION, - manual_async_fn::MANUAL_ASYNC_FN, - manual_map::MANUAL_MAP, - manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, - manual_ok_or::MANUAL_OK_OR, - manual_strip::MANUAL_STRIP, - manual_unwrap_or::MANUAL_UNWRAP_OR, - map_clone::MAP_CLONE, - map_err_ignore::MAP_ERR_IGNORE, - map_unit_fn::OPTION_MAP_UNIT_FN, - map_unit_fn::RESULT_MAP_UNIT_FN, - match_on_vec_items::MATCH_ON_VEC_ITEMS, - match_result_ok::MATCH_RESULT_OK, - matches::INFALLIBLE_DESTRUCTURING_MATCH, - matches::MATCH_AS_REF, - matches::MATCH_BOOL, - matches::MATCH_LIKE_MATCHES_MACRO, - matches::MATCH_OVERLAPPING_ARM, - matches::MATCH_REF_PATS, - matches::MATCH_SAME_ARMS, - matches::MATCH_SINGLE_BINDING, - matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, - matches::MATCH_WILD_ERR_ARM, - matches::REDUNDANT_PATTERN_MATCHING, - matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, - matches::SINGLE_MATCH, - matches::SINGLE_MATCH_ELSE, - matches::WILDCARD_ENUM_MATCH_ARM, - matches::WILDCARD_IN_OR_PATTERNS, - mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, - mem_forget::MEM_FORGET, - mem_replace::MEM_REPLACE_OPTION_WITH_NONE, - mem_replace::MEM_REPLACE_WITH_DEFAULT, - mem_replace::MEM_REPLACE_WITH_UNINIT, - methods::BIND_INSTEAD_OF_MAP, - methods::BYTES_NTH, - methods::CHARS_LAST_CMP, - methods::CHARS_NEXT_CMP, - methods::CLONED_INSTEAD_OF_COPIED, - methods::CLONE_DOUBLE_REF, - methods::CLONE_ON_COPY, - methods::CLONE_ON_REF_PTR, - methods::EXPECT_FUN_CALL, - methods::EXPECT_USED, - methods::EXTEND_WITH_DRAIN, - methods::FILETYPE_IS_FILE, - methods::FILTER_MAP_IDENTITY, - methods::FILTER_MAP_NEXT, - methods::FILTER_NEXT, - methods::FLAT_MAP_IDENTITY, - methods::FLAT_MAP_OPTION, - methods::FROM_ITER_INSTEAD_OF_COLLECT, - methods::GET_UNWRAP, - methods::IMPLICIT_CLONE, - methods::INEFFICIENT_TO_STRING, - methods::INSPECT_FOR_EACH, - methods::INTO_ITER_ON_REF, - methods::ITERATOR_STEP_BY_ZERO, - methods::ITER_CLONED_COLLECT, - methods::ITER_COUNT, - methods::ITER_NEXT_SLICE, - methods::ITER_NTH, - methods::ITER_NTH_ZERO, - methods::ITER_SKIP_NEXT, - methods::MANUAL_FILTER_MAP, - methods::MANUAL_FIND_MAP, - methods::MANUAL_SATURATING_ARITHMETIC, - methods::MANUAL_SPLIT_ONCE, - methods::MANUAL_STR_REPEAT, - methods::MAP_COLLECT_RESULT_UNIT, - methods::MAP_FLATTEN, - methods::MAP_IDENTITY, - methods::MAP_UNWRAP_OR, - methods::NEW_RET_NO_SELF, - methods::OK_EXPECT, - methods::OPTION_AS_REF_DEREF, - methods::OPTION_FILTER_MAP, - methods::OPTION_MAP_OR_NONE, - methods::OR_FUN_CALL, - methods::RESULT_MAP_OR_INTO_OPTION, - methods::SEARCH_IS_SOME, - methods::SHOULD_IMPLEMENT_TRAIT, - methods::SINGLE_CHAR_ADD_STR, - methods::SINGLE_CHAR_PATTERN, - methods::SKIP_WHILE_NEXT, - methods::STRING_EXTEND_CHARS, - methods::SUSPICIOUS_MAP, - methods::SUSPICIOUS_SPLITN, - methods::UNINIT_ASSUMED_INIT, - methods::UNNECESSARY_FILTER_MAP, - methods::UNNECESSARY_FOLD, - methods::UNNECESSARY_LAZY_EVALUATIONS, - methods::UNWRAP_OR_ELSE_DEFAULT, - methods::UNWRAP_USED, - methods::USELESS_ASREF, - methods::WRONG_SELF_CONVENTION, - methods::ZST_OFFSET, - minmax::MIN_MAX, - misc::CMP_NAN, - misc::CMP_OWNED, - misc::FLOAT_CMP, - misc::FLOAT_CMP_CONST, - misc::MODULO_ONE, - misc::SHORT_CIRCUIT_STATEMENT, - misc::TOPLEVEL_REF_ARG, - misc::USED_UNDERSCORE_BINDING, - misc::ZERO_PTR, - misc_early::BUILTIN_TYPE_SHADOW, - misc_early::DOUBLE_NEG, - misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, - misc_early::MIXED_CASE_HEX_LITERALS, - misc_early::REDUNDANT_PATTERN, - misc_early::UNNEEDED_FIELD_PATTERN, - misc_early::UNNEEDED_WILDCARD_PATTERN, - misc_early::UNSEPARATED_LITERAL_SUFFIX, - misc_early::ZERO_PREFIXED_LITERAL, - missing_const_for_fn::MISSING_CONST_FOR_FN, - missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, - missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES, - missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, - module_style::MOD_MODULE_FILES, - module_style::SELF_NAMED_MODULE_FILES, - modulo_arithmetic::MODULO_ARITHMETIC, - multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, - mut_key::MUTABLE_KEY_TYPE, - mut_mut::MUT_MUT, - mut_mutex_lock::MUT_MUTEX_LOCK, - mut_reference::UNNECESSARY_MUT_PASSED, - mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, - mutex_atomic::MUTEX_ATOMIC, - mutex_atomic::MUTEX_INTEGER, - needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, - needless_bitwise_bool::NEEDLESS_BITWISE_BOOL, - needless_bool::BOOL_COMPARISON, - needless_bool::NEEDLESS_BOOL, - needless_borrow::NEEDLESS_BORROW, - needless_borrow::REF_BINDING_TO_REFERENCE, - needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, - needless_continue::NEEDLESS_CONTINUE, - needless_for_each::NEEDLESS_FOR_EACH, - needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF, - needless_pass_by_value::NEEDLESS_PASS_BY_VALUE, - needless_question_mark::NEEDLESS_QUESTION_MARK, - needless_update::NEEDLESS_UPDATE, - neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD, - neg_multiply::NEG_MULTIPLY, - new_without_default::NEW_WITHOUT_DEFAULT, - no_effect::NO_EFFECT, - no_effect::UNNECESSARY_OPERATION, - non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, - non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, - non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, - non_expressive_names::MANY_SINGLE_CHAR_NAMES, - non_expressive_names::SIMILAR_NAMES, - non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS, - nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, - open_options::NONSENSICAL_OPEN_OPTIONS, - option_env_unwrap::OPTION_ENV_UNWRAP, - option_if_let_else::OPTION_IF_LET_ELSE, - overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, - panic_in_result_fn::PANIC_IN_RESULT_FN, - panic_unimplemented::PANIC, - panic_unimplemented::TODO, - panic_unimplemented::UNIMPLEMENTED, - panic_unimplemented::UNREACHABLE, - partialeq_ne_impl::PARTIALEQ_NE_IMPL, - pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, - pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, - path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, - pattern_type_mismatch::PATTERN_TYPE_MISMATCH, - precedence::PRECEDENCE, - ptr::CMP_NULL, - ptr::INVALID_NULL_PTR_USAGE, - ptr::MUT_FROM_REF, - ptr::PTR_ARG, - ptr_eq::PTR_EQ, - ptr_offset_with_cast::PTR_OFFSET_WITH_CAST, - question_mark::QUESTION_MARK, - ranges::MANUAL_RANGE_CONTAINS, - ranges::RANGE_MINUS_ONE, - ranges::RANGE_PLUS_ONE, - ranges::RANGE_ZIP_WITH_LEN, - ranges::REVERSED_EMPTY_RANGES, - redundant_clone::REDUNDANT_CLONE, - redundant_closure_call::REDUNDANT_CLOSURE_CALL, - redundant_else::REDUNDANT_ELSE, - redundant_field_names::REDUNDANT_FIELD_NAMES, - redundant_pub_crate::REDUNDANT_PUB_CRATE, - redundant_slicing::REDUNDANT_SLICING, - redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, - ref_option_ref::REF_OPTION_REF, - reference::DEREF_ADDROF, - reference::REF_IN_DEREF, - regex::INVALID_REGEX, - regex::TRIVIAL_REGEX, - repeat_once::REPEAT_ONCE, - returns::LET_AND_RETURN, - returns::NEEDLESS_RETURN, - same_name_method::SAME_NAME_METHOD, - self_assignment::SELF_ASSIGNMENT, - self_named_constructors::SELF_NAMED_CONSTRUCTORS, - semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, - serde_api::SERDE_API_MISUSE, - shadow::SHADOW_REUSE, - shadow::SHADOW_SAME, - shadow::SHADOW_UNRELATED, - single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, - size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, - slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - stable_sort_primitive::STABLE_SORT_PRIMITIVE, - strings::STRING_ADD, - strings::STRING_ADD_ASSIGN, - strings::STRING_FROM_UTF8_AS_BYTES, - strings::STRING_LIT_AS_BYTES, - strings::STRING_TO_STRING, - strings::STR_TO_STRING, - strlen_on_c_strings::STRLEN_ON_C_STRINGS, - suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS, - suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, - suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, - swap::ALMOST_SWAPPED, - swap::MANUAL_SWAP, - tabs_in_doc_comments::TABS_IN_DOC_COMMENTS, - temporary_assignment::TEMPORARY_ASSIGNMENT, - to_digit_is_some::TO_DIGIT_IS_SOME, - to_string_in_display::TO_STRING_IN_DISPLAY, - trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, - trait_bounds::TYPE_REPETITION_IN_BOUNDS, - transmute::CROSSPOINTER_TRANSMUTE, - transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, - transmute::TRANSMUTE_BYTES_TO_STR, - transmute::TRANSMUTE_FLOAT_TO_INT, - transmute::TRANSMUTE_INT_TO_BOOL, - transmute::TRANSMUTE_INT_TO_CHAR, - transmute::TRANSMUTE_INT_TO_FLOAT, - transmute::TRANSMUTE_PTR_TO_PTR, - transmute::TRANSMUTE_PTR_TO_REF, - transmute::UNSOUND_COLLECTION_TRANSMUTE, - transmute::USELESS_TRANSMUTE, - transmute::WRONG_TRANSMUTE, - transmuting_null::TRANSMUTING_NULL, - try_err::TRY_ERR, - types::BORROWED_BOX, - types::BOX_COLLECTION, - types::LINKEDLIST, - types::OPTION_OPTION, - types::RC_BUFFER, - types::RC_MUTEX, - types::REDUNDANT_ALLOCATION, - types::TYPE_COMPLEXITY, - types::VEC_BOX, - undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, - unicode::INVISIBLE_CHARACTERS, - unicode::NON_ASCII_LITERAL, - unicode::UNICODE_NOT_NFC, - unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, - unit_types::LET_UNIT_VALUE, - unit_types::UNIT_ARG, - unit_types::UNIT_CMP, - unnamed_address::FN_ADDRESS_COMPARISONS, - unnamed_address::VTABLE_ADDRESS_COMPARISONS, - unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, - unnecessary_sort_by::UNNECESSARY_SORT_BY, - unnecessary_wraps::UNNECESSARY_WRAPS, - unnested_or_patterns::UNNESTED_OR_PATTERNS, - unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - unused_async::UNUSED_ASYNC, - unused_io_amount::UNUSED_IO_AMOUNT, - unused_self::UNUSED_SELF, - unused_unit::UNUSED_UNIT, - unwrap::PANICKING_UNWRAP, - unwrap::UNNECESSARY_UNWRAP, - unwrap_in_result::UNWRAP_IN_RESULT, - upper_case_acronyms::UPPER_CASE_ACRONYMS, - use_self::USE_SELF, - useless_conversion::USELESS_CONVERSION, - vec::USELESS_VEC, - vec_init_then_push::VEC_INIT_THEN_PUSH, - vec_resize_to_zero::VEC_RESIZE_TO_ZERO, - verbose_file_reads::VERBOSE_FILE_READS, - wildcard_dependencies::WILDCARD_DEPENDENCIES, - wildcard_imports::ENUM_GLOB_USE, - wildcard_imports::WILDCARD_IMPORTS, - write::PRINTLN_EMPTY_STRING, - write::PRINT_LITERAL, - write::PRINT_STDERR, - write::PRINT_STDOUT, - write::PRINT_WITH_NEWLINE, - write::USE_DEBUG, - write::WRITELN_EMPTY_STRING, - write::WRITE_LITERAL, - write::WRITE_WITH_NEWLINE, - zero_div_zero::ZERO_DIVIDED_BY_ZERO, - zero_sized_map_values::ZERO_SIZED_MAP_VALUES, - ]); - // end register lints, do not remove this comment, it’s used in `update_lints` - - store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ - LintId::of(arithmetic::FLOAT_ARITHMETIC), - LintId::of(arithmetic::INTEGER_ARITHMETIC), - LintId::of(as_conversions::AS_CONVERSIONS), - LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), - LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), - LintId::of(create_dir::CREATE_DIR), - LintId::of(dbg_macro::DBG_MACRO), - LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK), - LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS), - LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE), - LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS), - LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS), - LintId::of(exit::EXIT), - LintId::of(float_literal::LOSSY_FLOAT_LITERAL), - LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE), - LintId::of(implicit_return::IMPLICIT_RETURN), - LintId::of(indexing_slicing::INDEXING_SLICING), - LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL), - LintId::of(integer_division::INTEGER_DIVISION), - LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), - LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), - LintId::of(map_err_ignore::MAP_ERR_IGNORE), - LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), - LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), - LintId::of(mem_forget::MEM_FORGET), - LintId::of(methods::CLONE_ON_REF_PTR), - LintId::of(methods::EXPECT_USED), - LintId::of(methods::FILETYPE_IS_FILE), - LintId::of(methods::GET_UNWRAP), - LintId::of(methods::UNWRAP_USED), - LintId::of(misc::FLOAT_CMP_CONST), - LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), - LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), - LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES), - LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), - LintId::of(module_style::MOD_MODULE_FILES), - LintId::of(module_style::SELF_NAMED_MODULE_FILES), - LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), - LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN), - LintId::of(panic_unimplemented::PANIC), - LintId::of(panic_unimplemented::TODO), - LintId::of(panic_unimplemented::UNIMPLEMENTED), - LintId::of(panic_unimplemented::UNREACHABLE), - LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH), - LintId::of(same_name_method::SAME_NAME_METHOD), - LintId::of(shadow::SHADOW_REUSE), - LintId::of(shadow::SHADOW_SAME), - LintId::of(strings::STRING_ADD), - LintId::of(strings::STRING_TO_STRING), - LintId::of(strings::STR_TO_STRING), - LintId::of(types::RC_BUFFER), - LintId::of(types::RC_MUTEX), - LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), - LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), - LintId::of(verbose_file_reads::VERBOSE_FILE_READS), - LintId::of(write::PRINT_STDERR), - LintId::of(write::PRINT_STDOUT), - LintId::of(write::USE_DEBUG), - ]); - - store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ - LintId::of(attrs::INLINE_ALWAYS), - LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), - LintId::of(bit_mask::VERBOSE_BIT_MASK), - LintId::of(bytecount::NAIVE_BYTECOUNT), - LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), - LintId::of(casts::CAST_LOSSLESS), - LintId::of(casts::CAST_POSSIBLE_TRUNCATION), - LintId::of(casts::CAST_POSSIBLE_WRAP), - LintId::of(casts::CAST_PRECISION_LOSS), - LintId::of(casts::CAST_PTR_ALIGNMENT), - LintId::of(casts::CAST_SIGN_LOSS), - LintId::of(casts::PTR_AS_PTR), - LintId::of(checked_conversions::CHECKED_CONVERSIONS), - LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION), - LintId::of(copy_iterator::COPY_ITERATOR), - LintId::of(default::DEFAULT_TRAIT_ACCESS), - LintId::of(dereference::EXPLICIT_DEREF_METHODS), - LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY), - LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE), - LintId::of(doc::DOC_MARKDOWN), - LintId::of(doc::MISSING_ERRORS_DOC), - LintId::of(doc::MISSING_PANICS_DOC), - LintId::of(empty_enum::EMPTY_ENUM), - LintId::of(enum_variants::MODULE_NAME_REPETITIONS), - LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), - LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), - LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), - LintId::of(functions::MUST_USE_CANDIDATE), - LintId::of(functions::TOO_MANY_LINES), - LintId::of(if_not_else::IF_NOT_ELSE), - LintId::of(implicit_hasher::IMPLICIT_HASHER), - LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), - LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), - LintId::of(infinite_iter::MAYBE_INFINITE_ITER), - LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), - LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), - LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), - LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), - LintId::of(let_underscore::LET_UNDERSCORE_DROP), - LintId::of(literal_representation::LARGE_DIGIT_GROUPS), - LintId::of(literal_representation::UNREADABLE_LITERAL), - LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), - LintId::of(loops::EXPLICIT_ITER_LOOP), - LintId::of(macro_use::MACRO_USE_IMPORTS), - LintId::of(manual_ok_or::MANUAL_OK_OR), - LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), - LintId::of(matches::MATCH_BOOL), - LintId::of(matches::MATCH_SAME_ARMS), - LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), - LintId::of(matches::MATCH_WILD_ERR_ARM), - LintId::of(matches::SINGLE_MATCH_ELSE), - LintId::of(methods::CLONED_INSTEAD_OF_COPIED), - LintId::of(methods::FILTER_MAP_NEXT), - LintId::of(methods::FLAT_MAP_OPTION), - LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), - LintId::of(methods::IMPLICIT_CLONE), - LintId::of(methods::INEFFICIENT_TO_STRING), - LintId::of(methods::MAP_FLATTEN), - LintId::of(methods::MAP_UNWRAP_OR), - LintId::of(misc::FLOAT_CMP), - LintId::of(misc::USED_UNDERSCORE_BINDING), - LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), - LintId::of(mut_mut::MUT_MUT), - LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), - LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE), - LintId::of(needless_continue::NEEDLESS_CONTINUE), - LintId::of(needless_for_each::NEEDLESS_FOR_EACH), - LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), - LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(non_expressive_names::SIMILAR_NAMES), - LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), - LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), - LintId::of(ranges::RANGE_MINUS_ONE), - LintId::of(ranges::RANGE_PLUS_ONE), - LintId::of(redundant_else::REDUNDANT_ELSE), - LintId::of(ref_option_ref::REF_OPTION_REF), - LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), - LintId::of(shadow::SHADOW_UNRELATED), - LintId::of(strings::STRING_ADD_ASSIGN), - LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), - LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS), - LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), - LintId::of(types::LINKEDLIST), - LintId::of(types::OPTION_OPTION), - LintId::of(unicode::NON_ASCII_LITERAL), - LintId::of(unicode::UNICODE_NOT_NFC), - LintId::of(unit_types::LET_UNIT_VALUE), - LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), - LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS), - LintId::of(unused_async::UNUSED_ASYNC), - LintId::of(unused_self::UNUSED_SELF), - LintId::of(wildcard_imports::ENUM_GLOB_USE), - LintId::of(wildcard_imports::WILDCARD_IMPORTS), - LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES), - ]); + include!("lib.register_lints.rs"); + include!("lib.register_restriction.rs"); + include!("lib.register_pedantic.rs"); #[cfg(feature = "internal-lints")] - store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![ - LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL), - LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS), - LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS), - LintId::of(utils::internal_lints::DEFAULT_LINT), - LintId::of(utils::internal_lints::IF_CHAIN_STYLE), - LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL), - LintId::of(utils::internal_lints::INVALID_PATHS), - LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS), - LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM), - LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA), - LintId::of(utils::internal_lints::PRODUCE_ICE), - LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR), - ]); + include!("lib.register_internal.rs"); - store.register_group(true, "clippy::all", Some("clippy"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), - LintId::of(approx_const::APPROX_CONSTANT), - LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assign_ops::ASSIGN_OP_PATTERN), - LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), - LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), - LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), - LintId::of(attrs::DEPRECATED_CFG_ATTR), - LintId::of(attrs::DEPRECATED_SEMVER), - LintId::of(attrs::MISMATCHED_TARGET_OS), - LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(bit_mask::BAD_BIT_MASK), - LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), - LintId::of(blacklisted_name::BLACKLISTED_NAME), - LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), - LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), - LintId::of(booleans::LOGIC_BUG), - LintId::of(booleans::NONMINIMAL_BOOL), - LintId::of(casts::CAST_REF_TO_MUT), - LintId::of(casts::CHAR_LIT_AS_U8), - LintId::of(casts::FN_TO_NUMERIC_CAST), - LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(casts::UNNECESSARY_CAST), - LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), - LintId::of(collapsible_if::COLLAPSIBLE_IF), - LintId::of(collapsible_match::COLLAPSIBLE_MATCH), - LintId::of(comparison_chain::COMPARISON_CHAIN), - LintId::of(copies::IFS_SAME_COND), - LintId::of(copies::IF_SAME_THEN_ELSE), - LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), - LintId::of(derivable_impls::DERIVABLE_IMPLS), - LintId::of(derive::DERIVE_HASH_XOR_EQ), - LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), - LintId::of(doc::MISSING_SAFETY_DOC), - LintId::of(doc::NEEDLESS_DOCTEST_MAIN), - LintId::of(double_comparison::DOUBLE_COMPARISONS), - LintId::of(double_parens::DOUBLE_PARENS), - LintId::of(drop_forget_ref::DROP_COPY), - LintId::of(drop_forget_ref::DROP_REF), - LintId::of(drop_forget_ref::FORGET_COPY), - LintId::of(drop_forget_ref::FORGET_REF), - LintId::of(duration_subsec::DURATION_SUBSEC), - LintId::of(entry::MAP_ENTRY), - LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(enum_variants::ENUM_VARIANT_NAMES), - LintId::of(enum_variants::MODULE_INCEPTION), - LintId::of(eq_op::EQ_OP), - LintId::of(eq_op::OP_REF), - LintId::of(erasing_op::ERASING_OP), - LintId::of(escape::BOXED_LOCAL), - LintId::of(eta_reduction::REDUNDANT_CLOSURE), - LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), - LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), - LintId::of(explicit_write::EXPLICIT_WRITE), - LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), - LintId::of(float_literal::EXCESSIVE_PRECISION), - LintId::of(format::USELESS_FORMAT), - LintId::of(formatting::POSSIBLE_MISSING_COMMA), - LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), - LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), - LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), - LintId::of(from_over_into::FROM_OVER_INTO), - LintId::of(from_str_radix_10::FROM_STR_RADIX_10), - LintId::of(functions::DOUBLE_MUST_USE), - LintId::of(functions::MUST_USE_UNIT), - LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), - LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(identity_op::IDENTITY_OP), - LintId::of(if_let_mutex::IF_LET_MUTEX), - LintId::of(if_then_panic::IF_THEN_PANIC), - LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), - LintId::of(infinite_iter::INFINITE_ITER), - LintId::of(inherent_to_string::INHERENT_TO_STRING), - LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), - LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), - LintId::of(int_plus_one::INT_PLUS_ONE), - LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), - LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), - LintId::of(len_zero::COMPARISON_TO_EMPTY), - LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), - LintId::of(len_zero::LEN_ZERO), - LintId::of(let_underscore::LET_UNDERSCORE_LOCK), - LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), - LintId::of(lifetimes::NEEDLESS_LIFETIMES), - LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), - LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), - LintId::of(loops::EMPTY_LOOP), - LintId::of(loops::EXPLICIT_COUNTER_LOOP), - LintId::of(loops::FOR_KV_MAP), - LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), - LintId::of(loops::ITER_NEXT_LOOP), - LintId::of(loops::MANUAL_FLATTEN), - LintId::of(loops::MANUAL_MEMCPY), - LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(loops::NEEDLESS_COLLECT), - LintId::of(loops::NEEDLESS_RANGE_LOOP), - LintId::of(loops::NEVER_LOOP), - LintId::of(loops::SAME_ITEM_PUSH), - LintId::of(loops::SINGLE_ELEMENT_LOOP), - LintId::of(loops::WHILE_IMMUTABLE_CONDITION), - LintId::of(loops::WHILE_LET_LOOP), - LintId::of(loops::WHILE_LET_ON_ITERATOR), - LintId::of(main_recursion::MAIN_RECURSION), - LintId::of(manual_async_fn::MANUAL_ASYNC_FN), - LintId::of(manual_map::MANUAL_MAP), - LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(manual_strip::MANUAL_STRIP), - LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), - LintId::of(map_clone::MAP_CLONE), - LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), - LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), - LintId::of(match_result_ok::MATCH_RESULT_OK), - LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), - LintId::of(matches::MATCH_AS_REF), - LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), - LintId::of(matches::MATCH_OVERLAPPING_ARM), - LintId::of(matches::MATCH_REF_PATS), - LintId::of(matches::MATCH_SINGLE_BINDING), - LintId::of(matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(matches::SINGLE_MATCH), - LintId::of(matches::WILDCARD_IN_OR_PATTERNS), - LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), - LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), - LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), - LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), - LintId::of(methods::BIND_INSTEAD_OF_MAP), - LintId::of(methods::BYTES_NTH), - LintId::of(methods::CHARS_LAST_CMP), - LintId::of(methods::CHARS_NEXT_CMP), - LintId::of(methods::CLONE_DOUBLE_REF), - LintId::of(methods::CLONE_ON_COPY), - LintId::of(methods::EXPECT_FUN_CALL), - LintId::of(methods::EXTEND_WITH_DRAIN), - LintId::of(methods::FILTER_MAP_IDENTITY), - LintId::of(methods::FILTER_NEXT), - LintId::of(methods::FLAT_MAP_IDENTITY), - LintId::of(methods::INSPECT_FOR_EACH), - LintId::of(methods::INTO_ITER_ON_REF), - LintId::of(methods::ITERATOR_STEP_BY_ZERO), - LintId::of(methods::ITER_CLONED_COLLECT), - LintId::of(methods::ITER_COUNT), - LintId::of(methods::ITER_NEXT_SLICE), - LintId::of(methods::ITER_NTH), - LintId::of(methods::ITER_NTH_ZERO), - LintId::of(methods::ITER_SKIP_NEXT), - LintId::of(methods::MANUAL_FILTER_MAP), - LintId::of(methods::MANUAL_FIND_MAP), - LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(methods::MANUAL_SPLIT_ONCE), - LintId::of(methods::MANUAL_STR_REPEAT), - LintId::of(methods::MAP_COLLECT_RESULT_UNIT), - LintId::of(methods::MAP_IDENTITY), - LintId::of(methods::NEW_RET_NO_SELF), - LintId::of(methods::OK_EXPECT), - LintId::of(methods::OPTION_AS_REF_DEREF), - LintId::of(methods::OPTION_FILTER_MAP), - LintId::of(methods::OPTION_MAP_OR_NONE), - LintId::of(methods::OR_FUN_CALL), - LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), - LintId::of(methods::SEARCH_IS_SOME), - LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(methods::SINGLE_CHAR_ADD_STR), - LintId::of(methods::SINGLE_CHAR_PATTERN), - LintId::of(methods::SKIP_WHILE_NEXT), - LintId::of(methods::STRING_EXTEND_CHARS), - LintId::of(methods::SUSPICIOUS_MAP), - LintId::of(methods::SUSPICIOUS_SPLITN), - LintId::of(methods::UNINIT_ASSUMED_INIT), - LintId::of(methods::UNNECESSARY_FILTER_MAP), - LintId::of(methods::UNNECESSARY_FOLD), - LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), - LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), - LintId::of(methods::USELESS_ASREF), - LintId::of(methods::WRONG_SELF_CONVENTION), - LintId::of(methods::ZST_OFFSET), - LintId::of(minmax::MIN_MAX), - LintId::of(misc::CMP_NAN), - LintId::of(misc::CMP_OWNED), - LintId::of(misc::MODULO_ONE), - LintId::of(misc::SHORT_CIRCUIT_STATEMENT), - LintId::of(misc::TOPLEVEL_REF_ARG), - LintId::of(misc::ZERO_PTR), - LintId::of(misc_early::BUILTIN_TYPE_SHADOW), - LintId::of(misc_early::DOUBLE_NEG), - LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), - LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), - LintId::of(misc_early::REDUNDANT_PATTERN), - LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), - LintId::of(misc_early::ZERO_PREFIXED_LITERAL), - LintId::of(mut_key::MUTABLE_KEY_TYPE), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), - LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), - LintId::of(mutex_atomic::MUTEX_ATOMIC), - LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), - LintId::of(needless_bool::BOOL_COMPARISON), - LintId::of(needless_bool::NEEDLESS_BOOL), - LintId::of(needless_borrow::NEEDLESS_BORROW), - LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), - LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), - LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), - LintId::of(needless_update::NEEDLESS_UPDATE), - LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), - LintId::of(neg_multiply::NEG_MULTIPLY), - LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), - LintId::of(no_effect::NO_EFFECT), - LintId::of(no_effect::UNNECESSARY_OPERATION), - LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), - LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), - LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), - LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), - LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), - LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), - LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), - LintId::of(precedence::PRECEDENCE), - LintId::of(ptr::CMP_NULL), - LintId::of(ptr::INVALID_NULL_PTR_USAGE), - LintId::of(ptr::MUT_FROM_REF), - LintId::of(ptr::PTR_ARG), - LintId::of(ptr_eq::PTR_EQ), - LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(question_mark::QUESTION_MARK), - LintId::of(ranges::MANUAL_RANGE_CONTAINS), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), - LintId::of(ranges::REVERSED_EMPTY_RANGES), - LintId::of(redundant_clone::REDUNDANT_CLONE), - LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), - LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(redundant_slicing::REDUNDANT_SLICING), - LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(reference::DEREF_ADDROF), - LintId::of(reference::REF_IN_DEREF), - LintId::of(regex::INVALID_REGEX), - LintId::of(repeat_once::REPEAT_ONCE), - LintId::of(returns::LET_AND_RETURN), - LintId::of(returns::NEEDLESS_RETURN), - LintId::of(self_assignment::SELF_ASSIGNMENT), - LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), - LintId::of(serde_api::SERDE_API_MISUSE), - LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), - LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), - LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), - LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), - LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), - LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), - LintId::of(swap::ALMOST_SWAPPED), - LintId::of(swap::MANUAL_SWAP), - LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), - LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), - LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), - LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), - LintId::of(transmute::CROSSPOINTER_TRANSMUTE), - LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), - LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), - LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), - LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), - LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), - LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), - LintId::of(transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), - LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), - LintId::of(try_err::TRY_ERR), - LintId::of(types::BORROWED_BOX), - LintId::of(types::BOX_COLLECTION), - LintId::of(types::REDUNDANT_ALLOCATION), - LintId::of(types::TYPE_COMPLEXITY), - LintId::of(types::VEC_BOX), - LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), - LintId::of(unicode::INVISIBLE_CHARACTERS), - LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), - LintId::of(unit_types::UNIT_ARG), - LintId::of(unit_types::UNIT_CMP), - LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), - LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), - LintId::of(unused_unit::UNUSED_UNIT), - LintId::of(unwrap::PANICKING_UNWRAP), - LintId::of(unwrap::UNNECESSARY_UNWRAP), - LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), - LintId::of(useless_conversion::USELESS_CONVERSION), - LintId::of(vec::USELESS_VEC), - LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), - LintId::of(write::PRINTLN_EMPTY_STRING), - LintId::of(write::PRINT_LITERAL), - LintId::of(write::PRINT_WITH_NEWLINE), - LintId::of(write::WRITELN_EMPTY_STRING), - LintId::of(write::WRITE_LITERAL), - LintId::of(write::WRITE_WITH_NEWLINE), - LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), - ]); - - store.register_group(true, "clippy::style", Some("clippy_style"), vec![ - LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(assign_ops::ASSIGN_OP_PATTERN), - LintId::of(blacklisted_name::BLACKLISTED_NAME), - LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), - LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), - LintId::of(casts::FN_TO_NUMERIC_CAST), - LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), - LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), - LintId::of(collapsible_if::COLLAPSIBLE_IF), - LintId::of(collapsible_match::COLLAPSIBLE_MATCH), - LintId::of(comparison_chain::COMPARISON_CHAIN), - LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), - LintId::of(doc::MISSING_SAFETY_DOC), - LintId::of(doc::NEEDLESS_DOCTEST_MAIN), - LintId::of(enum_variants::ENUM_VARIANT_NAMES), - LintId::of(enum_variants::MODULE_INCEPTION), - LintId::of(eq_op::OP_REF), - LintId::of(eta_reduction::REDUNDANT_CLOSURE), - LintId::of(float_literal::EXCESSIVE_PRECISION), - LintId::of(from_over_into::FROM_OVER_INTO), - LintId::of(from_str_radix_10::FROM_STR_RADIX_10), - LintId::of(functions::DOUBLE_MUST_USE), - LintId::of(functions::MUST_USE_UNIT), - LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(if_then_panic::IF_THEN_PANIC), - LintId::of(inherent_to_string::INHERENT_TO_STRING), - LintId::of(len_zero::COMPARISON_TO_EMPTY), - LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), - LintId::of(len_zero::LEN_ZERO), - LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING), - LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS), - LintId::of(loops::FOR_KV_MAP), - LintId::of(loops::NEEDLESS_RANGE_LOOP), - LintId::of(loops::SAME_ITEM_PUSH), - LintId::of(loops::WHILE_LET_ON_ITERATOR), - LintId::of(main_recursion::MAIN_RECURSION), - LintId::of(manual_async_fn::MANUAL_ASYNC_FN), - LintId::of(manual_map::MANUAL_MAP), - LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(map_clone::MAP_CLONE), - LintId::of(match_result_ok::MATCH_RESULT_OK), - LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), - LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), - LintId::of(matches::MATCH_OVERLAPPING_ARM), - LintId::of(matches::MATCH_REF_PATS), - LintId::of(matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(matches::SINGLE_MATCH), - LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), - LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), - LintId::of(methods::BYTES_NTH), - LintId::of(methods::CHARS_LAST_CMP), - LintId::of(methods::CHARS_NEXT_CMP), - LintId::of(methods::INTO_ITER_ON_REF), - LintId::of(methods::ITER_CLONED_COLLECT), - LintId::of(methods::ITER_NEXT_SLICE), - LintId::of(methods::ITER_NTH_ZERO), - LintId::of(methods::ITER_SKIP_NEXT), - LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), - LintId::of(methods::MAP_COLLECT_RESULT_UNIT), - LintId::of(methods::NEW_RET_NO_SELF), - LintId::of(methods::OK_EXPECT), - LintId::of(methods::OPTION_MAP_OR_NONE), - LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), - LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(methods::SINGLE_CHAR_ADD_STR), - LintId::of(methods::STRING_EXTEND_CHARS), - LintId::of(methods::UNNECESSARY_FOLD), - LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), - LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), - LintId::of(methods::WRONG_SELF_CONVENTION), - LintId::of(misc::TOPLEVEL_REF_ARG), - LintId::of(misc::ZERO_PTR), - LintId::of(misc_early::BUILTIN_TYPE_SHADOW), - LintId::of(misc_early::DOUBLE_NEG), - LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), - LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), - LintId::of(misc_early::REDUNDANT_PATTERN), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), - LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), - LintId::of(needless_borrow::NEEDLESS_BORROW), - LintId::of(neg_multiply::NEG_MULTIPLY), - LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), - LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), - LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), - LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), - LintId::of(ptr::CMP_NULL), - LintId::of(ptr::PTR_ARG), - LintId::of(ptr_eq::PTR_EQ), - LintId::of(question_mark::QUESTION_MARK), - LintId::of(ranges::MANUAL_RANGE_CONTAINS), - LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), - LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(returns::LET_AND_RETURN), - LintId::of(returns::NEEDLESS_RETURN), - LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), - LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), - LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), - LintId::of(try_err::TRY_ERR), - LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(unused_unit::UNUSED_UNIT), - LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS), - LintId::of(write::PRINTLN_EMPTY_STRING), - LintId::of(write::PRINT_LITERAL), - LintId::of(write::PRINT_WITH_NEWLINE), - LintId::of(write::WRITELN_EMPTY_STRING), - LintId::of(write::WRITE_LITERAL), - LintId::of(write::WRITE_WITH_NEWLINE), - ]); - - store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![ - LintId::of(attrs::DEPRECATED_CFG_ATTR), - LintId::of(booleans::NONMINIMAL_BOOL), - LintId::of(casts::CHAR_LIT_AS_U8), - LintId::of(casts::UNNECESSARY_CAST), - LintId::of(derivable_impls::DERIVABLE_IMPLS), - LintId::of(double_comparison::DOUBLE_COMPARISONS), - LintId::of(double_parens::DOUBLE_PARENS), - LintId::of(duration_subsec::DURATION_SUBSEC), - LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION), - LintId::of(explicit_write::EXPLICIT_WRITE), - LintId::of(format::USELESS_FORMAT), - LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(identity_op::IDENTITY_OP), - LintId::of(int_plus_one::INT_PLUS_ONE), - LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), - LintId::of(lifetimes::NEEDLESS_LIFETIMES), - LintId::of(loops::EXPLICIT_COUNTER_LOOP), - LintId::of(loops::MANUAL_FLATTEN), - LintId::of(loops::SINGLE_ELEMENT_LOOP), - LintId::of(loops::WHILE_LET_LOOP), - LintId::of(manual_strip::MANUAL_STRIP), - LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR), - LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), - LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), - LintId::of(matches::MATCH_AS_REF), - LintId::of(matches::MATCH_SINGLE_BINDING), - LintId::of(matches::WILDCARD_IN_OR_PATTERNS), - LintId::of(methods::BIND_INSTEAD_OF_MAP), - LintId::of(methods::CLONE_ON_COPY), - LintId::of(methods::FILTER_MAP_IDENTITY), - LintId::of(methods::FILTER_NEXT), - LintId::of(methods::FLAT_MAP_IDENTITY), - LintId::of(methods::INSPECT_FOR_EACH), - LintId::of(methods::ITER_COUNT), - LintId::of(methods::MANUAL_FILTER_MAP), - LintId::of(methods::MANUAL_FIND_MAP), - LintId::of(methods::MANUAL_SPLIT_ONCE), - LintId::of(methods::MAP_IDENTITY), - LintId::of(methods::OPTION_AS_REF_DEREF), - LintId::of(methods::OPTION_FILTER_MAP), - LintId::of(methods::SEARCH_IS_SOME), - LintId::of(methods::SKIP_WHILE_NEXT), - LintId::of(methods::UNNECESSARY_FILTER_MAP), - LintId::of(methods::USELESS_ASREF), - LintId::of(misc::SHORT_CIRCUIT_STATEMENT), - LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), - LintId::of(misc_early::ZERO_PREFIXED_LITERAL), - LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), - LintId::of(needless_bool::BOOL_COMPARISON), - LintId::of(needless_bool::NEEDLESS_BOOL), - LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), - LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF), - LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), - LintId::of(needless_update::NEEDLESS_UPDATE), - LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), - LintId::of(no_effect::NO_EFFECT), - LintId::of(no_effect::UNNECESSARY_OPERATION), - LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), - LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), - LintId::of(precedence::PRECEDENCE), - LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), - LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), - LintId::of(redundant_slicing::REDUNDANT_SLICING), - LintId::of(reference::DEREF_ADDROF), - LintId::of(reference::REF_IN_DEREF), - LintId::of(repeat_once::REPEAT_ONCE), - LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), - LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), - LintId::of(swap::MANUAL_SWAP), - LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT), - LintId::of(transmute::CROSSPOINTER_TRANSMUTE), - LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS), - LintId::of(transmute::TRANSMUTE_BYTES_TO_STR), - LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT), - LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), - LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), - LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), - LintId::of(transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(types::BORROWED_BOX), - LintId::of(types::TYPE_COMPLEXITY), - LintId::of(types::VEC_BOX), - LintId::of(unit_types::UNIT_ARG), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(unwrap::UNNECESSARY_UNWRAP), - LintId::of(useless_conversion::USELESS_CONVERSION), - LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), - ]); - - store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), - LintId::of(approx_const::APPROX_CONSTANT), - LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), - LintId::of(attrs::DEPRECATED_SEMVER), - LintId::of(attrs::MISMATCHED_TARGET_OS), - LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(bit_mask::BAD_BIT_MASK), - LintId::of(bit_mask::INEFFECTIVE_BIT_MASK), - LintId::of(booleans::LOGIC_BUG), - LintId::of(casts::CAST_REF_TO_MUT), - LintId::of(copies::IFS_SAME_COND), - LintId::of(copies::IF_SAME_THEN_ELSE), - LintId::of(derive::DERIVE_HASH_XOR_EQ), - LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), - LintId::of(drop_forget_ref::DROP_COPY), - LintId::of(drop_forget_ref::DROP_REF), - LintId::of(drop_forget_ref::FORGET_COPY), - LintId::of(drop_forget_ref::FORGET_REF), - LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), - LintId::of(eq_op::EQ_OP), - LintId::of(erasing_op::ERASING_OP), - LintId::of(formatting::POSSIBLE_MISSING_COMMA), - LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), - LintId::of(if_let_mutex::IF_LET_MUTEX), - LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), - LintId::of(infinite_iter::INFINITE_ITER), - LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), - LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY), - LintId::of(let_underscore::LET_UNDERSCORE_LOCK), - LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(loops::ITER_NEXT_LOOP), - LintId::of(loops::NEVER_LOOP), - LintId::of(loops::WHILE_IMMUTABLE_CONDITION), - LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), - LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), - LintId::of(methods::CLONE_DOUBLE_REF), - LintId::of(methods::ITERATOR_STEP_BY_ZERO), - LintId::of(methods::SUSPICIOUS_SPLITN), - LintId::of(methods::UNINIT_ASSUMED_INIT), - LintId::of(methods::ZST_OFFSET), - LintId::of(minmax::MIN_MAX), - LintId::of(misc::CMP_NAN), - LintId::of(misc::MODULO_ONE), - LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), - LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), - LintId::of(ptr::INVALID_NULL_PTR_USAGE), - LintId::of(ptr::MUT_FROM_REF), - LintId::of(ranges::REVERSED_EMPTY_RANGES), - LintId::of(regex::INVALID_REGEX), - LintId::of(self_assignment::SELF_ASSIGNMENT), - LintId::of(serde_api::SERDE_API_MISUSE), - LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), - LintId::of(swap::ALMOST_SWAPPED), - LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), - LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), - LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), - LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), - LintId::of(unicode::INVISIBLE_CHARACTERS), - LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), - LintId::of(unit_types::UNIT_CMP), - LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), - LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), - LintId::of(unwrap::PANICKING_UNWRAP), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), - ]); - - store.register_group(true, "clippy::suspicious", None, vec![ - LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP), - LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), - LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), - LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), - LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), - LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), - LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING), - LintId::of(loops::EMPTY_LOOP), - LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), - LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(methods::SUSPICIOUS_MAP), - LintId::of(mut_key::MUTABLE_KEY_TYPE), - LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), - LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), - ]); - - store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ - LintId::of(entry::MAP_ENTRY), - LintId::of(escape::BOXED_LOCAL), - LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), - LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), - LintId::of(loops::MANUAL_MEMCPY), - LintId::of(loops::NEEDLESS_COLLECT), - LintId::of(methods::EXPECT_FUN_CALL), - LintId::of(methods::EXTEND_WITH_DRAIN), - LintId::of(methods::ITER_NTH), - LintId::of(methods::MANUAL_STR_REPEAT), - LintId::of(methods::OR_FUN_CALL), - LintId::of(methods::SINGLE_CHAR_PATTERN), - LintId::of(misc::CMP_OWNED), - LintId::of(mutex_atomic::MUTEX_ATOMIC), - LintId::of(redundant_clone::REDUNDANT_CLONE), - LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), - LintId::of(types::BOX_COLLECTION), - LintId::of(types::REDUNDANT_ALLOCATION), - LintId::of(vec::USELESS_VEC), - LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - ]); - - store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![ - LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA), - LintId::of(feature_name::NEGATIVE_FEATURE_NAMES), - LintId::of(feature_name::REDUNDANT_FEATURE_NAMES), - LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS), - LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES), - ]); - - store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ - LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR), - LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY), - LintId::of(copies::BRANCHES_SHARING_CODE), - LintId::of(disallowed_method::DISALLOWED_METHOD), - LintId::of(disallowed_type::DISALLOWED_TYPE), - LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), - LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS), - LintId::of(future_not_send::FUTURE_NOT_SEND), - LintId::of(let_if_seq::USELESS_LET_IF_SEQ), - LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), - LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), - LintId::of(mutex_atomic::MUTEX_INTEGER), - LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), - LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), - LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), - LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), - LintId::of(regex::TRIVIAL_REGEX), - LintId::of(strings::STRING_LIT_AS_BYTES), - LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), - LintId::of(transmute::USELESS_TRANSMUTE), - LintId::of(use_self::USE_SELF), - ]); + include!("lib.register_all.rs"); + include!("lib.register_style.rs"); + include!("lib.register_complexity.rs"); + include!("lib.register_correctness.rs"); + include!("lib.register_suspicious.rs"); + include!("lib.register_perf.rs"); + include!("lib.register_cargo.rs"); + include!("lib.register_nursery.rs"); #[cfg(feature = "metadata-collector-lint")] { @@ -1931,7 +555,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); store.register_late_pass(|| Box::new(map_clone::MapClone)); store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore)); - store.register_late_pass(|| Box::new(shadow::Shadow)); + store.register_late_pass(|| Box::new(shadow::Shadow::default())); store.register_late_pass(|| Box::new(unit_types::UnitTypes)); store.register_late_pass(|| Box::new(loops::Loops)); store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default())); @@ -2092,6 +716,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); + store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); @@ -2142,6 +767,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(feature_name::FeatureName)); store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator)); store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic)); + let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; + store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send))); } #[rustfmt::skip] diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index 358d53e8859..aedf0844937 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -92,7 +92,7 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { - if let ty::BorrowKind::MutBorrow = bk { + if bk == ty::BorrowKind::MutBorrow { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) { self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 7157b801185..172d9fc39a2 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -95,7 +95,7 @@ pub(super) fn check<'tcx>( let mut take_expr = end; if let ExprKind::Binary(ref op, left, right) = end.kind { - if let BinOpKind::Add = op.node { + if op.node == BinOpKind::Add { let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left); let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right); diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 41956650c9f..c0fde5e5166 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { NeverLoopResult::AlwaysBreak => { span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| { if_chain! { - if let LoopSource::ForLoop = source; + if source == LoopSource::ForLoop; if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1); if let Some(ForLoop { arg: iterator, pat, span: for_span, .. }) = ForLoop::hir(parent_match); then { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 8e1385fb83a..b632af455f8 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -49,7 +49,7 @@ fn check_fn( ) { if_chain! { if let Some(header) = kind.header(); - if let IsAsync::NotAsync = header.asyncness; + if header.asyncness == IsAsync::NotAsync; // Check that this function returns `impl Future` if let FnRetTy::Return(ret_ty) = decl.output; if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty); @@ -178,7 +178,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) if args.len() == 1; if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0]; let closure_body = cx.tcx.hir().body(body_id); - if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind; + if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); then { return Some(closure_body); } diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 952e250bb9e..40de9ffcd4e 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -205,14 +205,13 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String { fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) { let var_arg = &map_args[0]; - let (map_type, variant, lint) = - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) { - ("Option", "Some", OPTION_MAP_UNIT_FN) - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) { - ("Result", "Ok", RESULT_MAP_UNIT_FN) - } else { - return; - }; + let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) { + ("Option", "Some", OPTION_MAP_UNIT_FN) + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) { + ("Result", "Ok", RESULT_MAP_UNIT_FN) + } else { + return; + }; let fn_arg = &map_args[1]; if is_unit_function(cx, fn_arg) { diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index a685c1eaa2c..56d4163a6b3 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1025,8 +1025,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) let adt_def = match ty.kind() { ty::Adt(adt_def, _) if adt_def.is_enum() - && !(is_type_diagnostic_item(cx, ty, sym::Option) - || is_type_diagnostic_item(cx, ty, sym::Result)) => + && !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) => { adt_def }, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 2025056ac94..b26d11c0d6b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1284,8 +1284,9 @@ /// /// ### Why is this bad? /// It looks suspicious. Maybe `map` was confused with `filter`. - /// If the `map` call is intentional, this should be rewritten. Or, if you intend to - /// drive the iterator to completion, you can just use `for_each` instead. + /// If the `map` call is intentional, this should be rewritten + /// using `inspect`. Or, if you intend to drive the iterator to + /// completion, you can just use `for_each` instead. /// /// ### Example /// ```rust diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index cabbb840076..b5bbbb09092 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -178,15 +178,15 @@ fn check_general_case<'tcx>( hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); }, - hir::ExprKind::Block(block, _) => { - if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules { - if let Some(block_expr) = block.expr { - if let hir::ExprKind::MethodCall(..) = block_expr.kind { - check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); - } + hir::ExprKind::Block(block, _) + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) => + { + if let Some(block_expr) = block.expr { + if let hir::ExprKind::MethodCall(..) = block_expr.kind { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); } } - }, + } _ => (), } } diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs index 0fd0668c734..18ded291915 100644 --- a/clippy_lints/src/methods/suspicious_map.rs +++ b/clippy_lints/src/methods/suspicious_map.rs @@ -28,7 +28,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi expr.span, "this call to `map()` won't have an effect on the call to `count()`", None, - "make sure you did not confuse `map` with `filter` or `for_each`", + "make sure you did not confuse `map` with `filter`, `for_each` or `inspect`", ); } } diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index a9d3764d92d..59bdfb923ed 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -35,8 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< let in_ty = cx.typeck_results().node_type(body.params[0].hir_id); match cx.typeck_results().expr_ty(&body.value).kind() { ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::Option, adt.did) - && TyS::same_type(in_ty, subst.type_at(0)) => + if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && TyS::same_type(in_ty, subst.type_at(0)) => { "filter" }, diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 2d14943b56c..f45e68233a1 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for ModuloArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match &expr.kind { ExprKind::Binary(op, lhs, rhs) | ExprKind::AssignOp(op, lhs, rhs) => { - if let BinOpKind::Rem = op.node { + if op.node == BinOpKind::Rem { let lhs_operand = analyze_operand(lhs, cx, expr); let rhs_operand = analyze_operand(rhs, cx, expr); if_chain! { diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index c9dd94400ef..91944653500 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -248,7 +248,7 @@ fn check_comparison<'a, 'tcx>( if l_ty.is_bool() && r_ty.is_bool() { let mut applicability = Applicability::MachineApplicable; - if let BinOpKind::Eq = op.node { + if op.node == BinOpKind::Eq { let expression_info = one_side_is_unary_not(left_side, right_side); if expression_info.one_side_is_unary_not { span_lint_and_sugg( diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index fa36d8fb1b3..1b15d29439f 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -46,7 +46,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { if_chain! { if let ExprKind::Lit(ref l) = lit.kind; - if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)); + if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); if cx.typeck_results().expr_ty(exp).is_integral(); then { span_lint(cx, NEG_MULTIPLY, span, "negation by multiplying with `-1`"); diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 0ad616a39d2..0ac27f1cba2 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -69,7 +69,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { }) = item.kind { for assoc_item in items { - if let hir::AssocItemKind::Fn { has_self: false } = assoc_item.kind { + if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) { let impl_item = cx.tcx.hir().impl_item(assoc_item.id); if in_external_macro(cx.sess(), impl_item.span) { return; diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs new file mode 100644 index 00000000000..374b7bd5964 --- /dev/null +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -0,0 +1,238 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_lint_allowed; +use clippy_utils::source::snippet; +use clippy_utils::ty::{implements_trait, is_copy}; +use rustc_ast::ImplPolarity; +use rustc_hir::def_id::DefId; +use rustc_hir::{FieldDef, Item, ItemKind, Node}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Warns about fields in struct implementing `Send` that are neither `Send` nor `Copy`. + /// + /// ### Why is this bad? + /// Sending the struct to another thread will transfer the ownership to + /// the new thread by dropping in the current thread during the transfer. + /// This causes soundness issues for non-`Send` fields, as they are also + /// dropped and might not be set up to handle this. + /// + /// See: + /// * [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html) + /// * [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html) + /// + /// ### Known Problems + /// Data structures that contain raw pointers may cause false positives. + /// They are sometimes safe to be sent across threads but do not implement + /// the `Send` trait. This lint has a heuristic to filter out basic cases + /// such as `Vec<*const T>`, but it's not perfect. Feel free to create an + /// issue if you have a suggestion on how this heuristic can be improved. + /// + /// ### Example + /// ```rust,ignore + /// struct ExampleStruct { + /// rc_is_not_send: Rc, + /// unbounded_generic_field: T, + /// } + /// + /// // This impl is unsound because it allows sending `!Send` types through `ExampleStruct` + /// unsafe impl Send for ExampleStruct {} + /// ``` + /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) + /// or specify correct bounds on generic type parameters (`T: Send`). + pub NON_SEND_FIELDS_IN_SEND_TY, + nursery, + "there is field that does not implement `Send` in a `Send` struct" +} + +#[derive(Copy, Clone)] +pub struct NonSendFieldInSendTy { + enable_raw_pointer_heuristic: bool, +} + +impl NonSendFieldInSendTy { + pub fn new(enable_raw_pointer_heuristic: bool) -> Self { + Self { + enable_raw_pointer_heuristic, + } + } +} + +impl_lint_pass!(NonSendFieldInSendTy => [NON_SEND_FIELDS_IN_SEND_TY]); + +impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + let ty_allowed_in_send = if self.enable_raw_pointer_heuristic { + ty_allowed_with_raw_pointer_heuristic + } else { + ty_allowed_without_raw_pointer_heuristic + }; + + // Checks if we are in `Send` impl item. + // We start from `Send` impl instead of `check_field_def()` because + // single `AdtDef` may have multiple `Send` impls due to generic + // parameters, and the lint is much easier to implement in this way. + if_chain! { + if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send); + if let ItemKind::Impl(hir_impl) = &item.kind; + if let Some(trait_ref) = &hir_impl.of_trait; + if let Some(trait_id) = trait_ref.trait_def_id(); + if send_trait == trait_id; + if hir_impl.polarity == ImplPolarity::Positive; + if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.def_id); + if let self_ty = ty_trait_ref.self_ty(); + if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind(); + then { + let mut non_send_fields = Vec::new(); + + let hir_map = cx.tcx.hir(); + for variant in &adt_def.variants { + for field in &variant.fields { + if_chain! { + if let Some(field_hir_id) = field + .did + .as_local() + .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id)); + if !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id); + if let field_ty = field.ty(cx.tcx, impl_trait_substs); + if !ty_allowed_in_send(cx, field_ty, send_trait); + if let Node::Field(field_def) = hir_map.get(field_hir_id); + then { + non_send_fields.push(NonSendField { + def: field_def, + ty: field_ty, + generic_params: collect_generic_params(cx, field_ty), + }) + } + } + } + } + + if !non_send_fields.is_empty() { + span_lint_and_then( + cx, + NON_SEND_FIELDS_IN_SEND_TY, + item.span, + &format!( + "this implementation is unsound, as some fields in `{}` are `!Send`", + snippet(cx, hir_impl.self_ty.span, "Unknown") + ), + |diag| { + for field in non_send_fields { + diag.span_note( + field.def.span, + &format!("the type of field `{}` is `!Send`", field.def.ident.name), + ); + + match field.generic_params.len() { + 0 => diag.help("use a thread-safe type that implements `Send`"), + 1 if is_ty_param(field.ty) => diag.help(&format!("add `{}: Send` bound in `Send` impl", field.ty)), + _ => diag.help(&format!( + "add bounds on type parameter{} `{}` that satisfy `{}: Send`", + if field.generic_params.len() > 1 { "s" } else { "" }, + field.generic_params_string(), + snippet(cx, field.def.ty.span, "Unknown"), + )), + }; + } + }, + ); + } + } + } + } +} + +struct NonSendField<'tcx> { + def: &'tcx FieldDef<'tcx>, + ty: Ty<'tcx>, + generic_params: Vec>, +} + +impl<'tcx> NonSendField<'tcx> { + fn generic_params_string(&self) -> String { + self.generic_params + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + } +} + +/// Given a type, collect all of its generic parameters. +/// Example: `MyStruct>` => `vec![P, Q, R]` +fn collect_generic_params<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Vec> { + ty.walk(cx.tcx) + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty), + _ => None, + }) + .filter(|&inner_ty| is_ty_param(inner_ty)) + .collect() +} + +/// Be more strict when the heuristic is disabled +fn ty_allowed_without_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool { + if implements_trait(cx, ty, send_trait, &[]) { + return true; + } + + if is_copy(cx, ty) && !contains_raw_pointer(cx, ty) { + return true; + } + + false +} + +/// Heuristic to allow cases like `Vec<*const u8>` +fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool { + if implements_trait(cx, ty, send_trait, &[]) || is_copy(cx, ty) { + return true; + } + + // The type is known to be `!Send` and `!Copy` + match ty.kind() { + ty::Tuple(_) => ty + .tuple_fields() + .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)), + ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), + ty::Adt(_, substs) => { + if contains_raw_pointer(cx, ty) { + // descends only if ADT contains any raw pointers + substs.iter().all(|generic_arg| match generic_arg.unpack() { + GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), + // Lifetimes and const generics are not solid part of ADT and ignored + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true, + }) + } else { + false + } + }, + // Raw pointers are `!Send` but allowed by the heuristic + ty::RawPtr(_) => true, + _ => false, + } +} + +/// Checks if the type contains any raw pointers in substs (including nested ones). +fn contains_raw_pointer<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool { + for ty_node in target_ty.walk(cx.tcx) { + if_chain! { + if let GenericArgKind::Type(inner_ty) = ty_node.unpack(); + if let ty::RawPtr(_) = inner_ty.kind(); + then { + return true; + } + } + } + + false +} + +/// Returns `true` if the type is a type parameter such as `T`. +fn is_ty_param(target_ty: Ty<'_>) -> bool { + matches!(target_ty.kind(), ty::Param(_)) +} diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 34755afdb72..0f9e5ada3a8 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -26,6 +26,9 @@ declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]); +const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust"; +const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust"; + impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { // a + b < a, a > a + b, a < a - b, a - b > a fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -40,17 +43,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); then { - if let BinOpKind::Lt = op.node { - if let BinOpKind::Add = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C overflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); } - if let BinOpKind::Gt = op.node { - if let BinOpKind::Sub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C underflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } } @@ -65,17 +62,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if cx.typeck_results().expr_ty(ident1).is_integral(); if cx.typeck_results().expr_ty(ident2).is_integral(); then { - if let BinOpKind::Gt = op.node { - if let BinOpKind::Add = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C overflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG); } - if let BinOpKind::Lt = op.node { - if let BinOpKind::Sub = op2.node { - span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, - "you are trying to use classic C underflow conditions that will fail in Rust"); - } + if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub { + span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG); } } } diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index ed2e1f90fa5..919d4e11e5a 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -41,25 +41,23 @@ pub struct RedundantPubCrate { impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let VisibilityKind::Crate { .. } = item.vis.node { - if !cx.access_levels.is_exported(item.def_id) { - if let Some(false) = self.is_exported.last() { - let span = item.span.with_hi(item.ident.span.hi()); - let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id()); - span_lint_and_then( - cx, - REDUNDANT_PUB_CRATE, - span, - &format!("pub(crate) {} inside private module", descr), - |diag| { - diag.span_suggestion( - item.vis.span, - "consider using", - "pub".to_string(), - Applicability::MachineApplicable, - ); - }, - ); - } + if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false) { + let span = item.span.with_hi(item.ident.span.hi()); + let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id()); + span_lint_and_then( + cx, + REDUNDANT_PUB_CRATE, + span, + &format!("pub(crate) {} inside private module", descr), + |diag| { + diag.span_suggestion( + item.vis.span, + "consider using", + "pub".to_string(), + Applicability::MachineApplicable, + ); + }, + ); } } diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index 5fd0d152763..cf94c0e97d9 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -48,7 +48,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { if_chain! { if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind; if path.ident.name == sym!(repeat); - if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(count); + if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1)); if !in_macro(receiver.span); then { let ty = cx.typeck_results().expr_ty(receiver).peel_refs(); diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index b9e317a3cfd..2ca7c18800e 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -1,17 +1,14 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::source::snippet; -use clippy_utils::{contains_name, higher, iter_input_pats}; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{ - Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind, - UnOp, -}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use clippy_utils::visitors::is_local_used; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def::Res; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::hir_id::ItemLocalId; +use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -23,10 +20,6 @@ /// code. Still, some may opt to avoid it in their code base, they can set this /// lint to `Warn`. /// - /// ### Known problems - /// This lint, as the other shadowing related lints, - /// currently only catches very simple patterns. - /// /// ### Example /// ```rust /// # let x = 1; @@ -52,10 +45,6 @@ /// because a value may be bound to different things depending on position in /// the code. /// - /// ### Known problems - /// This lint, as the other shadowing related lints, - /// currently only catches very simple patterns. - /// /// ### Example /// ```rust /// let x = 2; @@ -83,12 +72,6 @@ /// any place in the code. This can be alleviated by either giving more specific /// names to bindings or introducing more scopes to contain the bindings. /// - /// ### Known problems - /// This lint, as the other shadowing related lints, - /// currently only catches very simple patterns. Note that - /// `allow`/`warn`/`deny`/`forbid` attributes only work on the function level - /// for this lint. - /// /// ### Example /// ```rust /// # let y = 1; @@ -102,307 +85,151 @@ /// let w = z; // use different variable name /// ``` pub SHADOW_UNRELATED, - pedantic, + restriction, "rebinding a name without even using the original value" } -declare_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]); +#[derive(Default)] +pub(crate) struct Shadow { + bindings: Vec>>, +} + +impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]); impl<'tcx> LateLintPass<'tcx> for Shadow { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - _: FnKind<'tcx>, - decl: &'tcx FnDecl<'_>, - body: &'tcx Body<'_>, - _: Span, - _: HirId, - ) { - if in_external_macro(cx.sess(), body.value.span) { + fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { + let (id, ident) = match pat.kind { + PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident), + _ => return, + }; + if ident.span.from_expansion() || ident.span.is_dummy() { return; } - check_fn(cx, decl, body); - } -} + let HirId { owner, local_id } = id; -fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>) { - let mut bindings = Vec::with_capacity(decl.inputs.len()); - for arg in iter_input_pats(decl, body) { - if let PatKind::Binding(.., ident, _) = arg.pat.kind { - bindings.push((ident.name, ident.span)); + // get (or insert) the list of items for this owner and symbol + let data = self.bindings.last_mut().unwrap(); + let items_with_name = data.entry(ident.name).or_default(); + + // check other bindings with the same name, most recently seen first + for &prev in items_with_name.iter().rev() { + if prev == local_id { + // repeated binding in an `Or` pattern + return; + } + + if is_shadow(cx, owner, prev, local_id) { + let prev_hir_id = HirId { owner, local_id: prev }; + lint_shadow(cx, pat, prev_hir_id, ident.span); + // only lint against the "nearest" shadowed binding + break; + } + } + // store the binding + items_with_name.push(local_id); + } + + fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { + let hir = cx.tcx.hir(); + if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) { + self.bindings.push(FxHashMap::default()); } } - check_expr(cx, &body.value, &mut bindings); -} -fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>, bindings: &mut Vec<(Symbol, Span)>) { - let len = bindings.len(); - for stmt in block.stmts { - match stmt.kind { - StmtKind::Local(local) => check_local(cx, local, bindings), - StmtKind::Expr(e) | StmtKind::Semi(e) => check_expr(cx, e, bindings), - StmtKind::Item(..) => {}, + fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { + let hir = cx.tcx.hir(); + if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) { + self.bindings.pop(); } } - if let Some(o) = block.expr { - check_expr(cx, o, bindings); - } - bindings.truncate(len); } -fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &mut Vec<(Symbol, Span)>) { - if in_external_macro(cx.sess(), local.span) { - return; - } - if higher::is_from_for_desugar(local) { - return; - } - let Local { - pat, - ref ty, - ref init, +fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool { + let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id()); + let first_scope = scope_tree.var_scope(first); + let second_scope = scope_tree.var_scope(second); + scope_tree.is_subscope_of(second_scope, first_scope) +} + +fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) { + let (lint, msg) = match find_init(cx, pat.hir_id) { + Some(expr) if is_self_shadow(cx, pat, expr, shadowed) => { + let msg = format!( + "`{}` is shadowed by itself in `{}`", + snippet(cx, pat.span, "_"), + snippet(cx, expr.span, "..") + ); + (SHADOW_SAME, msg) + }, + Some(expr) if is_local_used(cx, expr, shadowed) => { + let msg = format!( + "`{}` is shadowed by `{}` which reuses the original value", + snippet(cx, pat.span, "_"), + snippet(cx, expr.span, "..") + ); + (SHADOW_REUSE, msg) + }, + _ => { + let msg = format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_")); + (SHADOW_UNRELATED, msg) + }, + }; + span_lint_and_note( + cx, + lint, span, - .. - } = *local; - if let Some(t) = *ty { - check_ty(cx, t, bindings); - } - if let Some(o) = *init { - check_expr(cx, o, bindings); - check_pat(cx, pat, Some(o), span, bindings); - } else { - check_pat(cx, pat, None, span, bindings); - } + &msg, + Some(cx.tcx.hir().span(shadowed)), + "previous binding is here", + ); } -fn is_binding(cx: &LateContext<'_>, pat_id: HirId) -> bool { - let var_ty = cx.typeck_results().node_type_opt(pat_id); - var_ty.map_or(false, |var_ty| !matches!(var_ty.kind(), ty::Adt(..))) -} - -fn check_pat<'tcx>( - cx: &LateContext<'tcx>, - pat: &'tcx Pat<'_>, - init: Option<&'tcx Expr<'_>>, - span: Span, - bindings: &mut Vec<(Symbol, Span)>, -) { - // TODO: match more stuff / destructuring - match pat.kind { - PatKind::Binding(.., ident, ref inner) => { - let name = ident.name; - if is_binding(cx, pat.hir_id) { - let mut new_binding = true; - for tup in bindings.iter_mut() { - if tup.0 == name { - lint_shadow(cx, name, span, pat.span, init, tup.1); - tup.1 = ident.span; - new_binding = false; - break; - } - } - if new_binding { - bindings.push((name, ident.span)); - } - } - if let Some(p) = *inner { - check_pat(cx, p, init, span, bindings); - } - }, - PatKind::Struct(_, pfields, _) => { - if let Some(init_struct) = init { - if let ExprKind::Struct(_, efields, _) = init_struct.kind { - for field in pfields { - let name = field.ident.name; - let efield = efields - .iter() - .find_map(|f| if f.ident.name == name { Some(&*f.expr) } else { None }); - check_pat(cx, field.pat, efield, span, bindings); - } - } else { - for field in pfields { - check_pat(cx, field.pat, init, span, bindings); - } - } - } else { - for field in pfields { - check_pat(cx, field.pat, None, span, bindings); - } - } - }, - PatKind::Tuple(inner, _) => { - if let Some(init_tup) = init { - if let ExprKind::Tup(tup) = init_tup.kind { - for (i, p) in inner.iter().enumerate() { - check_pat(cx, p, Some(&tup[i]), p.span, bindings); - } - } else { - for p in inner { - check_pat(cx, p, init, span, bindings); - } - } - } else { - for p in inner { - check_pat(cx, p, None, span, bindings); - } - } - }, - PatKind::Box(inner) => { - if let Some(initp) = init { - if let ExprKind::Box(inner_init) = initp.kind { - check_pat(cx, inner, Some(inner_init), span, bindings); - } else { - check_pat(cx, inner, init, span, bindings); - } - } else { - check_pat(cx, inner, init, span, bindings); - } - }, - PatKind::Ref(inner, _) => check_pat(cx, inner, init, span, bindings), - // PatVec(Vec>, Option>, Vec>), - _ => (), +/// Returns true if the expression is a simple transformation of a local binding such as `&x` +fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_id: HirId) -> bool { + let hir = cx.tcx.hir(); + let is_direct_binding = hir + .parent_iter(pat.hir_id) + .map_while(|(_id, node)| match node { + Node::Pat(pat) => Some(pat), + _ => None, + }) + .all(|pat| matches!(pat.kind, PatKind::Ref(..) | PatKind::Or(_))); + if !is_direct_binding { + return false; } -} - -fn lint_shadow<'tcx>( - cx: &LateContext<'tcx>, - name: Symbol, - span: Span, - pattern_span: Span, - init: Option<&'tcx Expr<'_>>, - prev_span: Span, -) { - if let Some(expr) = init { - if is_self_shadow(name, expr) { - span_lint_and_then( - cx, - SHADOW_SAME, - span, - &format!( - "`{}` is shadowed by itself in `{}`", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, "..") - ), - |diag| { - diag.span_note(prev_span, "previous binding is here"); + loop { + expr = match expr.kind { + ExprKind::Box(e) + | ExprKind::AddrOf(_, _, e) + | ExprKind::Block( + &Block { + stmts: [], + expr: Some(e), + .. }, - ); - } else if contains_name(name, expr) { - span_lint_and_then( - cx, - SHADOW_REUSE, - pattern_span, - &format!( - "`{}` is shadowed by `{}` which reuses the original value", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, "..") - ), - |diag| { - diag.span_note(expr.span, "initialization happens here"); - diag.span_note(prev_span, "previous binding is here"); - }, - ); - } else { - span_lint_and_then( - cx, - SHADOW_UNRELATED, - pattern_span, - &format!("`{}` is being shadowed", snippet(cx, pattern_span, "_")), - |diag| { - diag.span_note(expr.span, "initialization happens here"); - diag.span_note(prev_span, "previous binding is here"); - }, - ); + _, + ) + | ExprKind::Unary(UnOp::Deref, e) => e, + ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id), + _ => break false, } - } else { - span_lint_and_then( - cx, - SHADOW_UNRELATED, - span, - &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")), - |diag| { - diag.span_note(prev_span, "previous binding is here"); + } +} + +/// Finds the "init" expression for a pattern: `let = ;` or +/// `match { .., => .., .. }` +fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { + for (_, node) in cx.tcx.hir().parent_iter(hir_id) { + let init = match node { + Node::Arm(_) | Node::Pat(_) => continue, + Node::Expr(expr) => match expr.kind { + ExprKind::Match(e, _, _) => Some(e), + _ => None, }, - ); + Node::Local(local) => local.init, + _ => None, + }; + return init; } -} - -fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut Vec<(Symbol, Span)>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - match expr.kind { - ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => { - check_expr(cx, e, bindings); - }, - ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings), - // ExprKind::Call - // ExprKind::MethodCall - ExprKind::Array(v) | ExprKind::Tup(v) => { - for e in v { - check_expr(cx, e, bindings); - } - }, - ExprKind::If(cond, then, ref otherwise) => { - check_expr(cx, cond, bindings); - check_expr(cx, then, bindings); - if let Some(o) = *otherwise { - check_expr(cx, o, bindings); - } - }, - ExprKind::Match(init, arms, _) => { - check_expr(cx, init, bindings); - let len = bindings.len(); - for arm in arms { - check_pat(cx, arm.pat, Some(init), arm.pat.span, bindings); - // This is ugly, but needed to get the right type - if let Some(ref guard) = arm.guard { - match guard { - Guard::If(if_expr) => check_expr(cx, if_expr, bindings), - Guard::IfLet(guard_pat, guard_expr) => { - check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings); - check_expr(cx, guard_expr, bindings); - }, - } - } - check_expr(cx, arm.body, bindings); - bindings.truncate(len); - } - }, - _ => (), - } -} - -fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(Symbol, Span)>) { - match ty.kind { - TyKind::Slice(sty) => check_ty(cx, sty, bindings), - TyKind::Array(fty, ref anon_const) => { - check_ty(cx, fty, bindings); - check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings); - }, - TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings), - TyKind::Tup(tup) => { - for t in tup { - check_ty(cx, t, bindings); - } - }, - TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings), - _ => (), - } -} - -fn is_self_shadow(name: Symbol, expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Box(inner) | ExprKind::AddrOf(_, _, inner) => is_self_shadow(name, inner), - ExprKind::Block(block, _) => { - block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e)) - }, - ExprKind::Unary(op, inner) => (UnOp::Deref == op) && is_self_shadow(name, inner), - ExprKind::Path(QPath::Resolved(_, path)) => path_eq_name(name, path), - _ => false, - } -} - -fn path_eq_name(name: Symbol, path: &Path<'_>) -> bool { - !path.is_global() && path.segments.len() == 1 && path.segments[0].ident.name == name + None } diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index a67fa792205..ef80663d1da 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -49,8 +49,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let mut const_eval_context = constant_context(cx, cx.typeck_results()); if_chain! { if let ExprKind::Path(ref _qpath) = arg.kind; - let x = const_eval_context.expr(arg); - if let Some(Constant::RawPtr(0)) = x; + if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg); + if x == 0; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/types/option_option.rs b/clippy_lints/src/types/option_option.rs index 4f50284e941..903e62995c6 100644 --- a/clippy_lints/src/types/option_option.rs +++ b/clippy_lints/src/types/option_option.rs @@ -7,9 +7,7 @@ use super::OPTION_OPTION; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if cx.tcx.is_diagnostic_item(sym::Option, def_id) - && is_ty_param_diagnostic_item(cx, qpath, sym::Option).is_some() - { + if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_ty_param_diagnostic_item(cx, qpath, sym::Option).is_some() { span_lint( cx, OPTION_OPTION, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 1e0447239be..6cbada4c150 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -284,6 +284,10 @@ pub(crate) fn get_configuration_metadata() -> Vec { /// /// The list of unicode scripts allowed to be used in the scope. (allowed_scripts: Vec = vec!["Latin".to_string()]), + /// Lint: NON_SEND_FIELDS_IN_SEND_TY. + /// + /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. + (enable_raw_pointer_heuristic_for_send: bool = true), } /// Search for the configuration file. diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 59c40050522..9f9edbf258a 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -8,7 +8,7 @@ paths, SpanlessEq, }; use if_chain::if_chain; -use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; +use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId}; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -18,8 +18,8 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{ - BinOpKind, Block, Crate, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, - TyKind, UnOp, + BinOpKind, Block, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, TyKind, + UnOp, }; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -317,7 +317,7 @@ declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]); impl EarlyLintPass for ClippyLintsInternal { - fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") { if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind { if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") { @@ -412,7 +412,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { } } - fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) { + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) { return; } @@ -907,7 +907,7 @@ pub struct InterningDefinedSymbol { impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]); impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { - fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { + fn check_crate(&mut self, cx: &LateContext<'_>) { if !self.symbol_map.is_empty() { return; } diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index b29ced28ac4..e0746ce4d81 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -32,7 +32,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // check for instances of 0.0/0.0 if_chain! { if let ExprKind::Binary(ref op, left, right) = expr.kind; - if let BinOpKind::Div = op.node; + if op.node == BinOpKind::Div; // TODO - constant_simple does not fold many operations involving floats. // That's probably fine for this lint - it's pretty unlikely that someone would // do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too. diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 00123fdba24..c47aa9170e5 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -509,7 +509,6 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { } /// Gets the definition associated to a path. -#[allow(clippy::shadow_unrelated)] // false positive #6563 pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { macro_rules! try_res { ($e:expr) => { @@ -683,7 +682,17 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { _ => false, }, ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), - ExprKind::Repeat(x, _) => is_default_equivalent(cx, x), + ExprKind::Repeat(x, y) => if_chain! { + if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind; + if let LitKind::Int(v, _) = const_lit.node; + if v <= 32 && is_default_equivalent(cx, x); + then { + true + } + else { + false + } + }, ExprKind::Call(repl_func, _) => if_chain! { if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); @@ -1498,7 +1507,7 @@ fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if let ExprKind::Match(_, arms, ref source) = expr.kind { // desugared from a `?` operator - if let MatchSource::TryDesugar = *source { + if *source == MatchSource::TryDesugar { return Some(expr); } diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index 4a28c7dd9a0..68dd1b29845 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -74,7 +74,7 @@ pub fn new(lit: &'a str, suffix: Option<&'a str>, float: bool) -> Self { }; // Grab part of the literal after prefix, if present. - let (prefix, mut sans_prefix) = if let Radix::Decimal = radix { + let (prefix, mut sans_prefix) = if radix == Radix::Decimal { (None, lit) } else { let (p, s) = lit.split_at(2); @@ -157,8 +157,10 @@ pub fn format(&self) -> String { } if let Some((separator, exponent)) = self.exponent { - output.push_str(separator); - Self::group_digits(&mut output, exponent, group_size, true, false); + if exponent != "0" { + output.push_str(separator); + Self::group_digits(&mut output, exponent, group_size, true, false); + } } if let Some(suffix) = self.suffix { @@ -177,6 +179,13 @@ pub fn group_digits(output: &mut String, input: &str, group_size: usize, partial let mut digits = input.chars().filter(|&c| c != '_'); + // The exponent may have a sign, output it early, otherwise it will be + // treated as a digit + if digits.clone().next() == Some('-') { + let _ = digits.next(); + output.push('-'); + } + let first_group_size; if partial_group_first { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 5e0182ec1b8..e43c5756021 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -129,11 +129,17 @@ pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"]; pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"]; pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"]; +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"]; +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; +#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; /// Preferably use the diagnostic item `sym::Result` where possible pub const RESULT: [&str; 3] = ["core", "result", "Result"]; diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index ab05a0b4238..5b0efb1fd71 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -311,7 +311,7 @@ pub fn maybe_par(self) -> Self { /// Return `true` if `sugg` is enclosed in parenthesis. fn has_enclosing_paren(sugg: impl AsRef) -> bool { let mut chars = sugg.as_ref().chars(); - if let Some('(') = chars.next() { + if chars.next() == Some('(') { let mut depth = 1; for c in &mut chars { if c == '(' { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 96cb8a4dae4..6ebe1a0028a 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -224,15 +224,15 @@ fn is_normalizable_helper<'tcx>( result } -/// Returns true iff the given type is a non aggregate primitive (a bool or char, any integer or -/// floating-point number type). For checking aggregation of primitive types (e.g. tuples and slices -/// of primitive type) see `is_recursively_primitive_type` +/// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any +/// integer or floating-point number type). For checking aggregation of primitive types (e.g. +/// tuples and slices of primitive type) see `is_recursively_primitive_type` pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool { matches!(ty.kind(), ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_)) } -/// Returns true iff the given type is a primitive (a bool or char, any integer or floating-point -/// number type, a str, or an array, slice, or tuple of those types). +/// Returns `true` if the given type is a primitive (a `bool` or `char`, any integer or +/// floating-point number type, a `str`, or an array, slice, or tuple of those types). pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index 098ec175fe2..34206b5ae2b 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -65,7 +65,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { - if let ty::BorrowKind::MutBorrow = bk { + if bk == ty::BorrowKind::MutBorrow { self.update(cmt); } } diff --git a/rust-toolchain b/rust-toolchain index 660401ff28c..f98819303e6 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-09-28" +channel = "nightly-2021-10-07" components = ["llvm-tools-preview", "rustc-dev", "rust-src"] diff --git a/tests/compile-test.rs b/tests/compile-test.rs index d7596f6ff0c..e8b1640c869 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -92,7 +92,9 @@ fn extern_flags() -> String { .collect(); assert!( not_found.is_empty(), - "dependencies not found in depinfo: {:?}", + "dependencies not found in depinfo: {:?}\n\ + help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\ + help: Try adding to dev-dependencies in Cargo.toml", not_found ); crates diff --git a/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml b/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml new file mode 100644 index 00000000000..a942709d14a --- /dev/null +++ b/tests/ui-toml/strict_non_send_fields_in_send_ty/clippy.toml @@ -0,0 +1 @@ +enable-raw-pointer-heuristic-for-send = false diff --git a/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs new file mode 100644 index 00000000000..90c2439dc34 --- /dev/null +++ b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs @@ -0,0 +1,43 @@ +#![warn(clippy::non_send_fields_in_send_ty)] +#![feature(extern_types)] + +use std::rc::Rc; + +// Basic tests should not be affected +pub struct NoGeneric { + rc_is_not_send: Rc, +} + +unsafe impl Send for NoGeneric {} + +pub struct MultiField { + field1: T, + field2: T, + field3: T, +} + +unsafe impl Send for MultiField {} + +pub enum MyOption { + MySome(T), + MyNone, +} + +unsafe impl Send for MyOption {} + +// All fields are disallowed when raw pointer heuristic is off +extern "C" { + type NonSend; +} + +pub struct HeuristicTest { + field1: Vec<*const NonSend>, + field2: [*const NonSend; 3], + field3: (*const NonSend, *const NonSend, *const NonSend), + field4: (*const NonSend, Rc), + field5: Vec>, +} + +unsafe impl Send for HeuristicTest {} + +fn main() {} diff --git a/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr new file mode 100644 index 00000000000..b07f9dd3df3 --- /dev/null +++ b/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr @@ -0,0 +1,91 @@ +error: this implementation is unsound, as some fields in `NoGeneric` are `!Send` + --> $DIR/test.rs:11:1 + | +LL | unsafe impl Send for NoGeneric {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` +note: the type of field `rc_is_not_send` is `!Send` + --> $DIR/test.rs:8:5 + | +LL | rc_is_not_send: Rc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: this implementation is unsound, as some fields in `MultiField` are `!Send` + --> $DIR/test.rs:19:1 + | +LL | unsafe impl Send for MultiField {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/test.rs:14:5 + | +LL | field1: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field2` is `!Send` + --> $DIR/test.rs:15:5 + | +LL | field2: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field3` is `!Send` + --> $DIR/test.rs:16:5 + | +LL | field3: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `MyOption` are `!Send` + --> $DIR/test.rs:26:1 + | +LL | unsafe impl Send for MyOption {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `0` is `!Send` + --> $DIR/test.rs:22:12 + | +LL | MySome(T), + | ^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send` + --> $DIR/test.rs:41:1 + | +LL | unsafe impl Send for HeuristicTest {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/test.rs:34:5 + | +LL | field1: Vec<*const NonSend>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field2` is `!Send` + --> $DIR/test.rs:35:5 + | +LL | field2: [*const NonSend; 3], + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field3` is `!Send` + --> $DIR/test.rs:36:5 + | +LL | field3: (*const NonSend, *const NonSend, *const NonSend), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field4` is `!Send` + --> $DIR/test.rs:37:5 + | +LL | field4: (*const NonSend, Rc), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` +note: the type of field `field5` is `!Send` + --> $DIR/test.rs:38:5 + | +LL | field5: Vec>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: aborting due to 4 previous errors + 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 e0029ebeb27..97bab1308aa 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index 2ae4d613507..ccdbd34f7ec 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -1,5 +1,5 @@ #[warn(clippy::approx_constant)] -#[allow(unused, clippy::shadow_unrelated, clippy::similar_names)] +#[allow(clippy::similar_names)] fn main() { let my_e = 2.7182; let almost_e = 2.718; diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.rs b/tests/ui/branches_sharing_code/shared_at_bottom.rs index ce2040bdeb8..12f550d9c9a 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.rs +++ b/tests/ui/branches_sharing_code/shared_at_bottom.rs @@ -1,4 +1,4 @@ -#![allow(dead_code)] +#![allow(dead_code, clippy::equatable_if_let)] #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] // This tests the branches_sharing_code lint at the end of blocks diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index c69a46f0a77..bb6c4c0703d 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 1359c7eb627..6d4f688db8c 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index e4c088bf6f0..5b0e4a473c4 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index d6cf01c8319..cd231a5d7ab 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(clippy::assertions_on_constants)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_match.rs b/tests/ui/collapsible_match.rs index 4ce365cc764..603ae7dc9eb 100644 --- a/tests/ui/collapsible_match.rs +++ b/tests/ui/collapsible_match.rs @@ -1,5 +1,10 @@ #![warn(clippy::collapsible_match)] -#![allow(clippy::needless_return, clippy::no_effect, clippy::single_match)] +#![allow( + clippy::needless_return, + clippy::no_effect, + clippy::single_match, + clippy::equatable_if_let +)] fn lint_cases(opt_opt: Option>, res_opt: Result, String>) { // match without block diff --git a/tests/ui/collapsible_match.stderr b/tests/ui/collapsible_match.stderr index c119570e8ab..5f18b693502 100644 --- a/tests/ui/collapsible_match.stderr +++ b/tests/ui/collapsible_match.stderr @@ -1,5 +1,5 @@ error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:7:20 + --> $DIR/collapsible_match.rs:12:20 | LL | Ok(val) => match val { | ____________________^ @@ -10,7 +10,7 @@ LL | | }, | = note: `-D clippy::collapsible-match` implied by `-D warnings` help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:7:12 + --> $DIR/collapsible_match.rs:12:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -18,7 +18,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:16:20 + --> $DIR/collapsible_match.rs:21:20 | LL | Ok(val) => match val { | ____________________^ @@ -28,7 +28,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:16:12 + --> $DIR/collapsible_match.rs:21:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -36,7 +36,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:25:9 + --> $DIR/collapsible_match.rs:30:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -44,7 +44,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:24:15 + --> $DIR/collapsible_match.rs:29:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -52,7 +52,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:32:9 + --> $DIR/collapsible_match.rs:37:9 | LL | / if let Some(n) = val { LL | | take(n); @@ -62,7 +62,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:31:15 + --> $DIR/collapsible_match.rs:36:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -70,7 +70,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:43:9 + --> $DIR/collapsible_match.rs:48:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -79,7 +79,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:42:15 + --> $DIR/collapsible_match.rs:47:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -88,7 +88,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:52:13 + --> $DIR/collapsible_match.rs:57:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -96,7 +96,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:51:12 + --> $DIR/collapsible_match.rs:56:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -104,7 +104,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> $DIR/collapsible_match.rs:61:9 + --> $DIR/collapsible_match.rs:66:9 | LL | / match val { LL | | Some(n) => foo(n), @@ -113,7 +113,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:60:15 + --> $DIR/collapsible_match.rs:65:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -122,7 +122,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:72:13 + --> $DIR/collapsible_match.rs:77:13 | LL | / if let Some(n) = val { LL | | take(n); @@ -132,7 +132,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:71:12 + --> $DIR/collapsible_match.rs:76:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -140,7 +140,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:83:20 + --> $DIR/collapsible_match.rs:88:20 | LL | Ok(val) => match val { | ____________________^ @@ -150,7 +150,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:83:12 + --> $DIR/collapsible_match.rs:88:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -158,7 +158,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> $DIR/collapsible_match.rs:92:22 + --> $DIR/collapsible_match.rs:97:22 | LL | Some(val) => match val { | ______________________^ @@ -168,7 +168,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> $DIR/collapsible_match.rs:92:14 + --> $DIR/collapsible_match.rs:97:14 | LL | Some(val) => match val { | ^^^ replace this binding diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 7d62e315da2..02c49aa0d7c 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::blacklisted_name, clippy::equatable_if_let)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 1ed78547a60..156c88e2e45 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -3,6 +3,7 @@ #![feature(no_core, lang_items, start)] #![no_core] +#![allow(clippy::missing_safety_doc)] #[link(name = "c")] extern "C" {} diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index 6210d7c6cfd..40d355e9a2e 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/def_id_nocore.rs:27:19 + --> $DIR/def_id_nocore.rs:28:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index ebbc0c77e32..a6412004726 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -207,4 +207,37 @@ fn default() -> Self { } } +pub struct RepeatDefault1 { + a: [i8; 32], +} + +impl Default for RepeatDefault1 { + fn default() -> Self { + RepeatDefault1 { a: [0; 32] } + } +} + +pub struct RepeatDefault2 { + a: [i8; 33], +} + +impl Default for RepeatDefault2 { + fn default() -> Self { + RepeatDefault2 { a: [0; 33] } + } +} + +// https://github.com/rust-lang/rust-clippy/issues/7753 + +pub enum IntOrString { + Int(i32), + String(String), +} + +impl Default for IntOrString { + fn default() -> Self { + IntOrString::Int(0) + } +} + fn main() {} diff --git a/tests/ui/derivable_impls.stderr b/tests/ui/derivable_impls.stderr index 4ed64fade02..49fb471a219 100644 --- a/tests/ui/derivable_impls.stderr +++ b/tests/ui/derivable_impls.stderr @@ -73,5 +73,17 @@ LL | | } | = help: try annotating `WithoutSelfParan` with `#[derive(Default)]` -error: aborting due to 6 previous errors +error: this `impl` can be derived + --> $DIR/derivable_impls.rs:214:1 + | +LL | / impl Default for RepeatDefault1 { +LL | | fn default() -> Self { +LL | | RepeatDefault1 { a: [0; 32] } +LL | | } +LL | | } + | |_^ + | + = help: try annotating `RepeatDefault1` with `#[derive(Default)]` + +error: aborting due to 7 previous errors diff --git a/tests/ui/doc/doc.rs b/tests/ui/doc/doc.rs index 8b0c0f304fc..342208e52b8 100644 --- a/tests/ui/doc/doc.rs +++ b/tests/ui/doc/doc.rs @@ -203,6 +203,11 @@ fn issue_2343() {} /// __|_ _|__||_| fn pulldown_cmark_crash() {} +/// This should not lint +/// (regression test for #7758) +/// [plain text][path::to::item] +fn intra_doc_link() {} + // issue #7033 - generic_const_exprs ICE struct S where [(); N.checked_next_power_of_two().unwrap()]: { diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index 484aa72d59a..8f823f1672b 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -34,16 +34,25 @@ pub unsafe fn republished() { pub use private_mod::republished; -pub trait UnsafeTrait { +pub trait SafeTraitUnsafeMethods { unsafe fn woefully_underdocumented(self); /// # Safety unsafe fn at_least_somewhat_documented(self); } +pub unsafe trait UnsafeTrait { + fn method(); +} + +/// # Safety +pub unsafe trait DocumentedUnsafeTrait { + fn method2(); +} + pub struct Struct; -impl UnsafeTrait for Struct { +impl SafeTraitUnsafeMethods for Struct { unsafe fn woefully_underdocumented(self) { // all is well } @@ -53,6 +62,14 @@ unsafe fn at_least_somewhat_documented(self) { } } +unsafe impl UnsafeTrait for Struct { + fn method() {} +} + +unsafe impl DocumentedUnsafeTrait for Struct { + fn method2() {} +} + impl Struct { pub unsafe fn more_undocumented_unsafe() -> Self { unimplemented!(); diff --git a/tests/ui/doc_unsafe.stderr b/tests/ui/doc_unsafe.stderr index 73b53f3431e..34ca37a6efd 100644 --- a/tests/ui/doc_unsafe.stderr +++ b/tests/ui/doc_unsafe.stderr @@ -22,8 +22,16 @@ error: unsafe function's docs miss `# Safety` section LL | unsafe fn woefully_underdocumented(self); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: docs for unsafe trait missing `# Safety` section + --> $DIR/doc_unsafe.rs:44:1 + | +LL | / pub unsafe trait UnsafeTrait { +LL | | fn method(); +LL | | } + | |_^ + error: unsafe function's docs miss `# Safety` section - --> $DIR/doc_unsafe.rs:57:5 + --> $DIR/doc_unsafe.rs:74:5 | LL | / pub unsafe fn more_undocumented_unsafe() -> Self { LL | | unimplemented!(); @@ -31,7 +39,7 @@ LL | | } | |_____^ error: unsafe function's docs miss `# Safety` section - --> $DIR/doc_unsafe.rs:73:9 + --> $DIR/doc_unsafe.rs:90:9 | LL | / pub unsafe fn whee() { LL | | unimplemented!() @@ -43,5 +51,5 @@ LL | very_unsafe!(); | = note: this error originates in the macro `very_unsafe` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed new file mode 100644 index 00000000000..ba72cc237b4 --- /dev/null +++ b/tests/ui/equatable_if_let.fixed @@ -0,0 +1,69 @@ +// run-rustfix + +#![allow(unused_variables, dead_code)] +#![warn(clippy::equatable_if_let)] + +use std::cmp::Ordering; + +#[derive(PartialEq)] +enum Enum { + TupleVariant(i32, u64), + RecordVariant { a: i64, b: u32 }, + UnitVariant, + Recursive(Struct), +} + +#[derive(PartialEq)] +struct Struct { + a: i32, + b: bool, +} + +enum NotPartialEq { + A, + B, +} + +enum NotStructuralEq { + A, + B, +} + +impl PartialEq for NotStructuralEq { + fn eq(&self, _: &NotStructuralEq) -> bool { + false + } +} + +fn main() { + let a = 2; + let b = 3; + let c = Some(2); + let d = Struct { a: 2, b: false }; + let e = Enum::UnitVariant; + let f = NotPartialEq::A; + let g = NotStructuralEq::A; + + // true + + if a == 2 {} + if a.cmp(&b) == Ordering::Greater {} + if c == Some(2) {} + if d == (Struct { a: 2, b: false }) {} + if e == Enum::TupleVariant(32, 64) {} + if e == (Enum::RecordVariant { a: 64, b: 32 }) {} + if e == Enum::UnitVariant {} + if (e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false }) {} + + // false + + if let 2 | 3 = a {} + if let x @ 2 = a {} + if let Some(3 | 4) = c {} + if let Struct { a, b: false } = d {} + if let Struct { a: 2, b: x } = d {} + if let NotPartialEq::A = f {} + if g == NotStructuralEq::A {} + if let Some(NotPartialEq::A) = Some(f) {} + if Some(g) == Some(NotStructuralEq::A) {} +} diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs new file mode 100644 index 00000000000..12526ca193d --- /dev/null +++ b/tests/ui/equatable_if_let.rs @@ -0,0 +1,69 @@ +// run-rustfix + +#![allow(unused_variables, dead_code)] +#![warn(clippy::equatable_if_let)] + +use std::cmp::Ordering; + +#[derive(PartialEq)] +enum Enum { + TupleVariant(i32, u64), + RecordVariant { a: i64, b: u32 }, + UnitVariant, + Recursive(Struct), +} + +#[derive(PartialEq)] +struct Struct { + a: i32, + b: bool, +} + +enum NotPartialEq { + A, + B, +} + +enum NotStructuralEq { + A, + B, +} + +impl PartialEq for NotStructuralEq { + fn eq(&self, _: &NotStructuralEq) -> bool { + false + } +} + +fn main() { + let a = 2; + let b = 3; + let c = Some(2); + let d = Struct { a: 2, b: false }; + let e = Enum::UnitVariant; + let f = NotPartialEq::A; + let g = NotStructuralEq::A; + + // true + + if let 2 = a {} + if let Ordering::Greater = a.cmp(&b) {} + if let Some(2) = c {} + if let Struct { a: 2, b: false } = d {} + if let Enum::TupleVariant(32, 64) = e {} + if let Enum::RecordVariant { a: 64, b: 32 } = e {} + if let Enum::UnitVariant = e {} + if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + + // false + + if let 2 | 3 = a {} + if let x @ 2 = a {} + if let Some(3 | 4) = c {} + if let Struct { a, b: false } = d {} + if let Struct { a: 2, b: x } = d {} + if let NotPartialEq::A = f {} + if let NotStructuralEq::A = g {} + if let Some(NotPartialEq::A) = Some(f) {} + if let Some(NotStructuralEq::A) = Some(g) {} +} diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr new file mode 100644 index 00000000000..79ef919384d --- /dev/null +++ b/tests/ui/equatable_if_let.stderr @@ -0,0 +1,64 @@ +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:49:8 + | +LL | if let 2 = a {} + | ^^^^^^^^^ help: try: `a == 2` + | + = note: `-D clippy::equatable-if-let` implied by `-D warnings` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:50:8 + | +LL | if let Ordering::Greater = a.cmp(&b) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:51:8 + | +LL | if let Some(2) = c {} + | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:52:8 + | +LL | if let Struct { a: 2, b: false } = d {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:53:8 + | +LL | if let Enum::TupleVariant(32, 64) = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:54:8 + | +LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:55:8 + | +LL | if let Enum::UnitVariant = e {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:56:8 + | +LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:66:8 + | +LL | if let NotStructuralEq::A = g {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:68:8 + | +LL | if let Some(NotStructuralEq::A) = Some(g) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index 90376620a9f..b74bda182be 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -60,4 +60,10 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; + + // issue #7744 + let _ = 2.225_073_858_507_201e-308_f64; + + // issue #7745 + let _ = 0_f64; } diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index ce4722a90f9..6e84a71f24c 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -60,4 +60,10 @@ fn main() { // issue #2840 let num = 0.000_000_000_01e-10f64; + + // issue #7744 + let _ = 2.225_073_858_507_201_1e-308_f64; + + // issue #7745 + let _ = 1.000_000_000_000_001e-324_f64; } diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index e59c20c30b4..42d9d4de193 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -78,5 +78,17 @@ error: float has excessive precision LL | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` -error: aborting due to 13 previous errors +error: float has excessive precision + --> $DIR/excessive_precision.rs:65:13 + | +LL | let _ = 2.225_073_858_507_201_1e-308_f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `2.225_073_858_507_201e-308_f64` + +error: float has excessive precision + --> $DIR/excessive_precision.rs:68:13 + | +LL | let _ = 1.000_000_000_000_001e-324_f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64` + +error: aborting due to 15 previous errors diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index f0e4835415f..f373e905d05 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -23,12 +23,7 @@ impl Unrelated { clippy::iter_next_loop, clippy::for_kv_map )] -#[allow( - clippy::linkedlist, - clippy::shadow_unrelated, - clippy::unnecessary_mut_passed, - clippy::similar_names -)] +#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] #[allow(unused_variables)] fn main() { let mut vec = vec![1, 2, 3, 4]; diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 1edef175fb9..3814583bb6e 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -23,12 +23,7 @@ fn iter(&self) -> std::slice::Iter { clippy::iter_next_loop, clippy::for_kv_map )] -#[allow( - clippy::linkedlist, - clippy::shadow_unrelated, - clippy::unnecessary_mut_passed, - clippy::similar_names -)] +#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] #[allow(unused_variables)] fn main() { let mut vec = vec![1, 2, 3, 4]; diff --git a/tests/ui/for_loop_fixable.stderr b/tests/ui/for_loop_fixable.stderr index ddfe66d675f..009dbe1a0bf 100644 --- a/tests/ui/for_loop_fixable.stderr +++ b/tests/ui/for_loop_fixable.stderr @@ -1,5 +1,5 @@ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:43:15 + --> $DIR/for_loop_fixable.rs:38:15 | LL | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -7,13 +7,13 @@ LL | for _v in vec.iter() {} = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:45:15 + --> $DIR/for_loop_fixable.rs:40:15 | LL | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:48:15 + --> $DIR/for_loop_fixable.rs:43:15 | LL | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` @@ -21,73 +21,73 @@ LL | for _v in out_vec.into_iter() {} = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:53:15 + --> $DIR/for_loop_fixable.rs:48:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:57:15 + --> $DIR/for_loop_fixable.rs:52:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:62:15 + --> $DIR/for_loop_fixable.rs:57:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:65:15 + --> $DIR/for_loop_fixable.rs:60:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:68:15 + --> $DIR/for_loop_fixable.rs:63:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:71:15 + --> $DIR/for_loop_fixable.rs:66:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:74:15 + --> $DIR/for_loop_fixable.rs:69:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:77:15 + --> $DIR/for_loop_fixable.rs:72:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:80:15 + --> $DIR/for_loop_fixable.rs:75:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:255:18 + --> $DIR/for_loop_fixable.rs:250:18 | LL | for i in iterator.into_iter() { | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:275:18 + --> $DIR/for_loop_fixable.rs:270:18 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:277:18 + --> $DIR/for_loop_fixable.rs:272:18 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` diff --git a/tests/ui/for_loop_unfixable.rs b/tests/ui/for_loop_unfixable.rs index e73536052f0..efcaffce24e 100644 --- a/tests/ui/for_loop_unfixable.rs +++ b/tests/ui/for_loop_unfixable.rs @@ -7,14 +7,7 @@ clippy::iter_next_loop, clippy::for_kv_map )] -#[allow( - clippy::linkedlist, - clippy::shadow_unrelated, - clippy::unnecessary_mut_passed, - clippy::similar_names, - unused, - dead_code -)] +#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] fn main() { let vec = vec![1, 2, 3, 4]; diff --git a/tests/ui/for_loop_unfixable.stderr b/tests/ui/for_loop_unfixable.stderr index 1c9287b6acb..f769b4bdc94 100644 --- a/tests/ui/for_loop_unfixable.stderr +++ b/tests/ui/for_loop_unfixable.stderr @@ -1,5 +1,5 @@ error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop_unfixable.rs:21:15 + --> $DIR/for_loop_unfixable.rs:14:15 | LL | for _v in vec.iter().next() {} | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index e4dc5b647df..69189d9e0c0 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -2,6 +2,7 @@ #![allow( clippy::blacklisted_name, clippy::collapsible_else_if, + clippy::equatable_if_let, clippy::collapsible_if, clippy::ifs_same_cond, clippy::needless_return, diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index 6524be0af85..cac788f859d 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -1,5 +1,5 @@ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:13:13 + --> $DIR/if_same_then_else2.rs:14:13 | LL | if true { | _____________^ @@ -13,7 +13,7 @@ LL | | } else { | = note: `-D clippy::if-same-then-else` implied by `-D warnings` note: same as this - --> $DIR/if_same_then_else2.rs:22:12 + --> $DIR/if_same_then_else2.rs:23:12 | LL | } else { | ____________^ @@ -26,7 +26,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:34:13 + --> $DIR/if_same_then_else2.rs:35:13 | LL | if true { | _____________^ @@ -35,7 +35,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:36:12 + --> $DIR/if_same_then_else2.rs:37:12 | LL | } else { | ____________^ @@ -45,7 +45,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:41:13 + --> $DIR/if_same_then_else2.rs:42:13 | LL | if true { | _____________^ @@ -54,7 +54,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:43:12 + --> $DIR/if_same_then_else2.rs:44:12 | LL | } else { | ____________^ @@ -64,7 +64,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:91:21 + --> $DIR/if_same_then_else2.rs:92:21 | LL | let _ = if true { | _____________________^ @@ -73,7 +73,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:93:12 + --> $DIR/if_same_then_else2.rs:94:12 | LL | } else { | ____________^ @@ -83,7 +83,7 @@ LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:98:13 + --> $DIR/if_same_then_else2.rs:99:13 | LL | if true { | _____________^ @@ -92,7 +92,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:100:12 + --> $DIR/if_same_then_else2.rs:101:12 | LL | } else { | ____________^ @@ -102,7 +102,7 @@ LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:122:20 + --> $DIR/if_same_then_else2.rs:123:20 | LL | } else if true { | ____________________^ @@ -112,7 +112,7 @@ LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:125:12 + --> $DIR/if_same_then_else2.rs:126:12 | LL | } else { | ____________^ diff --git a/tests/ui/if_then_panic.fixed b/tests/ui/if_then_panic.fixed index fc57ae0dfa5..0998f8ffa9d 100644 --- a/tests/ui/if_then_panic.fixed +++ b/tests/ui/if_then_panic.fixed @@ -31,4 +31,10 @@ fn main() { } else { println!("qwq"); } + let b = vec![1, 2, 3]; + assert!(!b.is_empty(), "panic1"); + assert!(!(b.is_empty() && a.is_empty()), "panic2"); + assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + assert!(!(b.is_empty() || a.is_empty()), "panic4"); + assert!(!(a.is_empty() || !b.is_empty()), "panic5"); } diff --git a/tests/ui/if_then_panic.rs b/tests/ui/if_then_panic.rs index d1ac93d8d41..10433c8d54f 100644 --- a/tests/ui/if_then_panic.rs +++ b/tests/ui/if_then_panic.rs @@ -35,4 +35,20 @@ fn main() { } else { println!("qwq"); } + let b = vec![1, 2, 3]; + if b.is_empty() { + panic!("panic1"); + } + if b.is_empty() && a.is_empty() { + panic!("panic2"); + } + if a.is_empty() && !b.is_empty() { + panic!("panic3"); + } + if b.is_empty() || a.is_empty() { + panic!("panic4"); + } + if a.is_empty() || !b.is_empty() { + panic!("panic5"); + } } diff --git a/tests/ui/if_then_panic.stderr b/tests/ui/if_then_panic.stderr index b92c9bdf674..5bb62f87566 100644 --- a/tests/ui/if_then_panic.stderr +++ b/tests/ui/if_then_panic.stderr @@ -16,5 +16,45 @@ LL | | panic!("qwqwq"); LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` -error: aborting due to 2 previous errors +error: only a `panic!` in `if`-then statement + --> $DIR/if_then_panic.rs:39:5 + | +LL | / if b.is_empty() { +LL | | panic!("panic1"); +LL | | } + | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` + +error: only a `panic!` in `if`-then statement + --> $DIR/if_then_panic.rs:42:5 + | +LL | / if b.is_empty() && a.is_empty() { +LL | | panic!("panic2"); +LL | | } + | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + +error: only a `panic!` in `if`-then statement + --> $DIR/if_then_panic.rs:45:5 + | +LL | / if a.is_empty() && !b.is_empty() { +LL | | panic!("panic3"); +LL | | } + | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + +error: only a `panic!` in `if`-then statement + --> $DIR/if_then_panic.rs:48:5 + | +LL | / if b.is_empty() || a.is_empty() { +LL | | panic!("panic4"); +LL | | } + | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + +error: only a `panic!` in `if`-then statement + --> $DIR/if_then_panic.rs:51:5 + | +LL | / if a.is_empty() || !b.is_empty() { +LL | | panic!("panic5"); +LL | | } + | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + +error: aborting due to 7 previous errors diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index 97c26bc83ad..aa69b097410 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,3 +1,4 @@ +// edition:2018 // aux-build:implicit_hasher_macros.rs #![deny(clippy::implicit_hasher)] #![allow(unused)] @@ -96,4 +97,7 @@ pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} // #4260 implicit_hasher_fn!(); +// #7712 +pub async fn election_vote(_data: HashMap) {} + fn main() {} diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 2e62dd30f9f..dad5ab71f15 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -1,11 +1,11 @@ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:16:35 + --> $DIR/implicit_hasher.rs:17:35 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/implicit_hasher.rs:2:9 + --> $DIR/implicit_hasher.rs:3:9 | LL | #![deny(clippy::implicit_hasher)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:25:36 + --> $DIR/implicit_hasher.rs:26:36 | LL | impl Foo for (HashMap,) { | ^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:30:19 + --> $DIR/implicit_hasher.rs:31:19 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:47:32 + --> $DIR/implicit_hasher.rs:48:32 | LL | impl Foo for HashSet { | ^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: impl for `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:52:19 + --> $DIR/implicit_hasher.rs:53:19 | LL | impl Foo for HashSet { | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default: | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:23 + --> $DIR/implicit_hasher.rs:70:23 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn foo(_map: &mut HashMap, _s | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashSet` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:69:53 + --> $DIR/implicit_hasher.rs:70:53 | LL | pub fn foo(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^ @@ -101,7 +101,7 @@ LL | pub fn foo(_map: &mut HashMap, _set: | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ error: impl for `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:73:43 + --> $DIR/implicit_hasher.rs:74:43 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | (HashMap::default(), HashMap::with_capacity_and_hasher(10, | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: parameter of type `HashMap` should be generalized over different hashers - --> $DIR/implicit_hasher.rs:81:33 + --> $DIR/implicit_hasher.rs:82:33 | LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | pub fn $name(_map: &mut HashMap $DIR/implicit_hasher.rs:81:63 + --> $DIR/implicit_hasher.rs:82:63 | LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^ @@ -149,5 +149,16 @@ help: consider adding a type parameter LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~ -error: aborting due to 10 previous errors +error: parameter of type `HashMap` should be generalized over different hashers + --> $DIR/implicit_hasher.rs:101:35 + | +LL | pub async fn election_vote(_data: HashMap) {} + | ^^^^^^^^^^^^^^^^^ + | +help: consider adding a type parameter + | +LL | pub async fn election_vote(_data: HashMap) {} + | +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 11 previous errors diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs index b74c93dc4a6..67f24b4548a 100644 --- a/tests/ui/integer_arithmetic.rs +++ b/tests/ui/integer_arithmetic.rs @@ -1,12 +1,5 @@ #![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::op_ref -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)] #[rustfmt::skip] fn main() { diff --git a/tests/ui/integer_arithmetic.stderr b/tests/ui/integer_arithmetic.stderr index add3b6b90fa..9a795b1f291 100644 --- a/tests/ui/integer_arithmetic.stderr +++ b/tests/ui/integer_arithmetic.stderr @@ -1,5 +1,5 @@ error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:37:5 + --> $DIR/integer_arithmetic.rs:30:5 | LL | i /= 0; | ^^^^^^ attempt to divide `_` by zero @@ -7,13 +7,13 @@ LL | i /= 0; = note: `#[deny(unconditional_panic)]` on by default error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:42:5 + --> $DIR/integer_arithmetic.rs:35:5 | LL | i %= 0; | ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 + --> $DIR/integer_arithmetic.rs:9:5 | LL | 1 + i; | ^^^^^ @@ -21,146 +21,146 @@ LL | 1 + i; = note: `-D clippy::integer-arithmetic` implied by `-D warnings` error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:17:5 + --> $DIR/integer_arithmetic.rs:10:5 | LL | i * 2; | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:18:5 + --> $DIR/integer_arithmetic.rs:11:5 | LL | / 1 % LL | | i / 2; // no error, this is part of the expression in the preceding line | |_____^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:20:5 + --> $DIR/integer_arithmetic.rs:13:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:21:5 + --> $DIR/integer_arithmetic.rs:14:5 | LL | -i; | ^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:22:5 + --> $DIR/integer_arithmetic.rs:15:5 | LL | i >> 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:23:5 + --> $DIR/integer_arithmetic.rs:16:5 | LL | i << 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 + --> $DIR/integer_arithmetic.rs:26:5 | LL | i += 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:34:5 + --> $DIR/integer_arithmetic.rs:27:5 | LL | i -= 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:35:5 + --> $DIR/integer_arithmetic.rs:28:5 | LL | i *= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:38:11 + --> $DIR/integer_arithmetic.rs:31:11 | LL | i /= -1; | ^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:39:5 + --> $DIR/integer_arithmetic.rs:32:5 | LL | i /= var1; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:40:5 + --> $DIR/integer_arithmetic.rs:33:5 | LL | i /= var2; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:43:11 + --> $DIR/integer_arithmetic.rs:36:11 | LL | i %= -1; | ^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:44:5 + --> $DIR/integer_arithmetic.rs:37:5 | LL | i %= var1; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:45:5 + --> $DIR/integer_arithmetic.rs:38:5 | LL | i %= var2; | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:46:5 + --> $DIR/integer_arithmetic.rs:39:5 | LL | i <<= 3; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:47:5 + --> $DIR/integer_arithmetic.rs:40:5 | LL | i >>= 2; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:89:5 + --> $DIR/integer_arithmetic.rs:82:5 | LL | 3 + &1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:90:5 + --> $DIR/integer_arithmetic.rs:83:5 | LL | &3 + 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:91:5 + --> $DIR/integer_arithmetic.rs:84:5 | LL | &3 + &1; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:96:5 + --> $DIR/integer_arithmetic.rs:89:5 | LL | a + x | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:100:5 + --> $DIR/integer_arithmetic.rs:93:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:104:5 + --> $DIR/integer_arithmetic.rs:97:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:108:5 + --> $DIR/integer_arithmetic.rs:101:5 | LL | (&x + &y) | ^^^^^^^^^ diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index d22fee3f27b..b45cc849eae 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -35,6 +35,7 @@ enum LargeEnum2 { VariantOk(i32, u32), ContainingLargeEnum(LargeEnum), } + enum LargeEnum3 { ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), VoidVariant, @@ -56,6 +57,23 @@ enum LargeEnumOk { LargeB([i32; 8001]), } +enum LargeEnum6 { + A, + B([u8; 255]), + C([u8; 200]), +} + +enum LargeEnum7 { + A, + B([u8; 1255]), + C([u8; 200]), +} + +enum LargeEnum8 { + VariantOk(i32, u32), + ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), +} + fn main() { large_enum_variant!(); } diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index 0eac28fbd35..899f97ce2e1 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -32,30 +32,45 @@ LL | ContainingLargeEnum(Box), | ~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:46:5 + --> $DIR/large_enum_variant.rs:40:5 + | +LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes + | +note: and the second-largest variant is 8 bytes: + --> $DIR/large_enum_variant.rs:42:5 + | +LL | StructLikeLittle { x: i32, y: i32 }, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider boxing the large fields to reduce the total size of the enum + | +LL | ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), + | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:47:5 | LL | StructLikeLarge { x: [i32; 8000], y: i32 }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes | note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:45:5 + --> $DIR/large_enum_variant.rs:46:5 | LL | VariantOk(i32, u32), | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> $DIR/large_enum_variant.rs:46:5 | -LL | StructLikeLarge { x: [i32; 8000], y: i32 }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, + | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:51:5 + --> $DIR/large_enum_variant.rs:52:5 | LL | StructLikeLarge2 { x: [i32; 8000] }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes | note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:50:5 + --> $DIR/large_enum_variant.rs:51:5 | LL | VariantOk(i32, u32), | ^^^^^^^^^^^^^^^^^^^ @@ -64,5 +79,37 @@ help: consider boxing the large fields to reduce the total size of the enum LL | StructLikeLarge2 { x: Box<[i32; 8000]> }, | ~~~~~~~~~~~~~~~~ -error: aborting due to 4 previous errors +error: large size difference between variants + --> $DIR/large_enum_variant.rs:68:5 + | +LL | B([u8; 1255]), + | ^^^^^^^^^^^^^ this variant is 1255 bytes + | +note: and the second-largest variant is 200 bytes: + --> $DIR/large_enum_variant.rs:69:5 + | +LL | C([u8; 200]), + | ^^^^^^^^^^^^ +help: consider boxing the large fields to reduce the total size of the enum + | +LL | B(Box<[u8; 1255]>), + | ~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:74:5 + | +LL | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes + | +note: and the second-largest variant is 8 bytes: + --> $DIR/large_enum_variant.rs:73:5 + | +LL | VariantOk(i32, u32), + | ^^^^^^^^^^^^^^^^^^^ +help: consider boxing the large fields to reduce the total size of the enum + | +LL | ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), + | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ + +error: aborting due to 7 previous errors diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 178d8705c2f..0860dcf8e0d 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -1,11 +1,11 @@ // run-rustfix -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::iter_cloned_collect)] -#![allow(clippy::clone_on_copy, clippy::redundant_clone)] -#![allow(clippy::let_underscore_drop)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::redundant_closure_for_method_calls)] -#![allow(clippy::many_single_char_names)] +#![warn(clippy::map_clone)] +#![allow( + clippy::clone_on_copy, + clippy::iter_cloned_collect, + clippy::many_single_char_names, + clippy::redundant_clone +)] fn main() { let _: Vec = vec![5_i8; 6].iter().copied().collect(); diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index c73d81713b8..b6987336834 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -1,11 +1,11 @@ // run-rustfix -#![warn(clippy::all, clippy::pedantic)] -#![allow(clippy::iter_cloned_collect)] -#![allow(clippy::clone_on_copy, clippy::redundant_clone)] -#![allow(clippy::let_underscore_drop)] -#![allow(clippy::missing_docs_in_private_items)] -#![allow(clippy::redundant_closure_for_method_calls)] -#![allow(clippy::many_single_char_names)] +#![warn(clippy::map_clone)] +#![allow( + clippy::clone_on_copy, + clippy::iter_cloned_collect, + clippy::many_single_char_names, + clippy::redundant_clone +)] fn main() { let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed index 319299862a7..c611f76bf96 100644 --- a/tests/ui/match_expr_like_matches_macro.fixed +++ b/tests/ui/match_expr_like_matches_macro.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_like_matches_macro)] -#![allow(unreachable_patterns, dead_code)] +#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)] fn main() { let x = Some(5); diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs index 2ef6cf42387..2deeb84e741 100644 --- a/tests/ui/match_expr_like_matches_macro.rs +++ b/tests/ui/match_expr_like_matches_macro.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::match_like_matches_macro)] -#![allow(unreachable_patterns, dead_code)] +#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)] fn main() { let x = Some(5); diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index c84e31ea482..846d665d1d8 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -2,7 +2,7 @@ #![feature(half_open_range_patterns)] #![warn(clippy::match_overlapping_arm)] #![allow(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] /// Tests for match_overlapping_arm diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 5de43733ad3..6cbb4d32b0d 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,4 +1,5 @@ #![warn(clippy::match_ref_pats)] +#![allow(clippy::equatable_if_let)] fn ref_pats() { { diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index a57a338b276..072aff445e9 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:6:9 + --> $DIR/match_ref_pats.rs:7:9 | LL | / match v { LL | | &Some(v) => println!("{:?}", v), @@ -16,7 +16,7 @@ LL ~ None => println!("none"), | error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:17:5 + --> $DIR/match_ref_pats.rs:18:5 | LL | / match tup { LL | | &(v, 1) => println!("{}", v), @@ -31,7 +31,7 @@ LL ~ (v, 1) => println!("{}", v), | error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:23:5 + --> $DIR/match_ref_pats.rs:24:5 | LL | / match &w { LL | | &Some(v) => println!("{:?}", v), @@ -47,7 +47,7 @@ LL ~ None => println!("none"), | error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:35:12 + --> $DIR/match_ref_pats.rs:36:12 | LL | if let &None = a { | -------^^^^^---- help: try this: `if a.is_none()` @@ -55,7 +55,7 @@ LL | if let &None = a { = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:35:5 + --> $DIR/match_ref_pats.rs:36:5 | LL | / if let &None = a { LL | | println!("none"); @@ -68,13 +68,13 @@ LL | if let None = *a { | ~~~~ ~~ error: redundant pattern matching, consider using `is_none()` - --> $DIR/match_ref_pats.rs:40:12 + --> $DIR/match_ref_pats.rs:41:12 | LL | if let &None = &b { | -------^^^^^----- help: try this: `if b.is_none()` error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:40:5 + --> $DIR/match_ref_pats.rs:41:5 | LL | / if let &None = &b { LL | | println!("none"); @@ -87,7 +87,7 @@ LL | if let None = b { | ~~~~ ~ error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:67:9 + --> $DIR/match_ref_pats.rs:68:9 | LL | / match foo_variant!(0) { LL | | &Foo::A => println!("A"), diff --git a/tests/ui/modulo_arithmetic_float.rs b/tests/ui/modulo_arithmetic_float.rs index b010b0dbdfa..b1861f07cd1 100644 --- a/tests/ui/modulo_arithmetic_float.rs +++ b/tests/ui/modulo_arithmetic_float.rs @@ -1,12 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::modulo_one -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] fn main() { // Lint when both sides are const and of the opposite sign diff --git a/tests/ui/modulo_arithmetic_float.stderr b/tests/ui/modulo_arithmetic_float.stderr index 7bfdb0bde60..97844aaaa75 100644 --- a/tests/ui/modulo_arithmetic_float.stderr +++ b/tests/ui/modulo_arithmetic_float.stderr @@ -1,5 +1,5 @@ error: you are using modulo operator on constants with different signs: `-1.600 % 2.100` - --> $DIR/modulo_arithmetic_float.rs:13:5 + --> $DIR/modulo_arithmetic_float.rs:6:5 | LL | -1.6 % 2.1; | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | -1.6 % 2.1; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `1.600 % -2.100` - --> $DIR/modulo_arithmetic_float.rs:14:5 + --> $DIR/modulo_arithmetic_float.rs:7:5 | LL | 1.6 % -2.1; | ^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | 1.6 % -2.1; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `-1.200 % 3.400` - --> $DIR/modulo_arithmetic_float.rs:15:5 + --> $DIR/modulo_arithmetic_float.rs:8:5 | LL | (1.1 - 2.3) % (1.1 + 2.3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | (1.1 - 2.3) % (1.1 + 2.3); = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on constants with different signs: `3.400 % -1.200` - --> $DIR/modulo_arithmetic_float.rs:16:5 + --> $DIR/modulo_arithmetic_float.rs:9:5 | LL | (1.1 + 2.3) % (1.1 - 2.3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | (1.1 + 2.3) % (1.1 - 2.3); = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:21:5 + --> $DIR/modulo_arithmetic_float.rs:14:5 | LL | a_f32 % b_f32; | ^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | a_f32 % b_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:22:5 + --> $DIR/modulo_arithmetic_float.rs:15:5 | LL | b_f32 % a_f32; | ^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | b_f32 % a_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:23:5 + --> $DIR/modulo_arithmetic_float.rs:16:5 | LL | b_f32 %= a_f32; | ^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | b_f32 %= a_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:27:5 + --> $DIR/modulo_arithmetic_float.rs:20:5 | LL | a_f64 % b_f64; | ^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | a_f64 % b_f64; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:28:5 + --> $DIR/modulo_arithmetic_float.rs:21:5 | LL | b_f64 % a_f64; | ^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | b_f64 % a_f64; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_float.rs:29:5 + --> $DIR/modulo_arithmetic_float.rs:22:5 | LL | b_f64 %= a_f64; | ^^^^^^^^^^^^^^ diff --git a/tests/ui/modulo_arithmetic_integral.rs b/tests/ui/modulo_arithmetic_integral.rs index 779d035c5f8..fc1acc39ebc 100644 --- a/tests/ui/modulo_arithmetic_integral.rs +++ b/tests/ui/modulo_arithmetic_integral.rs @@ -1,12 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::modulo_one -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] fn main() { // Lint on signed integral numbers diff --git a/tests/ui/modulo_arithmetic_integral.stderr b/tests/ui/modulo_arithmetic_integral.stderr index e863b838699..f71adf5b0d0 100644 --- a/tests/ui/modulo_arithmetic_integral.stderr +++ b/tests/ui/modulo_arithmetic_integral.stderr @@ -1,5 +1,5 @@ error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:15:5 + --> $DIR/modulo_arithmetic_integral.rs:8:5 | LL | a % b; | ^^^^^ @@ -9,7 +9,7 @@ LL | a % b; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:16:5 + --> $DIR/modulo_arithmetic_integral.rs:9:5 | LL | b % a; | ^^^^^ @@ -18,7 +18,7 @@ LL | b % a; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:17:5 + --> $DIR/modulo_arithmetic_integral.rs:10:5 | LL | b %= a; | ^^^^^^ @@ -27,7 +27,7 @@ LL | b %= a; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:21:5 + --> $DIR/modulo_arithmetic_integral.rs:14:5 | LL | a_i8 % b_i8; | ^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | a_i8 % b_i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:22:5 + --> $DIR/modulo_arithmetic_integral.rs:15:5 | LL | b_i8 %= a_i8; | ^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | b_i8 %= a_i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:26:5 + --> $DIR/modulo_arithmetic_integral.rs:19:5 | LL | a_i16 % b_i16; | ^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | a_i16 % b_i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:27:5 + --> $DIR/modulo_arithmetic_integral.rs:20:5 | LL | b_i16 %= a_i16; | ^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | b_i16 %= a_i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:31:5 + --> $DIR/modulo_arithmetic_integral.rs:24:5 | LL | a_i32 % b_i32; | ^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | a_i32 % b_i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:32:5 + --> $DIR/modulo_arithmetic_integral.rs:25:5 | LL | b_i32 %= a_i32; | ^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | b_i32 %= a_i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:36:5 + --> $DIR/modulo_arithmetic_integral.rs:29:5 | LL | a_i64 % b_i64; | ^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | a_i64 % b_i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:37:5 + --> $DIR/modulo_arithmetic_integral.rs:30:5 | LL | b_i64 %= a_i64; | ^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | b_i64 %= a_i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:41:5 + --> $DIR/modulo_arithmetic_integral.rs:34:5 | LL | a_i128 % b_i128; | ^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | a_i128 % b_i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:42:5 + --> $DIR/modulo_arithmetic_integral.rs:35:5 | LL | b_i128 %= a_i128; | ^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | b_i128 %= a_i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:46:5 + --> $DIR/modulo_arithmetic_integral.rs:39:5 | LL | a_isize % b_isize; | ^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | a_isize % b_isize; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:47:5 + --> $DIR/modulo_arithmetic_integral.rs:40:5 | LL | b_isize %= a_isize; | ^^^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | b_isize %= a_isize; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:51:5 + --> $DIR/modulo_arithmetic_integral.rs:44:5 | LL | a % b; | ^^^^^ @@ -144,7 +144,7 @@ LL | a % b; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> $DIR/modulo_arithmetic_integral.rs:52:5 + --> $DIR/modulo_arithmetic_integral.rs:45:5 | LL | b %= a; | ^^^^^^ diff --git a/tests/ui/modulo_arithmetic_integral_const.rs b/tests/ui/modulo_arithmetic_integral_const.rs index 57a96692c00..047a29fa1e3 100644 --- a/tests/ui/modulo_arithmetic_integral_const.rs +++ b/tests/ui/modulo_arithmetic_integral_const.rs @@ -1,12 +1,5 @@ #![warn(clippy::modulo_arithmetic)] -#![allow( - unused, - clippy::shadow_reuse, - clippy::shadow_unrelated, - clippy::no_effect, - clippy::unnecessary_operation, - clippy::modulo_one -)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::modulo_one)] fn main() { // Lint when both sides are const and of the opposite sign diff --git a/tests/ui/modulo_arithmetic_integral_const.stderr b/tests/ui/modulo_arithmetic_integral_const.stderr index de328bb75fe..64335f35f0f 100644 --- a/tests/ui/modulo_arithmetic_integral_const.stderr +++ b/tests/ui/modulo_arithmetic_integral_const.stderr @@ -1,5 +1,5 @@ error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:13:5 + --> $DIR/modulo_arithmetic_integral_const.rs:6:5 | LL | -1 % 2; | ^^^^^^ @@ -9,7 +9,7 @@ LL | -1 % 2; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:14:5 + --> $DIR/modulo_arithmetic_integral_const.rs:7:5 | LL | 1 % -2; | ^^^^^^ @@ -18,7 +18,7 @@ LL | 1 % -2; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 3` - --> $DIR/modulo_arithmetic_integral_const.rs:15:5 + --> $DIR/modulo_arithmetic_integral_const.rs:8:5 | LL | (1 - 2) % (1 + 2); | ^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | (1 - 2) % (1 + 2); = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `3 % -1` - --> $DIR/modulo_arithmetic_integral_const.rs:16:5 + --> $DIR/modulo_arithmetic_integral_const.rs:9:5 | LL | (1 + 2) % (1 - 2); | ^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | (1 + 2) % (1 - 2); = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-35 % 300000` - --> $DIR/modulo_arithmetic_integral_const.rs:17:5 + --> $DIR/modulo_arithmetic_integral_const.rs:10:5 | LL | 35 * (7 - 4 * 2) % (-500 * -600); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | 35 * (7 - 4 * 2) % (-500 * -600); = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:19:5 + --> $DIR/modulo_arithmetic_integral_const.rs:12:5 | LL | -1i8 % 2i8; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | -1i8 % 2i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:20:5 + --> $DIR/modulo_arithmetic_integral_const.rs:13:5 | LL | 1i8 % -2i8; | ^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | 1i8 % -2i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:21:5 + --> $DIR/modulo_arithmetic_integral_const.rs:14:5 | LL | -1i16 % 2i16; | ^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | -1i16 % 2i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:22:5 + --> $DIR/modulo_arithmetic_integral_const.rs:15:5 | LL | 1i16 % -2i16; | ^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | 1i16 % -2i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:23:5 + --> $DIR/modulo_arithmetic_integral_const.rs:16:5 | LL | -1i32 % 2i32; | ^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | -1i32 % 2i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:24:5 + --> $DIR/modulo_arithmetic_integral_const.rs:17:5 | LL | 1i32 % -2i32; | ^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | 1i32 % -2i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:25:5 + --> $DIR/modulo_arithmetic_integral_const.rs:18:5 | LL | -1i64 % 2i64; | ^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | -1i64 % 2i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:26:5 + --> $DIR/modulo_arithmetic_integral_const.rs:19:5 | LL | 1i64 % -2i64; | ^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | 1i64 % -2i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:27:5 + --> $DIR/modulo_arithmetic_integral_const.rs:20:5 | LL | -1i128 % 2i128; | ^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | -1i128 % 2i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:28:5 + --> $DIR/modulo_arithmetic_integral_const.rs:21:5 | LL | 1i128 % -2i128; | ^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | 1i128 % -2i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> $DIR/modulo_arithmetic_integral_const.rs:29:5 + --> $DIR/modulo_arithmetic_integral_const.rs:22:5 | LL | -1isize % 2isize; | ^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | -1isize % 2isize; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> $DIR/modulo_arithmetic_integral_const.rs:30:5 + --> $DIR/modulo_arithmetic_integral_const.rs:23:5 | LL | 1isize % -2isize; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index 639eac8b8b3..a2e3988daff 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -6,6 +6,7 @@ dead_code, clippy::no_effect, clippy::if_same_then_else, + clippy::equatable_if_let, clippy::needless_return, clippy::self_named_constructors )] diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index a3ce086a1c9..75805e85789 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -6,6 +6,7 @@ dead_code, clippy::no_effect, clippy::if_same_then_else, + clippy::equatable_if_let, clippy::needless_return, clippy::self_named_constructors )] diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr index 8026d643c44..1fa12add167 100644 --- a/tests/ui/needless_bool/fixable.stderr +++ b/tests/ui/needless_bool/fixable.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:40:5 + --> $DIR/fixable.rs:41:5 | LL | / if x { LL | | true @@ -11,7 +11,7 @@ LL | | }; = note: `-D clippy::needless-bool` implied by `-D warnings` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:45:5 + --> $DIR/fixable.rs:46:5 | LL | / if x { LL | | false @@ -21,7 +21,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:50:5 + --> $DIR/fixable.rs:51:5 | LL | / if x && y { LL | | false @@ -31,7 +31,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:70:5 + --> $DIR/fixable.rs:71:5 | LL | / if x { LL | | return true; @@ -41,7 +41,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:78:5 + --> $DIR/fixable.rs:79:5 | LL | / if x { LL | | return false; @@ -51,7 +51,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:86:5 + --> $DIR/fixable.rs:87:5 | LL | / if x && y { LL | | return true; @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:94:5 + --> $DIR/fixable.rs:95:5 | LL | / if x && y { LL | | return false; @@ -71,7 +71,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:102:8 + --> $DIR/fixable.rs:103:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -79,25 +79,25 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:106:8 + --> $DIR/fixable.rs:107:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:116:8 + --> $DIR/fixable.rs:117:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:117:8 + --> $DIR/fixable.rs:118:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:126:12 + --> $DIR/fixable.rs:127:12 | LL | } else if returns_bool() { | ____________^ diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 37efa6274df..9c999e12b4c 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -3,7 +3,12 @@ #![feature(let_else)] #![allow(unused)] -#![allow(clippy::if_same_then_else, clippy::single_match, clippy::needless_bool)] +#![allow( + clippy::if_same_then_else, + clippy::single_match, + clippy::needless_bool, + clippy::equatable_if_let +)] #![warn(clippy::needless_return)] macro_rules! the_answer { diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index cbf384ac9e4..da7dcf4f0a9 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -3,7 +3,12 @@ #![feature(let_else)] #![allow(unused)] -#![allow(clippy::if_same_then_else, clippy::single_match, clippy::needless_bool)] +#![allow( + clippy::if_same_then_else, + clippy::single_match, + clippy::needless_bool, + clippy::equatable_if_let +)] #![warn(clippy::needless_return)] macro_rules! the_answer { diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 7ce7028bbae..2e802cff1e6 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement - --> $DIR/needless_return.rs:20:5 + --> $DIR/needless_return.rs:25:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` @@ -7,187 +7,187 @@ LL | return true; = note: `-D clippy::needless-return` implied by `-D warnings` error: unneeded `return` statement - --> $DIR/needless_return.rs:24:5 + --> $DIR/needless_return.rs:29:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:29:9 + --> $DIR/needless_return.rs:34:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:31:9 + --> $DIR/needless_return.rs:36:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:37:17 + --> $DIR/needless_return.rs:42:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:39:13 + --> $DIR/needless_return.rs:44:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:46:9 + --> $DIR/needless_return.rs:51:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:48:16 + --> $DIR/needless_return.rs:53:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:56:5 + --> $DIR/needless_return.rs:61:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:61:9 + --> $DIR/needless_return.rs:66:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:63:9 + --> $DIR/needless_return.rs:68:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:70:14 + --> $DIR/needless_return.rs:75:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:85:9 + --> $DIR/needless_return.rs:90:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:87:9 + --> $DIR/needless_return.rs:92:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:108:32 + --> $DIR/needless_return.rs:113:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:113:13 + --> $DIR/needless_return.rs:118:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:115:20 + --> $DIR/needless_return.rs:120:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:121:32 + --> $DIR/needless_return.rs:126:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:130:5 + --> $DIR/needless_return.rs:135:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:134:5 + --> $DIR/needless_return.rs:139:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:139:9 + --> $DIR/needless_return.rs:144:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:141:9 + --> $DIR/needless_return.rs:146:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:147:17 + --> $DIR/needless_return.rs:152:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:149:13 + --> $DIR/needless_return.rs:154:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:156:9 + --> $DIR/needless_return.rs:161:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:158:16 + --> $DIR/needless_return.rs:163:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:166:5 + --> $DIR/needless_return.rs:171:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:171:9 + --> $DIR/needless_return.rs:176:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:173:9 + --> $DIR/needless_return.rs:178:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:180:14 + --> $DIR/needless_return.rs:185:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:195:9 + --> $DIR/needless_return.rs:200:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:197:9 + --> $DIR/needless_return.rs:202:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` diff --git a/tests/ui/non_send_fields_in_send_ty.rs b/tests/ui/non_send_fields_in_send_ty.rs new file mode 100644 index 00000000000..eca7f5e5655 --- /dev/null +++ b/tests/ui/non_send_fields_in_send_ty.rs @@ -0,0 +1,127 @@ +#![warn(clippy::non_send_fields_in_send_ty)] +#![feature(extern_types)] + +use std::cell::UnsafeCell; +use std::ptr::NonNull; +use std::rc::Rc; +use std::sync::{Arc, Mutex, MutexGuard}; + +// disrustor / RUSTSEC-2020-0150 +pub struct RingBuffer { + data: Vec>, + capacity: usize, + mask: usize, +} + +unsafe impl Send for RingBuffer {} + +// noise_search / RUSTSEC-2020-0141 +pub struct MvccRwLock { + raw: *const T, + lock: Mutex>, +} + +unsafe impl Send for MvccRwLock {} + +// async-coap / RUSTSEC-2020-0124 +pub struct ArcGuard { + inner: T, + head: Arc, +} + +unsafe impl Send for ArcGuard {} + +// rusb / RUSTSEC-2020-0098 +extern "C" { + type libusb_device_handle; +} + +pub trait UsbContext { + // some user trait that does not guarantee `Send` +} + +pub struct DeviceHandle { + context: T, + handle: NonNull, +} + +unsafe impl Send for DeviceHandle {} + +// Other basic tests +pub struct NoGeneric { + rc_is_not_send: Rc, +} + +unsafe impl Send for NoGeneric {} + +pub struct MultiField { + field1: T, + field2: T, + field3: T, +} + +unsafe impl Send for MultiField {} + +pub enum MyOption { + MySome(T), + MyNone, +} + +unsafe impl Send for MyOption {} + +// Multiple type parameters +pub struct MultiParam { + vec: Vec<(A, B)>, +} + +unsafe impl Send for MultiParam {} + +// Tests for raw pointer heuristic +extern "C" { + type NonSend; +} + +pub struct HeuristicTest { + // raw pointers are allowed + field1: Vec<*const NonSend>, + field2: [*const NonSend; 3], + field3: (*const NonSend, *const NonSend, *const NonSend), + // not allowed when it contains concrete `!Send` field + field4: (*const NonSend, Rc), + // nested raw pointer is also allowed + field5: Vec>, +} + +unsafe impl Send for HeuristicTest {} + +// Test attributes +#[allow(clippy::non_send_fields_in_send_ty)] +pub struct AttrTest1(T); + +pub struct AttrTest2 { + #[allow(clippy::non_send_fields_in_send_ty)] + field: T, +} + +pub enum AttrTest3 { + #[allow(clippy::non_send_fields_in_send_ty)] + Enum1(T), + Enum2(T), +} + +unsafe impl Send for AttrTest1 {} +unsafe impl Send for AttrTest2 {} +unsafe impl Send for AttrTest3 {} + +// Multiple non-overlapping `Send` for a single type +pub struct Complex { + field1: A, + field2: B, +} + +unsafe impl

Send for Complex {} + +// `MutexGuard` is non-Send +unsafe impl Send for Complex> {} + +fn main() {} diff --git a/tests/ui/non_send_fields_in_send_ty.stderr b/tests/ui/non_send_fields_in_send_ty.stderr new file mode 100644 index 00000000000..8b8a1d16d9b --- /dev/null +++ b/tests/ui/non_send_fields_in_send_ty.stderr @@ -0,0 +1,171 @@ +error: this implementation is unsound, as some fields in `RingBuffer` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:16:1 + | +LL | unsafe impl Send for RingBuffer {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings` +note: the type of field `data` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:11:5 + | +LL | data: Vec>, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = help: add bounds on type parameter `T` that satisfy `Vec>: Send` + +error: this implementation is unsound, as some fields in `MvccRwLock` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:24:1 + | +LL | unsafe impl Send for MvccRwLock {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `lock` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:21:5 + | +LL | lock: Mutex>, + | ^^^^^^^^^^^^^^^^^^^ + = help: add bounds on type parameter `T` that satisfy `Mutex>: Send` + +error: this implementation is unsound, as some fields in `ArcGuard` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:32:1 + | +LL | unsafe impl Send for ArcGuard {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `head` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:29:5 + | +LL | head: Arc, + | ^^^^^^^^^^^^^ + = help: add bounds on type parameter `RC` that satisfy `Arc: Send` + +error: this implementation is unsound, as some fields in `DeviceHandle` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:48:1 + | +LL | unsafe impl Send for DeviceHandle {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `context` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:44:5 + | +LL | context: T, + | ^^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `NoGeneric` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:55:1 + | +LL | unsafe impl Send for NoGeneric {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `rc_is_not_send` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:52:5 + | +LL | rc_is_not_send: Rc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: this implementation is unsound, as some fields in `MultiField` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:63:1 + | +LL | unsafe impl Send for MultiField {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:58:5 + | +LL | field1: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field2` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:59:5 + | +LL | field2: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl +note: the type of field `field3` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:60:5 + | +LL | field3: T, + | ^^^^^^^^^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `MyOption` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:70:1 + | +LL | unsafe impl Send for MyOption {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `0` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:66:12 + | +LL | MySome(T), + | ^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `MultiParam` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:77:1 + | +LL | unsafe impl Send for MultiParam {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `vec` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:74:5 + | +LL | vec: Vec<(A, B)>, + | ^^^^^^^^^^^^^^^^ + = help: add bounds on type parameters `A, B` that satisfy `Vec<(A, B)>: Send` + +error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:95:1 + | +LL | unsafe impl Send for HeuristicTest {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field4` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:90:5 + | +LL | field4: (*const NonSend, Rc), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: this implementation is unsound, as some fields in `AttrTest3` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:114:1 + | +LL | unsafe impl Send for AttrTest3 {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `0` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:109:11 + | +LL | Enum2(T), + | ^ + = help: add `T: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `Complex` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:122:1 + | +LL | unsafe impl

Send for Complex {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field1` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:118:5 + | +LL | field1: A, + | ^^^^^^^^^ + = help: add `P: Send` bound in `Send` impl + +error: this implementation is unsound, as some fields in `Complex>` are `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:125:1 + | +LL | unsafe impl Send for Complex> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the type of field `field2` is `!Send` + --> $DIR/non_send_fields_in_send_ty.rs:119:5 + | +LL | field2: B, + | ^^^^^^^^^ + = help: use a thread-safe type that implements `Send` + +error: aborting due to 12 previous errors + diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index d1815d0aec3..a3ebe5d0703 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -2,7 +2,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref)] +#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { string.map_or((false, "hello"), |x| (true, x)) diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index a15627338cb..b11df3db60f 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -2,7 +2,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref)] +#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { diff --git a/tests/ui/redundant_pattern_matching_drop_order.fixed b/tests/ui/redundant_pattern_matching_drop_order.fixed index 794ed542435..ce3229f1759 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.fixed +++ b/tests/ui/redundant_pattern_matching_drop_order.fixed @@ -2,7 +2,7 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] use std::task::Poll::{Pending, Ready}; fn main() { diff --git a/tests/ui/redundant_pattern_matching_drop_order.rs b/tests/ui/redundant_pattern_matching_drop_order.rs index b9c82d86f61..29b8543cf47 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.rs +++ b/tests/ui/redundant_pattern_matching_drop_order.rs @@ -2,7 +2,7 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] use std::task::Poll::{Pending, Ready}; fn main() { diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 99714477266..813e268a60c 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 8309847e181..82a98468943 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 613a30d4a48..3a58e5ad7be 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:13:12 + --> $DIR/redundant_pattern_matching_option.rs:14:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` @@ -7,43 +7,43 @@ LL | if let None = None::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:15:12 + --> $DIR/redundant_pattern_matching_option.rs:16:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:17:12 + --> $DIR/redundant_pattern_matching_option.rs:18:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:23:15 + --> $DIR/redundant_pattern_matching_option.rs:24:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:25:15 + --> $DIR/redundant_pattern_matching_option.rs:26:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try this: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:27:15 + --> $DIR/redundant_pattern_matching_option.rs:28:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:30:15 + --> $DIR/redundant_pattern_matching_option.rs:31:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:38:5 + --> $DIR/redundant_pattern_matching_option.rs:39:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:43:5 + --> $DIR/redundant_pattern_matching_option.rs:44:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:48:13 + --> $DIR/redundant_pattern_matching_option.rs:49:13 | LL | let _ = match None::<()> { | _____________^ @@ -71,49 +71,49 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:54:20 + --> $DIR/redundant_pattern_matching_option.rs:55:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:58:20 + --> $DIR/redundant_pattern_matching_option.rs:59:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:60:19 + --> $DIR/redundant_pattern_matching_option.rs:61:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:79:12 + --> $DIR/redundant_pattern_matching_option.rs:80:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:81:12 + --> $DIR/redundant_pattern_matching_option.rs:82:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:83:15 + --> $DIR/redundant_pattern_matching_option.rs:84:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:85:15 + --> $DIR/redundant_pattern_matching_option.rs:86:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:87:5 + --> $DIR/redundant_pattern_matching_option.rs:88:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:92:5 + --> $DIR/redundant_pattern_matching_option.rs:93:5 | LL | / match None::<()> { LL | | Some(_) => false, diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed index c2977453804..3645f2c4bfd 100644 --- a/tests/ui/redundant_pattern_matching_poll.fixed +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs index 665c8c41750..866c71b7cfa 100644 --- a/tests/ui/redundant_pattern_matching_poll.rs +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -6,6 +6,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::equatable_if_let, clippy::if_same_then_else )] diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index 5ecf024a733..1b480f3157f 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:15:12 + --> $DIR/redundant_pattern_matching_poll.rs:16:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` @@ -7,37 +7,37 @@ LL | if let Pending = Pending::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:17:12 + --> $DIR/redundant_pattern_matching_poll.rs:18:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:19:12 + --> $DIR/redundant_pattern_matching_poll.rs:20:12 | LL | if let Ready(_) = Ready(42) { | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:25:15 + --> $DIR/redundant_pattern_matching_poll.rs:26:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:27:15 + --> $DIR/redundant_pattern_matching_poll.rs:28:15 | LL | while let Pending = Ready(42) {} | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:29:15 + --> $DIR/redundant_pattern_matching_poll.rs:30:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:35:5 + --> $DIR/redundant_pattern_matching_poll.rs:36:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -46,7 +46,7 @@ LL | | }; | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:40:5 + --> $DIR/redundant_pattern_matching_poll.rs:41:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, @@ -55,7 +55,7 @@ LL | | }; | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:45:13 + --> $DIR/redundant_pattern_matching_poll.rs:46:13 | LL | let _ = match Pending::<()> { | _____________^ @@ -65,49 +65,49 @@ LL | | }; | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:51:20 + --> $DIR/redundant_pattern_matching_poll.rs:52:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; | -------^^^^^^^^------- help: try this: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:55:20 + --> $DIR/redundant_pattern_matching_poll.rs:56:20 | LL | let _ = if let Ready(_) = gen_poll() { | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:57:19 + --> $DIR/redundant_pattern_matching_poll.rs:58:19 | LL | } else if let Pending = gen_poll() { | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:73:12 + --> $DIR/redundant_pattern_matching_poll.rs:74:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:75:12 + --> $DIR/redundant_pattern_matching_poll.rs:76:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:77:15 + --> $DIR/redundant_pattern_matching_poll.rs:78:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:79:15 + --> $DIR/redundant_pattern_matching_poll.rs:80:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:81:5 + --> $DIR/redundant_pattern_matching_poll.rs:82:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -116,7 +116,7 @@ LL | | }; | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:86:5 + --> $DIR/redundant_pattern_matching_poll.rs:87:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index e366c75335c..02e838456d0 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,54 +1,77 @@ -#![warn( - clippy::all, - clippy::pedantic, - clippy::shadow_same, - clippy::shadow_reuse, - clippy::shadow_unrelated -)] -#![allow( - unused_parens, - unused_variables, - clippy::manual_unwrap_or, - clippy::missing_docs_in_private_items, - clippy::single_match -)] +#![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)] -fn id(x: T) -> T { - x -} - -#[must_use] -fn first(x: (isize, isize)) -> isize { - x.0 -} - -fn main() { - let mut x = 1; +fn shadow_same() { + let x = 1; + let x = x; + let mut x = &x; let x = &mut x; - let x = { x }; - let x = (&*x); - let x = { *x + 1 }; - let x = id(x); - let x = (1, x); - let x = first(x); - let y = 1; - let x = y; - - let x; - x = 42; - - let o = Some(1_u8); - - if let Some(p) = o { - assert_eq!(1, p); - } - match o { - Some(p) => p, // no error, because the p above is in its own scope - None => 0, - }; - - match (x, o) { - (1, Some(a)) | (a, Some(1)) => (), // no error though `a` appears twice - _ => (), - } + let x = *x; } + +fn shadow_reuse() -> Option<()> { + let x = ([[0]], ()); + let x = x.0; + let x = x[0]; + let [x] = x; + let x = Some(x); + let x = foo(x); + let x = || x; + let x = Some(1).map(|_| x)?; + None +} + +fn shadow_unrelated() { + let x = 1; + let x = 2; +} + +fn syntax() { + fn f(x: u32) { + let x = 1; + } + let x = 1; + match Some(1) { + Some(1) => {}, + Some(x) => { + let x = 1; + }, + _ => {}, + } + if let Some(x) = Some(1) {} + while let Some(x) = Some(1) {} + let _ = |[x]: [u32; 1]| { + let x = 1; + }; +} + +fn negative() { + match Some(1) { + Some(x) if x == 1 => {}, + Some(x) => {}, + None => {}, + } + match [None, Some(1)] { + [Some(x), None] | [None, Some(x)] => {}, + _ => {}, + } + if let Some(x) = Some(1) { + let y = 1; + } else { + let x = 1; + let y = 1; + } + let x = 1; + #[allow(clippy::shadow_unrelated)] + let x = 1; +} + +fn foo(_: T) {} + +fn question_mark() -> Option<()> { + let val = 1; + // `?` expands with a `val` binding + None?; + None +} + +fn main() {} diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 7c1ad2949e9..8b60e072c93 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -1,138 +1,233 @@ -error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:27:5 +error: `x` is shadowed by itself in `x` + --> $DIR/shadow.rs:5:9 | -LL | let x = &mut x; - | ^^^^^^^^^^^^^^^ +LL | let x = x; + | ^ | = note: `-D clippy::shadow-same` implied by `-D warnings` note: previous binding is here - --> $DIR/shadow.rs:26:13 + --> $DIR/shadow.rs:4:9 | -LL | let mut x = 1; - | ^ +LL | let x = 1; + | ^ -error: `x` is shadowed by itself in `{ x }` - --> $DIR/shadow.rs:28:5 +error: `mut x` is shadowed by itself in `&x` + --> $DIR/shadow.rs:6:13 | -LL | let x = { x }; - | ^^^^^^^^^^^^^^ +LL | let mut x = &x; + | ^ | note: previous binding is here - --> $DIR/shadow.rs:27:9 + --> $DIR/shadow.rs:5:9 + | +LL | let x = x; + | ^ + +error: `x` is shadowed by itself in `&mut x` + --> $DIR/shadow.rs:7:9 + | +LL | let x = &mut x; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:6:9 + | +LL | let mut x = &x; + | ^^^^^ + +error: `x` is shadowed by itself in `*x` + --> $DIR/shadow.rs:8:9 + | +LL | let x = *x; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:7:9 | LL | let x = &mut x; | ^ -error: `x` is shadowed by itself in `(&*x)` - --> $DIR/shadow.rs:29:5 +error: `x` is shadowed by `x.0` which reuses the original value + --> $DIR/shadow.rs:13:9 | -LL | let x = (&*x); - | ^^^^^^^^^^^^^^ - | -note: previous binding is here - --> $DIR/shadow.rs:28:9 - | -LL | let x = { x }; - | ^ - -error: `x` is shadowed by `{ *x + 1 }` which reuses the original value - --> $DIR/shadow.rs:30:9 - | -LL | let x = { *x + 1 }; +LL | let x = x.0; | ^ | = note: `-D clippy::shadow-reuse` implied by `-D warnings` -note: initialization happens here - --> $DIR/shadow.rs:30:13 - | -LL | let x = { *x + 1 }; - | ^^^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:29:9 + --> $DIR/shadow.rs:12:9 | -LL | let x = (&*x); +LL | let x = ([[0]], ()); | ^ -error: `x` is shadowed by `id(x)` which reuses the original value - --> $DIR/shadow.rs:31:9 +error: `x` is shadowed by `x[0]` which reuses the original value + --> $DIR/shadow.rs:14:9 | -LL | let x = id(x); +LL | let x = x[0]; | ^ | -note: initialization happens here - --> $DIR/shadow.rs:31:13 - | -LL | let x = id(x); - | ^^^^^ note: previous binding is here - --> $DIR/shadow.rs:30:9 + --> $DIR/shadow.rs:13:9 | -LL | let x = { *x + 1 }; +LL | let x = x.0; | ^ -error: `x` is shadowed by `(1, x)` which reuses the original value - --> $DIR/shadow.rs:32:9 +error: `x` is shadowed by `x` which reuses the original value + --> $DIR/shadow.rs:15:10 | -LL | let x = (1, x); - | ^ +LL | let [x] = x; + | ^ | -note: initialization happens here - --> $DIR/shadow.rs:32:13 - | -LL | let x = (1, x); - | ^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:14:9 | -LL | let x = id(x); +LL | let x = x[0]; | ^ -error: `x` is shadowed by `first(x)` which reuses the original value - --> $DIR/shadow.rs:33:9 +error: `x` is shadowed by `Some(x)` which reuses the original value + --> $DIR/shadow.rs:16:9 | -LL | let x = first(x); +LL | let x = Some(x); | ^ | -note: initialization happens here - --> $DIR/shadow.rs:33:13 - | -LL | let x = first(x); - | ^^^^^^^^ note: previous binding is here - --> $DIR/shadow.rs:32:9 + --> $DIR/shadow.rs:15:10 | -LL | let x = (1, x); +LL | let [x] = x; + | ^ + +error: `x` is shadowed by `foo(x)` which reuses the original value + --> $DIR/shadow.rs:17:9 + | +LL | let x = foo(x); + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:16:9 + | +LL | let x = Some(x); | ^ -error: `x` is being shadowed - --> $DIR/shadow.rs:35:9 +error: `x` is shadowed by `|| x` which reuses the original value + --> $DIR/shadow.rs:18:9 | -LL | let x = y; +LL | let x = || x; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:17:9 + | +LL | let x = foo(x); + | ^ + +error: `x` is shadowed by `Some(1).map(|_| x)?` which reuses the original value + --> $DIR/shadow.rs:19:9 + | +LL | let x = Some(1).map(|_| x)?; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:18:9 + | +LL | let x = || x; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:25:9 + | +LL | let x = 2; | ^ | = note: `-D clippy::shadow-unrelated` implied by `-D warnings` -note: initialization happens here - --> $DIR/shadow.rs:35:13 +note: previous binding is here + --> $DIR/shadow.rs:24:9 | -LL | let x = y; +LL | let x = 1; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:30:13 + | +LL | let x = 1; | ^ -note: previous binding is here - --> $DIR/shadow.rs:33:9 - | -LL | let x = first(x); - | ^ - -error: `x` shadows a previous declaration - --> $DIR/shadow.rs:37:5 - | -LL | let x; - | ^^^^^^ | note: previous binding is here - --> $DIR/shadow.rs:35:9 + --> $DIR/shadow.rs:29:10 | -LL | let x = y; +LL | fn f(x: u32) { + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:35:14 + | +LL | Some(x) => { + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:32:9 + | +LL | let x = 1; | ^ -error: aborting due to 9 previous errors +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:36:17 + | +LL | let x = 1; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:35:14 + | +LL | Some(x) => { + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:40:17 + | +LL | if let Some(x) = Some(1) {} + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:32:9 + | +LL | let x = 1; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:41:20 + | +LL | while let Some(x) = Some(1) {} + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:32:9 + | +LL | let x = 1; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:42:15 + | +LL | let _ = |[x]: [u32; 1]| { + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:32:9 + | +LL | let x = 1; + | ^ + +error: `x` shadows a previous, unrelated binding + --> $DIR/shadow.rs:43:13 + | +LL | let x = 1; + | ^ + | +note: previous binding is here + --> $DIR/shadow.rs:42:15 + | +LL | let _ = |[x]: [u32; 1]| { + | ^ + +error: aborting due to 19 previous errors diff --git a/tests/ui/suspicious_map.stderr b/tests/ui/suspicious_map.stderr index 8c3f36584a5..3ffcd1a9031 100644 --- a/tests/ui/suspicious_map.stderr +++ b/tests/ui/suspicious_map.stderr @@ -5,7 +5,7 @@ LL | let _ = (0..3).map(|x| x + 2).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::suspicious-map` implied by `-D warnings` - = help: make sure you did not confuse `map` with `filter` or `for_each` + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` error: this call to `map()` won't have an effect on the call to `count()` --> $DIR/suspicious_map.rs:7:13 @@ -13,7 +13,7 @@ error: this call to `map()` won't have an effect on the call to `count()` LL | let _ = (0..3).map(f).count(); | ^^^^^^^^^^^^^^^^^^^^^ | - = help: make sure you did not confuse `map` with `filter` or `for_each` + = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` error: aborting due to 2 previous errors diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index f5a34190902..1e74ad2de65 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -1,7 +1,13 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] +#![allow( + clippy::never_loop, + unreachable_code, + unused_mut, + dead_code, + clippy::equatable_if_let +)] fn base() { let mut iter = 1..20; diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 72f34257d1f..69cb636cee8 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -1,7 +1,13 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] +#![allow( + clippy::never_loop, + unreachable_code, + unused_mut, + dead_code, + clippy::equatable_if_let +)] fn base() { let mut iter = 1..20; diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index 5e2fce4491a..1a11ba26eef 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:8:5 + --> $DIR/while_let_on_iterator.rs:14:5 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` @@ -7,85 +7,85 @@ LL | while let Option::Some(x) = iter.next() { = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:13:5 + --> $DIR/while_let_on_iterator.rs:19:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:18:5 + --> $DIR/while_let_on_iterator.rs:24:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:94:9 + --> $DIR/while_let_on_iterator.rs:100:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:101:9 + --> $DIR/while_let_on_iterator.rs:107:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:114:9 + --> $DIR/while_let_on_iterator.rs:120:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:134:9 + --> $DIR/while_let_on_iterator.rs:140:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:191:9 + --> $DIR/while_let_on_iterator.rs:197:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:202:5 + --> $DIR/while_let_on_iterator.rs:208:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:204:9 + --> $DIR/while_let_on_iterator.rs:210:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:213:9 + --> $DIR/while_let_on_iterator.rs:219:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:222:9 + --> $DIR/while_let_on_iterator.rs:228:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:239:9 + --> $DIR/while_let_on_iterator.rs:245:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:254:13 + --> $DIR/while_let_on_iterator.rs:260:13 | LL | while let Some(i) = self.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: manual `!RangeInclusive::contains` implementation - --> $DIR/while_let_on_iterator.rs:255:20 + --> $DIR/while_let_on_iterator.rs:261:20 | LL | if i < 3 || i > 7 { | ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)` @@ -93,37 +93,37 @@ LL | if i < 3 || i > 7 { = note: `-D clippy::manual-range-contains` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:286:13 + --> $DIR/while_let_on_iterator.rs:292:13 | LL | while let Some(i) = self.0.0.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:315:5 + --> $DIR/while_let_on_iterator.rs:321:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:327:9 + --> $DIR/while_let_on_iterator.rs:333:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:341:5 + --> $DIR/while_let_on_iterator.rs:347:5 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:352:5 + --> $DIR/while_let_on_iterator.rs:358:5 | LL | while let Some(x) = it.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:371:5 + --> $DIR/while_let_on_iterator.rs:377:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` diff --git a/util/etc/pre-commit.sh b/util/etc/pre-commit.sh index 528f8953b25..5dd2ba3d5f5 100755 --- a/util/etc/pre-commit.sh +++ b/util/etc/pre-commit.sh @@ -6,6 +6,7 @@ set -e # Update lints cargo dev update_lints git add clippy_lints/src/lib.rs +git add clippy_lints/src/lib.*.rs # Formatting: # Git will not automatically add the formatted code to the staged changes once From fbd0fb9aedbee06d0eefeecd62bc710832e0c457 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Thu, 7 Oct 2021 11:50:14 +1100 Subject: [PATCH 004/100] Restriction lint for function pointer casts --- CHANGELOG.md | 1 + .../src/casts/fn_to_numeric_cast_any.rs | 34 ++++++ clippy_lints/src/casts/mod.rs | 39 +++++++ clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_restriction.rs | 1 + tests/ui/fn_to_numeric_cast_any.rs | 76 +++++++++++++ tests/ui/fn_to_numeric_cast_any.stderr | 106 ++++++++++++++++++ 7 files changed, 258 insertions(+) create mode 100644 clippy_lints/src/casts/fn_to_numeric_cast_any.rs create mode 100644 tests/ui/fn_to_numeric_cast_any.rs create mode 100644 tests/ui/fn_to_numeric_cast_any.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fdb300c977..b13a5d76002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2730,6 +2730,7 @@ Released 2018-09-13 [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast +[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any [`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation [`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs new file mode 100644 index 00000000000..03621887a34 --- /dev/null +++ b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; + +use super::FN_TO_NUMERIC_CAST_ANY; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { + // We allow casts from any function type to any function type. + match cast_to.kind() { + ty::FnDef(..) | ty::FnPtr(..) => return, + _ => { /* continue to checks */ }, + } + + match cast_from.kind() { + ty::FnDef(..) | ty::FnPtr(_) => { + let mut applicability = Applicability::MaybeIncorrect; + let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability); + + span_lint_and_sugg( + cx, + FN_TO_NUMERIC_CAST_ANY, + expr.span, + &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), + "did you mean to invoke the function?", + format!("{}() as {}", from_snippet, cast_to), + applicability, + ); + }, + _ => {}, + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 27e1bea7993..f0800c6a6f1 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -7,6 +7,7 @@ mod cast_sign_loss; mod char_lit_as_u8; mod fn_to_numeric_cast; +mod fn_to_numeric_cast_any; mod fn_to_numeric_cast_with_truncation; mod ptr_as_ptr; mod unnecessary_cast; @@ -251,6 +252,42 @@ "casting a function pointer to a numeric type not wide enough to store the address" } +declare_clippy_lint! { + /// ### What it does + /// Checks for casts of a function pointer to any integer type. + /// + /// ### Why is this bad? + /// Casting a function pointer to an integer can have surprising results and can occur + /// accidentally if parantheses are omitted from a function call. If you aren't doing anything + /// low-level with function pointers then you can opt-out of casting functions to integers in + /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function + /// pointer casts in your code. + /// + /// ### Example + /// ```rust + /// // Bad: fn1 is cast as `usize` + /// fn fn1() -> u16 { + /// 1 + /// }; + /// let _ = fn1 as usize; + /// + /// // Good: maybe you intended to call the function? + /// fn fn2() -> u16 { + /// 1 + /// }; + /// let _ = fn2() as usize; + /// + /// // Good: maybe you intended to cast it to a function type? + /// fn fn3() -> u16 { + /// 1 + /// } + /// let _ = fn3 as fn() -> u16; + /// ``` + pub FN_TO_NUMERIC_CAST_ANY, + restriction, + "casting a function pointer to any integer type" +} + declare_clippy_lint! { /// ### What it does /// Checks for casts of `&T` to `&mut T` anywhere in the code. @@ -360,6 +397,7 @@ pub fn new(msrv: Option) -> Self { CAST_REF_TO_MUT, CAST_PTR_ALIGNMENT, UNNECESSARY_CAST, + FN_TO_NUMERIC_CAST_ANY, FN_TO_NUMERIC_CAST, FN_TO_NUMERIC_CAST_WITH_TRUNCATION, CHAR_LIT_AS_U8, @@ -385,6 +423,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { return; } + fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 2ba2b3da55c..3c6d8103b6d 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -67,6 +67,7 @@ casts::CAST_SIGN_LOSS, casts::CHAR_LIT_AS_U8, casts::FN_TO_NUMERIC_CAST, + casts::FN_TO_NUMERIC_CAST_ANY, casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION, casts::PTR_AS_PTR, casts::UNNECESSARY_CAST, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 4463dea5fcb..503f4f64a0e 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -8,6 +8,7 @@ LintId::of(as_conversions::AS_CONVERSIONS), LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), + LintId::of(casts::FN_TO_NUMERIC_CAST_ANY), LintId::of(create_dir::CREATE_DIR), LintId::of(dbg_macro::DBG_MACRO), LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK), diff --git a/tests/ui/fn_to_numeric_cast_any.rs b/tests/ui/fn_to_numeric_cast_any.rs new file mode 100644 index 00000000000..46704683926 --- /dev/null +++ b/tests/ui/fn_to_numeric_cast_any.rs @@ -0,0 +1,76 @@ +#![warn(clippy::fn_to_numeric_cast_any)] +#![allow(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] + +fn foo() -> u8 { + 0 +} + +fn generic_foo(x: T) -> T { + x +} + +trait Trait { + fn static_method() -> u32 { + 2 + } +} + +struct Struct; + +impl Trait for Struct {} + +fn fn_pointer_to_integer() { + let _ = foo as i8; + let _ = foo as i16; + let _ = foo as i32; + let _ = foo as i64; + let _ = foo as i128; + let _ = foo as isize; + + let _ = foo as u8; + let _ = foo as u16; + let _ = foo as u32; + let _ = foo as u64; + let _ = foo as u128; + let _ = foo as usize; +} + +fn static_method_to_integer() { + let _ = Struct::static_method as usize; +} + +fn fn_with_fn_arg(f: fn(i32) -> u32) -> usize { + f as usize +} + +fn fn_with_generic_static_trait_method() -> usize { + T::static_method as usize +} + +fn closure_to_fn_to_integer() { + let clos = |x| x * 2_u32; + + let _ = (clos as fn(u32) -> u32) as usize; +} + +fn fn_to_raw_ptr() { + let _ = foo as *const (); +} + +fn cast_fn_to_self() { + // Casting to the same function pointer type should be permitted. + let _ = foo as fn() -> u8; +} + +fn cast_generic_to_concrete() { + // Casting to a more concrete function pointer type should be permitted. + let _ = generic_foo as fn(usize) -> usize; +} + +fn cast_closure_to_fn() { + // Casting a closure to a function pointer should be permitted. + let id = |x| x; + let _ = id as fn(usize) -> usize; +} + +fn main() {} diff --git a/tests/ui/fn_to_numeric_cast_any.stderr b/tests/ui/fn_to_numeric_cast_any.stderr new file mode 100644 index 00000000000..a6c4a77672f --- /dev/null +++ b/tests/ui/fn_to_numeric_cast_any.stderr @@ -0,0 +1,106 @@ +error: casting function pointer `foo` to `i8` + --> $DIR/fn_to_numeric_cast_any.rs:23:13 + | +LL | let _ = foo as i8; + | ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8` + | + = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings` + +error: casting function pointer `foo` to `i16` + --> $DIR/fn_to_numeric_cast_any.rs:24:13 + | +LL | let _ = foo as i16; + | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i16` + +error: casting function pointer `foo` to `i32` + --> $DIR/fn_to_numeric_cast_any.rs:25:13 + | +LL | let _ = foo as i32; + | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i32` + +error: casting function pointer `foo` to `i64` + --> $DIR/fn_to_numeric_cast_any.rs:26:13 + | +LL | let _ = foo as i64; + | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i64` + +error: casting function pointer `foo` to `i128` + --> $DIR/fn_to_numeric_cast_any.rs:27:13 + | +LL | let _ = foo as i128; + | ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i128` + +error: casting function pointer `foo` to `isize` + --> $DIR/fn_to_numeric_cast_any.rs:28:13 + | +LL | let _ = foo as isize; + | ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as isize` + +error: casting function pointer `foo` to `u8` + --> $DIR/fn_to_numeric_cast_any.rs:30:13 + | +LL | let _ = foo as u8; + | ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u8` + +error: casting function pointer `foo` to `u16` + --> $DIR/fn_to_numeric_cast_any.rs:31:13 + | +LL | let _ = foo as u16; + | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u16` + +error: casting function pointer `foo` to `u32` + --> $DIR/fn_to_numeric_cast_any.rs:32:13 + | +LL | let _ = foo as u32; + | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u32` + +error: casting function pointer `foo` to `u64` + --> $DIR/fn_to_numeric_cast_any.rs:33:13 + | +LL | let _ = foo as u64; + | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u64` + +error: casting function pointer `foo` to `u128` + --> $DIR/fn_to_numeric_cast_any.rs:34:13 + | +LL | let _ = foo as u128; + | ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u128` + +error: casting function pointer `foo` to `usize` + --> $DIR/fn_to_numeric_cast_any.rs:35:13 + | +LL | let _ = foo as usize; + | ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as usize` + +error: casting function pointer `Struct::static_method` to `usize` + --> $DIR/fn_to_numeric_cast_any.rs:39:13 + | +LL | let _ = Struct::static_method as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `Struct::static_method() as usize` + +error: casting function pointer `f` to `usize` + --> $DIR/fn_to_numeric_cast_any.rs:43:5 + | +LL | f as usize + | ^^^^^^^^^^ help: did you mean to invoke the function?: `f() as usize` + +error: casting function pointer `T::static_method` to `usize` + --> $DIR/fn_to_numeric_cast_any.rs:47:5 + | +LL | T::static_method as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `T::static_method() as usize` + +error: casting function pointer `(clos as fn(u32) -> u32)` to `usize` + --> $DIR/fn_to_numeric_cast_any.rs:53:13 + | +LL | let _ = (clos as fn(u32) -> u32) as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `(clos as fn(u32) -> u32)() as usize` + +error: casting function pointer `foo` to `*const ()` + --> $DIR/fn_to_numeric_cast_any.rs:57:13 + | +LL | let _ = foo as *const (); + | ^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as *const ()` + +error: aborting due to 17 previous errors + From 412b862fba9df1219ab4fb5bd5a096bfbdaa37d2 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Fri, 1 Oct 2021 23:25:48 -0400 Subject: [PATCH 005/100] Add undocumented_unsafe_blocks lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/lib.rs | 2 + .../src/undocumented_unsafe_blocks.rs | 225 ++++++++++++++ tests/ui/undocumented_unsafe_blocks.rs | 287 ++++++++++++++++++ tests/ui/undocumented_unsafe_blocks.stderr | 159 ++++++++++ 7 files changed, 676 insertions(+) create mode 100644 clippy_lints/src/undocumented_unsafe_blocks.rs create mode 100644 tests/ui/undocumented_unsafe_blocks.rs create mode 100644 tests/ui/undocumented_unsafe_blocks.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index b13a5d76002..13067e4e92a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3033,6 +3033,7 @@ Released 2018-09-13 [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds +[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks [`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 3c6d8103b6d..3c4b720671a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -465,6 +465,7 @@ types::REDUNDANT_ALLOCATION, types::TYPE_COMPLEXITY, types::VEC_BOX, + undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS, undropped_manually_drops::UNDROPPED_MANUALLY_DROPS, unicode::INVISIBLE_CHARACTERS, unicode::NON_ASCII_LITERAL, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 503f4f64a0e..3d68a6e9009 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -57,6 +57,7 @@ LintId::of(strings::STR_TO_STRING), LintId::of(types::RC_BUFFER), LintId::of(types::RC_MUTEX), + LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS), LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), LintId::of(verbose_file_reads::VERBOSE_FILE_READS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9fc6a9e0ccc..7e1bcbbd0ed 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -358,6 +358,7 @@ macro_rules! declare_clippy_lint { mod transmuting_null; mod try_err; mod types; +mod undocumented_unsafe_blocks; mod undropped_manually_drops; mod unicode; mod unit_return_expecting_ord; @@ -769,6 +770,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic)); let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send))); + store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); } #[rustfmt::skip] diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs new file mode 100644 index 00000000000..e08e4d03c7e --- /dev/null +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -0,0 +1,225 @@ +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet}; +use clippy_utils::{in_macro, is_lint_allowed}; +use rustc_errors::Applicability; +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource}; +use rustc_lexer::TokenKind; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::TyCtxt; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{BytePos, Span}; +use std::borrow::Cow; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `unsafe` blocks without a `// Safety: ` comment + /// explaining why the unsafe operations performed inside + /// the block are safe. + /// + /// ### Why is this bad? + /// Undocumented unsafe blocks can make it difficult to + /// read and maintain code, as well as uncover unsoundness + /// and bugs. + /// + /// ### Example + /// ```rust + /// use std::ptr::NonNull; + /// let a = &mut 42; + /// + /// let ptr = unsafe { NonNull::new_unchecked(a) }; + /// ``` + /// Use instead: + /// ```rust + /// use std::ptr::NonNull; + /// let a = &mut 42; + /// + /// // Safety: references are guaranteed to be non-null. + /// let ptr = unsafe { NonNull::new_unchecked(a) }; + /// ``` + pub UNDOCUMENTED_UNSAFE_BLOCKS, + restriction, + "creating an unsafe block without explaining why it is safe" +} + +impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]); + +#[derive(Default)] +pub struct UndocumentedUnsafeBlocks { + pub local_level: u32, + pub local_span: Option, + // The local was already checked for an overall safety comment + // There is no need to continue checking the blocks in the local + pub local_checked: bool, + // Since we can only check the blocks from expanded macros + // We have to omit the suggestion due to the actual definition + // Not being available to us + pub macro_expansion: bool, +} + +impl LateLintPass<'_> for UndocumentedUnsafeBlocks { + fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) { + if_chain! { + if !self.local_checked; + if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id); + if !in_external_macro(cx.tcx.sess, block.span); + if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules; + if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id); + if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false); + then { + let mut span = block.span; + + if let Some(local_span) = self.local_span { + span = local_span; + + let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span); + + if result.unwrap_or(true) { + self.local_checked = true; + return; + } + } + + self.lint(cx, span); + } + } + } + + fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) { + if_chain! { + if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id); + if !in_external_macro(cx.tcx.sess, local.span); + if let Some(init) = local.init; + then { + self.visit_expr(init); + + if self.local_level > 0 { + self.local_span = Some(local.span); + } + } + } + } + + fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) { + self.local_level = self.local_level.saturating_sub(1); + + if self.local_level == 0 { + self.local_checked = false; + self.local_span = None; + } + } +} + +impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'v Expr<'v>) { + match ex.kind { + ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1), + _ => walk_expr(self, ex), + } + } +} + +impl UndocumentedUnsafeBlocks { + fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option { + let map = tcx.hir(); + let source_map = tcx.sess.source_map(); + + let enclosing_scope_span = map.opt_span(enclosing_hir_id)?; + + let between_span = if in_macro(block_span) { + self.macro_expansion = true; + enclosing_scope_span.with_hi(block_span.hi()) + } else { + self.macro_expansion = false; + enclosing_scope_span.to(block_span) + }; + + let file_name = source_map.span_to_filename(between_span); + let source_file = source_map.get_source_file(&file_name)?; + + let lex_start = (between_span.lo().0 + 1) as usize; + let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string(); + + let mut pos = 0; + let mut comment = false; + + for token in rustc_lexer::tokenize(&src_str) { + match token.kind { + TokenKind::LineComment { doc_style: None } + | TokenKind::BlockComment { + doc_style: None, + terminated: true, + } => { + let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase(); + + if comment_str.contains("SAFETY:") { + comment = true; + } + }, + // We need to add all whitespace to `pos` before checking the comment's line number + TokenKind::Whitespace => {}, + _ => { + if comment { + // Get the line number of the "comment" (really wherever the trailing whitespace ended) + let comment_line_num = source_file + .lookup_file_pos_with_col_display(BytePos((lex_start + pos).try_into().unwrap())) + .0; + // Find the block/local's line number + let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line; + + // Check the comment is immediately followed by the block/local + if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num { + return Some(true); + } + + comment = false; + } + }, + } + + pos += token.len; + } + + Some(false) + } + + fn lint(&self, cx: &LateContext<'_>, mut span: Span) { + let source_map = cx.tcx.sess.source_map(); + + if source_map.is_multiline(span) { + span = source_map.span_until_char(span, '\n'); + } + + if self.macro_expansion { + span_lint_and_help( + cx, + UNDOCUMENTED_UNSAFE_BLOCKS, + span, + "unsafe block in macro expansion missing a safety comment", + None, + "consider adding a safety comment in the macro definition", + ); + } else { + let block_indent = indent_of(cx, span); + let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, "..")); + + span_lint_and_sugg( + cx, + UNDOCUMENTED_UNSAFE_BLOCKS, + span, + "unsafe block missing a safety comment", + "consider adding a safety comment", + reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(), + Applicability::HasPlaceholders, + ); + } + } +} diff --git a/tests/ui/undocumented_unsafe_blocks.rs b/tests/ui/undocumented_unsafe_blocks.rs new file mode 100644 index 00000000000..52577323a58 --- /dev/null +++ b/tests/ui/undocumented_unsafe_blocks.rs @@ -0,0 +1,287 @@ +#![warn(clippy::undocumented_unsafe_blocks)] + +// Valid comments + +fn nested_local() { + let _ = { + let _ = { + // Safety: + let _ = unsafe {}; + }; + }; +} + +fn deep_nest() { + let _ = { + let _ = { + // Safety: + let _ = unsafe {}; + + // Safety: + unsafe {}; + + let _ = { + let _ = { + let _ = { + let _ = { + let _ = { + // Safety: + let _ = unsafe {}; + + // Safety: + unsafe {}; + }; + }; + }; + + // Safety: + unsafe {}; + }; + }; + }; + + // Safety: + unsafe {}; + }; + + // Safety: + unsafe {}; +} + +fn local_tuple_expression() { + // Safety: + let _ = (42, unsafe {}); +} + +fn line_comment() { + // Safety: + unsafe {} +} + +fn line_comment_newlines() { + // Safety: + + unsafe {} +} + +fn line_comment_empty() { + // Safety: + // + // + // + unsafe {} +} + +fn line_comment_with_extras() { + // This is a description + // Safety: + unsafe {} +} + +fn block_comment() { + /* Safety: */ + unsafe {} +} + +fn block_comment_newlines() { + /* Safety: */ + + unsafe {} +} + +#[rustfmt::skip] +fn inline_block_comment() { + /* Safety: */unsafe {} +} + +fn block_comment_with_extras() { + /* This is a description + * Safety: + */ + unsafe {} +} + +fn block_comment_terminator_same_line() { + /* This is a description + * Safety: */ + unsafe {} +} + +fn buried_safety() { + // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor + // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation + // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in + // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + // laborum. Safety: + // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi + // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio + // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl + // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus. + unsafe {} +} + +fn safety_with_prepended_text() { + // This is a test. Safety: + unsafe {} +} + +fn local_line_comment() { + // Safety: + let _ = unsafe {}; +} + +fn local_block_comment() { + /* Safety: */ + let _ = unsafe {}; +} + +fn comment_array() { + // Safety: + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; +} + +fn comment_tuple() { + // Safety: + let _ = (42, unsafe {}, "test", unsafe {}); +} + +fn comment_unary() { + // Safety: + let _ = *unsafe { &42 }; +} + +#[allow(clippy::match_single_binding)] +fn comment_match() { + // Safety: + let _ = match unsafe {} { + _ => {}, + }; +} + +fn comment_addr_of() { + // Safety: + let _ = &unsafe {}; +} + +fn comment_repeat() { + // Safety: + let _ = [unsafe {}; 5]; +} + +fn comment_macro_call() { + macro_rules! t { + ($b:expr) => { + $b + }; + } + + t!( + // Safety: + unsafe {} + ); +} + +fn comment_macro_def() { + macro_rules! t { + () => { + // Safety: + unsafe {} + }; + } + + t!(); +} + +fn non_ascii_comment() { + // ॐ᧻໒ Safety: ௵∰ + unsafe {}; +} + +fn local_commented_block() { + let _ = + // Safety: + unsafe {}; +} + +fn local_nest() { + // Safety: + let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})]; +} + +// Invalid comments + +fn no_comment() { + unsafe {} +} + +fn no_comment_array() { + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; +} + +fn no_comment_tuple() { + let _ = (42, unsafe {}, "test", unsafe {}); +} + +fn no_comment_unary() { + let _ = *unsafe { &42 }; +} + +#[allow(clippy::match_single_binding)] +fn no_comment_match() { + let _ = match unsafe {} { + _ => {}, + }; +} + +fn no_comment_addr_of() { + let _ = &unsafe {}; +} + +fn no_comment_repeat() { + let _ = [unsafe {}; 5]; +} + +fn local_no_comment() { + let _ = unsafe {}; +} + +fn no_comment_macro_call() { + macro_rules! t { + ($b:expr) => { + $b + }; + } + + t!(unsafe {}); +} + +fn no_comment_macro_def() { + macro_rules! t { + () => { + unsafe {} + }; + } + + t!(); +} + +fn trailing_comment() { + unsafe {} // Safety: +} + +fn internal_comment() { + unsafe { + // Safety: + } +} + +fn interference() { + // Safety + + let _ = 42; + + unsafe {}; +} + +fn main() {} diff --git a/tests/ui/undocumented_unsafe_blocks.stderr b/tests/ui/undocumented_unsafe_blocks.stderr new file mode 100644 index 00000000000..b32069a334c --- /dev/null +++ b/tests/ui/undocumented_unsafe_blocks.stderr @@ -0,0 +1,159 @@ +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:215:5 + | +LL | unsafe {} + | ^^^^^^^^^ + | + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + unsafe {} + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:219:5 + | +LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:223:5 + | +LL | let _ = (42, unsafe {}, "test", unsafe {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + let _ = (42, unsafe {}, "test", unsafe {}); + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:227:5 + | +LL | let _ = *unsafe { &42 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + let _ = *unsafe { &42 }; + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:232:5 + | +LL | let _ = match unsafe {} { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + let _ = match unsafe {} { + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:238:5 + | +LL | let _ = &unsafe {}; + | ^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + let _ = &unsafe {}; + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:242:5 + | +LL | let _ = [unsafe {}; 5]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + let _ = [unsafe {}; 5]; + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:246:5 + | +LL | let _ = unsafe {}; + | ^^^^^^^^^^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + let _ = unsafe {}; + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:256:8 + | +LL | t!(unsafe {}); + | ^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ t!(// Safety: ... +LL ~ unsafe {}); + | + +error: unsafe block in macro expansion missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:262:13 + | +LL | unsafe {} + | ^^^^^^^^^ +... +LL | t!(); + | ----- in this macro invocation + | + = help: consider adding a safety comment in the macro definition + = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:270:5 + | +LL | unsafe {} // Safety: + | ^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL ~ unsafe {} // Safety: + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:274:5 + | +LL | unsafe { + | ^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL + unsafe { + | + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:284:5 + | +LL | unsafe {}; + | ^^^^^^^^^ + | +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL ~ unsafe {}; + | + +error: aborting due to 13 previous errors + From 28fb591b6e681493b6ba3917146fbfe410dd45d0 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 8 Oct 2021 15:26:10 +0200 Subject: [PATCH 006/100] Do not expand macros in equatable_if_let suggestion --- clippy_lints/src/equatable_if_let.rs | 8 ++++---- tests/ui/equatable_if_let.fixed | 9 +++++++++ tests/ui/equatable_if_let.rs | 9 +++++++++ tests/ui/equatable_if_let.stderr | 8 +++++++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 0c6ba91c943..e8b1d6f6eda 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; @@ -77,9 +77,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { let pat_str = match pat.kind { PatKind::Struct(..) => format!( "({})", - snippet_with_applicability(cx, pat.span, "..", &mut applicability), + snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0, ), - _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(), + _ => snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(), }; span_lint_and_sugg( cx, @@ -89,7 +89,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { "try", format!( "{} == {}", - snippet_with_applicability(cx, exp.span, "..", &mut applicability), + snippet_with_context(cx, exp.span, expr.span.ctxt(), "..", &mut applicability).0, pat_str, ), applicability, diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index ba72cc237b4..88918d9671e 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -66,4 +66,13 @@ fn main() { if g == NotStructuralEq::A {} if let Some(NotPartialEq::A) = Some(f) {} if Some(g) == Some(NotStructuralEq::A) {} + + macro_rules! m1 { + (x) => { + "abc" + }; + } + if "abc" == m1!(x) { + println!("OK"); + } } diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index 12526ca193d..9a7ab75ef45 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -66,4 +66,13 @@ fn main() { if let NotStructuralEq::A = g {} if let Some(NotPartialEq::A) = Some(f) {} if let Some(NotStructuralEq::A) = Some(g) {} + + macro_rules! m1 { + (x) => { + "abc" + }; + } + if let m1!(x) = "abc" { + println!("OK"); + } } diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index 79ef919384d..760ff88f448 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -60,5 +60,11 @@ error: this pattern matching can be expressed using equality LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` -error: aborting due to 10 previous errors +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:75:8 + | +LL | if let m1!(x) = "abc" { + | ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)` + +error: aborting due to 11 previous errors From b423b85ca99c2a085797e228ec405038bbd3308f Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 8 Oct 2021 16:16:56 +0200 Subject: [PATCH 007/100] Don't trigger semicolon_if_nothing_returned in expanded code Before this lint didn't trigger on macros. With rust-lang/rust#88175 this isn't enough anymore. In this PR a `WhileLoop` desugaring kind was introduced. This overrides the span of expanded expressions when lowering the while loop. So if a while loop is in a macro, the expressions that it expands to are no longer marked with `ExpnKind::Macro`, but with `ExpnKind::Desugaring`. In general, this is the correct behavior and the same that is done for `ForLoop`s. It just tripped up this lint. --- clippy_lints/src/semicolon_if_nothing_returned.rs | 4 ++-- tests/ui/semicolon_if_nothing_returned.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 6966230156c..c0e4914efe0 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,7 +1,7 @@ use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{in_macro, sugg}; +use clippy_utils::sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; @@ -39,7 +39,7 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if_chain! { - if !in_macro(block.span); + if !block.span.from_expansion(); if let Some(expr) = block.expr; let t_expr = cx.typeck_results().expr_ty(expr); if t_expr.is_unit(); diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index 9644a232968..7a45f1b18d4 100644 --- a/tests/ui/semicolon_if_nothing_returned.rs +++ b/tests/ui/semicolon_if_nothing_returned.rs @@ -98,3 +98,15 @@ fn unsafe_checks() { let mut s = MaybeUninit::::uninit(); let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) }; } + +// Issue #7768 +#[rustfmt::skip] +fn macro_with_semicolon() { + macro_rules! repro { + () => { + while false { + } + }; + } + repro!(); +} From 72078faf9122e99f496f3f868d5e4ff59cfa0b00 Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Fri, 8 Oct 2021 20:45:44 +0100 Subject: [PATCH 008/100] Allow giving reasons for `disallowed_types` Co-authored-by: James Hinshelwood --- clippy_lints/src/disallowed_type.rs | 59 +++++++++++-------- clippy_lints/src/lib.rs | 4 +- clippy_lints/src/utils/conf.rs | 10 +++- .../ui-toml/toml_disallowed_type/clippy.toml | 6 +- .../conf_disallowed_type.rs | 4 ++ .../conf_disallowed_type.stderr | 34 +++++++---- 6 files changed, 79 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/disallowed_type.rs b/clippy_lints/src/disallowed_type.rs index 87124f093a8..261e9af11c8 100644 --- a/clippy_lints/src/disallowed_type.rs +++ b/clippy_lints/src/disallowed_type.rs @@ -1,12 +1,14 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_then; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; + +use crate::utils::conf; declare_clippy_lint! { /// ### What it does @@ -38,33 +40,30 @@ } #[derive(Clone, Debug)] pub struct DisallowedType { - disallowed: FxHashSet>, - def_ids: FxHashSet, - prim_tys: FxHashSet, + disallowed: Vec, + def_ids: FxHashMap>, + prim_tys: FxHashMap>, } impl DisallowedType { - pub fn new(disallowed: &FxHashSet) -> Self { + pub fn new(disallowed: Vec) -> Self { Self { - disallowed: disallowed - .iter() - .map(|s| s.split("::").map(Symbol::intern).collect::>()) - .collect(), - def_ids: FxHashSet::default(), - prim_tys: FxHashSet::default(), + disallowed, + def_ids: FxHashMap::default(), + prim_tys: FxHashMap::default(), } } fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { match res { Res::Def(_, did) => { - if self.def_ids.contains(did) { - emit(cx, &cx.tcx.def_path_str(*did), span); + if let Some(reason) = self.def_ids.get(did) { + emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref()); } }, Res::PrimTy(prim) => { - if self.prim_tys.contains(prim) { - emit(cx, prim.name_str(), span); + if let Some(reason) = self.prim_tys.get(prim) { + emit(cx, prim.name_str(), span, reason.as_deref()); } }, _ => {}, @@ -76,14 +75,21 @@ fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { impl<'tcx> LateLintPass<'tcx> for DisallowedType { fn check_crate(&mut self, cx: &LateContext<'_>) { - for path in &self.disallowed { - let segs = path.iter().map(ToString::to_string).collect::>(); - match clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::>()) { + for conf in &self.disallowed { + let (path, reason) = match conf { + conf::DisallowedType::Simple(path) => (path, None), + conf::DisallowedType::WithReason { path, reason } => ( + path, + reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)), + ), + }; + let segs: Vec<_> = path.split("::").collect(); + match clippy_utils::path_to_res(cx, &segs) { Res::Def(_, id) => { - self.def_ids.insert(id); + self.def_ids.insert(id, reason); }, Res::PrimTy(ty) => { - self.prim_tys.insert(ty); + self.prim_tys.insert(ty, reason); }, _ => {}, } @@ -107,11 +113,16 @@ fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTrait } } -fn emit(cx: &LateContext<'_>, name: &str, span: Span) { - span_lint( +fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) { + span_lint_and_then( cx, DISALLOWED_TYPE, span, &format!("`{}` is not allowed according to config", name), + |diag| { + if let Some(reason) = reason { + diag.note(reason); + } + }, ); } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e1bcbbd0ed..8af76cbed6e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -757,8 +757,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison)); store.register_early_pass(move || Box::new(module_style::ModStyle)); store.register_late_pass(|| Box::new(unused_async::UnusedAsync)); - let disallowed_types = conf.disallowed_types.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(&disallowed_types))); + let disallowed_types = conf.disallowed_types.clone(); + store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(disallowed_types.clone()))); let import_renames = conf.enforced_import_renames.clone(); store.register_late_pass(move || Box::new(missing_enforced_import_rename::ImportRename::new(import_renames.clone()))); let scripts = conf.allowed_scripts.clone(); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 6cbada4c150..d05c52122d5 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -23,6 +23,14 @@ pub enum DisallowedMethod { WithReason { path: String, reason: Option }, } +/// A single disallowed type, used by the `DISALLOWED_TYPE` lint. +#[derive(Clone, Debug, Deserialize)] +#[serde(untagged)] +pub enum DisallowedType { + Simple(String), + WithReason { path: String, reason: Option }, +} + /// Conf with parse errors #[derive(Default)] pub struct TryConf { @@ -255,7 +263,7 @@ pub(crate) fn get_configuration_metadata() -> Vec { /// Lint: DISALLOWED_TYPE. /// /// The list of disallowed types, written as fully qualified paths. - (disallowed_types: Vec = Vec::new()), + (disallowed_types: Vec = Vec::new()), /// Lint: UNREADABLE_LITERAL. /// /// Should the fraction of a decimal be linted to include separators. diff --git a/tests/ui-toml/toml_disallowed_type/clippy.toml b/tests/ui-toml/toml_disallowed_type/clippy.toml index dac4446703b..6cb9e2ef954 100644 --- a/tests/ui-toml/toml_disallowed_type/clippy.toml +++ b/tests/ui-toml/toml_disallowed_type/clippy.toml @@ -7,5 +7,9 @@ disallowed-types = [ "std::time::Instant", "std::io::Read", "std::primitive::usize", - "bool" + "bool", + # can give path and reason with an inline table + { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" }, + # can use an inline table but omit reason + { path = "std::net::TcpListener" }, ] diff --git a/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs index 0871a3073ab..410f0765055 100644 --- a/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs +++ b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs @@ -25,6 +25,10 @@ fn const_generics() {} static BAD: foo::atomic::AtomicPtr<()> = foo::atomic::AtomicPtr::new(std::ptr::null_mut()); +fn ip(_: std::net::Ipv4Addr) {} + +fn listener(_: std::net::TcpListener) {} + #[allow(clippy::diverging_sub_expression)] fn main() { let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); diff --git a/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr index 90ce7db2cc4..08a400a8367 100644 --- a/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr +++ b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr @@ -60,59 +60,73 @@ error: `usize` is not allowed according to config LL | struct GenArg([u8; U]); | ^^^^^ +error: `std::net::Ipv4Addr` is not allowed according to config + --> $DIR/conf_disallowed_type.rs:28:10 + | +LL | fn ip(_: std::net::Ipv4Addr) {} + | ^^^^^^^^^^^^^^^^^^ + | + = note: no IPv4 allowed (from clippy.toml) + +error: `std::net::TcpListener` is not allowed according to config + --> $DIR/conf_disallowed_type.rs:30:16 + | +LL | fn listener(_: std::net::TcpListener) {} + | ^^^^^^^^^^^^^^^^^^^^^ + error: `std::collections::HashMap` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:30:48 + --> $DIR/conf_disallowed_type.rs:34:48 | LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `std::collections::HashMap` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:30:12 + --> $DIR/conf_disallowed_type.rs:34:12 | LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `std::time::Instant` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:31:13 + --> $DIR/conf_disallowed_type.rs:35:13 | LL | let _ = Sneaky::now(); | ^^^^^^ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:32:13 + --> $DIR/conf_disallowed_type.rs:36:13 | LL | let _ = foo::atomic::AtomicU32::new(0); | ^^^^^^^^^^^^^^^^^^^^^^ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:33:17 + --> $DIR/conf_disallowed_type.rs:37:17 | LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `std::sync::atomic::AtomicU32` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:33:48 + --> $DIR/conf_disallowed_type.rs:37:48 | LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1); | ^^^^^^^^^^^^^^^^^^^^^^ error: `syn::TypePath` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:34:43 + --> $DIR/conf_disallowed_type.rs:38:43 | LL | let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default(); | ^^^^^^^^^^^^^ error: `syn::Ident` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:35:13 + --> $DIR/conf_disallowed_type.rs:39:13 | LL | let _ = syn::Ident::new("", todo!()); | ^^^^^^^^^^ error: `usize` is not allowed according to config - --> $DIR/conf_disallowed_type.rs:37:12 + --> $DIR/conf_disallowed_type.rs:41:12 | LL | let _: usize = 64_usize; | ^^^^^ -error: aborting due to 19 previous errors +error: aborting due to 21 previous errors From da76c06209451fa01d5248374869b689116ae05e Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 9 Oct 2021 05:58:05 +0200 Subject: [PATCH 009/100] Add `--msrv` option to `new_lint` command --- clippy_dev/src/main.rs | 6 ++ clippy_dev/src/new_lint.rs | 110 +++++++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 8fdeba9842a..b5c04efce3b 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -28,6 +28,7 @@ fn main() { matches.value_of("pass"), matches.value_of("name"), matches.value_of("category"), + matches.is_present("msrv"), ) { Ok(_) => update_lints::run(update_lints::UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {}", e), @@ -147,6 +148,11 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { "internal_warn", ]) .takes_value(true), + ) + .arg( + Arg::with_name("msrv") + .long("msrv") + .help("Add MSRV config code to the lint"), ), ) .subcommand( diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 3a81aaba6de..ebbe26c46f7 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -32,7 +32,7 @@ fn context>(self, text: C) -> Self { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> io::Result<()> { +pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>, msrv: bool) -> io::Result<()> { let lint = LintData { pass: pass.expect("`pass` argument is validated by clap"), name: lint_name.expect("`name` argument is validated by clap"), @@ -40,11 +40,11 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str project_root: clippy_project_root(), }; - create_lint(&lint).context("Unable to create lint implementation")?; + create_lint(&lint, msrv).context("Unable to create lint implementation")?; create_test(&lint).context("Unable to create a test for the new lint") } -fn create_lint(lint: &LintData<'_>) -> io::Result<()> { +fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"), @@ -55,6 +55,7 @@ fn create_lint(lint: &LintData<'_>) -> io::Result<()> { let camel_case_name = to_camel_case(lint.name); let lint_contents = get_lint_file_contents( + lint.pass, pass_type, pass_lifetimes, lint.name, @@ -62,6 +63,7 @@ fn create_lint(lint: &LintData<'_>) -> io::Result<()> { lint.category, pass_import, context_import, + enable_msrv, ); let lint_path = format!("clippy_lints/src/{}.rs", lint.name); @@ -155,6 +157,7 @@ fn get_manifest_contents(lint_name: &str, hint: &str) -> String { } fn get_lint_file_contents( + pass_name: &str, pass_type: &str, pass_lifetimes: &str, lint_name: &str, @@ -162,13 +165,41 @@ fn get_lint_file_contents( category: &str, pass_import: &str, context_import: &str, + enable_msrv: bool, ) -> String { - format!( - "use rustc_lint::{{{type}, {context_import}}}; -use rustc_session::{{declare_lint_pass, declare_tool_lint}}; -{pass_import} + let mut result = String::new(); -declare_clippy_lint! {{ + let name_camel = camel_case_name; + let name_upper = lint_name.to_uppercase(); + + result.push_str(&if enable_msrv { + format!( + "use clippy_utils::msrvs; +{pass_import} +use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; +use rustc_semver::RustcVersion; +use rustc_session::{{declare_tool_lint, impl_lint_pass}}; + +", + pass_type = pass_type, + pass_import = pass_import, + context_import = context_import, + ) + } else { + format!( + "{pass_import} +use rustc_lint::{{{context_import}, {pass_type}}}; +use rustc_session::{{declare_lint_pass, declare_tool_lint}}; + +", + pass_import = pass_import, + pass_type = pass_type, + context_import = context_import + ) + }); + + result.push_str(&format!( + "declare_clippy_lint! {{ /// ### What it does /// /// ### Why is this bad? @@ -184,20 +215,65 @@ fn get_lint_file_contents( pub {name_upper}, {category}, \"default lint description\" +}}", + name_upper = name_upper, + category = category, + )); + + result.push_str(&if enable_msrv { + format!( + " +pub struct {name_camel} {{ + msrv: Option, }} +impl {name_camel} {{ + #[must_use] + pub fn new(msrv: Option) -> Self {{ + Self {{ msrv }} + }} +}} + +impl_lint_pass!({name_camel} => [{name_upper}]); + +impl {pass_type}{pass_lifetimes} for {name_camel} {{ + extract_msrv_attr!({context_import}); +}} + +// TODO: Register the lint pass in `clippy_lints/src/lib.rs`, +// e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv))); +// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. +// TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. +// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` +", + pass_type = pass_type, + pass_lifetimes = pass_lifetimes, + pass_name = pass_name, + name_upper = name_upper, + name_camel = name_camel, + module_name = lint_name, + context_import = context_import, + ) + } else { + format!( + " declare_lint_pass!({name_camel} => [{name_upper}]); -impl {type}{lifetimes} for {name_camel} {{}} +impl {pass_type}{pass_lifetimes} for {name_camel} {{}} +// +// TODO: Register the lint pass in `clippy_lints/src/lib.rs`, +// e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel})); ", - type=pass_type, - lifetimes=pass_lifetimes, - name_upper=lint_name.to_uppercase(), - name_camel=camel_case_name, - category=category, - pass_import=pass_import, - context_import=context_import - ) + pass_type = pass_type, + pass_lifetimes = pass_lifetimes, + pass_name = pass_name, + name_upper = name_upper, + name_camel = name_camel, + module_name = lint_name, + ) + }); + + result } #[test] From b8782257ae54674101b08caeee59c0d51ff760c6 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 9 Oct 2021 05:58:05 +0200 Subject: [PATCH 010/100] Fix `clippy::too-many-arguments` violation --- clippy_dev/src/new_lint.rs | 46 ++++++++++++-------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index ebbe26c46f7..50297efde21 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -45,26 +45,7 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str } fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { - let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { - "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), - "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"), - _ => { - unreachable!("`pass_type` should only ever be `early` or `late`!"); - }, - }; - - let camel_case_name = to_camel_case(lint.name); - let lint_contents = get_lint_file_contents( - lint.pass, - pass_type, - pass_lifetimes, - lint.name, - &camel_case_name, - lint.category, - pass_import, - context_import, - enable_msrv, - ); + let lint_contents = get_lint_file_contents(lint, enable_msrv); let lint_path = format!("clippy_lints/src/{}.rs", lint.name); write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes()) @@ -156,20 +137,21 @@ fn get_manifest_contents(lint_name: &str, hint: &str) -> String { ) } -fn get_lint_file_contents( - pass_name: &str, - pass_type: &str, - pass_lifetimes: &str, - lint_name: &str, - camel_case_name: &str, - category: &str, - pass_import: &str, - context_import: &str, - enable_msrv: bool, -) -> String { +fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { let mut result = String::new(); - let name_camel = camel_case_name; + let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { + "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), + "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"), + _ => { + unreachable!("`pass_type` should only ever be `early` or `late`!"); + }, + }; + + let lint_name = lint.name; + let pass_name = lint.pass; + let category = lint.category; + let name_camel = to_camel_case(lint.name); let name_upper = lint_name.to_uppercase(); result.push_str(&if enable_msrv { From 7d9b21b90bc77ab26c8afefc78d6087aff34e4ad Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 9 Oct 2021 05:58:05 +0200 Subject: [PATCH 011/100] Use `indoc` for formatting --- clippy_dev/Cargo.toml | 1 + clippy_dev/src/new_lint.rs | 140 +++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 67 deletions(-) diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 4a13a452409..affb283017c 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] bytecount = "0.6" clap = "2.33" +indoc = "1.0" itertools = "0.10" opener = "0.5" regex = "1.5" diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 50297efde21..25320907bb4 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,4 +1,5 @@ use crate::clippy_project_root; +use indoc::indoc; use std::fs::{self, OpenOptions}; use std::io::prelude::*; use std::io::{self, ErrorKind}; @@ -105,12 +106,13 @@ fn to_camel_case(name: &str) -> String { fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String { let mut contents = format!( - "#![warn(clippy::{})] + indoc! {" + #![warn(clippy::{})] -fn main() {{ - // test code goes here -}} -", + fn main() {{ + // test code goes here + }} + "}, lint_name ); @@ -123,16 +125,16 @@ fn main() {{ fn get_manifest_contents(lint_name: &str, hint: &str) -> String { format!( - r#" -# {} + indoc! {r#" + # {} -[package] -name = "{}" -version = "0.1.0" -publish = false + [package] + name = "{}" + version = "0.1.0" + publish = false -[workspace] -"#, + [workspace] + "#}, hint, lint_name ) } @@ -156,24 +158,26 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result.push_str(&if enable_msrv { format!( - "use clippy_utils::msrvs; -{pass_import} -use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; -use rustc_semver::RustcVersion; -use rustc_session::{{declare_tool_lint, impl_lint_pass}}; + indoc! {" + use clippy_utils::msrvs; + {pass_import} + use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; + use rustc_semver::RustcVersion; + use rustc_session::{{declare_tool_lint, impl_lint_pass}}; -", + "}, pass_type = pass_type, pass_import = pass_import, context_import = context_import, ) } else { format!( - "{pass_import} -use rustc_lint::{{{context_import}, {pass_type}}}; -use rustc_session::{{declare_lint_pass, declare_tool_lint}}; + indoc! {" + {pass_import} + use rustc_lint::{{{context_import}, {pass_type}}}; + use rustc_session::{{declare_lint_pass, declare_tool_lint}}; -", + "}, pass_import = pass_import, pass_type = pass_type, context_import = context_import @@ -181,53 +185,55 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }); result.push_str(&format!( - "declare_clippy_lint! {{ - /// ### What it does - /// - /// ### Why is this bad? - /// - /// ### Example - /// ```rust - /// // example code where clippy issues a warning - /// ``` - /// Use instead: - /// ```rust - /// // example code which does not raise clippy warning - /// ``` - pub {name_upper}, - {category}, - \"default lint description\" -}}", + indoc! {" + declare_clippy_lint! {{ + /// ### What it does + /// + /// ### Why is this bad? + /// + /// ### Example + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + pub {name_upper}, + {category}, + \"default lint description\" + }} + "}, name_upper = name_upper, category = category, )); result.push_str(&if enable_msrv { format!( - " -pub struct {name_camel} {{ - msrv: Option, -}} + indoc! {" + pub struct {name_camel} {{ + msrv: Option, + }} -impl {name_camel} {{ - #[must_use] - pub fn new(msrv: Option) -> Self {{ - Self {{ msrv }} - }} -}} + impl {name_camel} {{ + #[must_use] + pub fn new(msrv: Option) -> Self {{ + Self {{ msrv }} + }} + }} -impl_lint_pass!({name_camel} => [{name_upper}]); + impl_lint_pass!({name_camel} => [{name_upper}]); -impl {pass_type}{pass_lifetimes} for {name_camel} {{ - extract_msrv_attr!({context_import}); -}} + impl {pass_type}{pass_lifetimes} for {name_camel} {{ + extract_msrv_attr!({context_import}); + }} -// TODO: Register the lint pass in `clippy_lints/src/lib.rs`, -// e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv))); -// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. -// TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. -// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` -", + // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, + // e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv))); + // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed. + // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`. + // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs` + "}, pass_type = pass_type, pass_lifetimes = pass_lifetimes, pass_name = pass_name, @@ -238,14 +244,14 @@ impl {pass_type}{pass_lifetimes} for {name_camel} {{ ) } else { format!( - " -declare_lint_pass!({name_camel} => [{name_upper}]); + indoc! {" + declare_lint_pass!({name_camel} => [{name_upper}]); -impl {pass_type}{pass_lifetimes} for {name_camel} {{}} -// -// TODO: Register the lint pass in `clippy_lints/src/lib.rs`, -// e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel})); -", + impl {pass_type}{pass_lifetimes} for {name_camel} {{}} + // + // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, + // e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel})); + "}, pass_type = pass_type, pass_lifetimes = pass_lifetimes, pass_name = pass_name, From 452181c69d2a106d9d5a1262b69e68a765c4b3e3 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Fri, 17 Sep 2021 02:55:26 -0400 Subject: [PATCH 012/100] Implement uninit_vec lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_correctness.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + .../src/methods/uninit_assumed_init.rs | 14 +- clippy_lints/src/uninit_vec.rs | 174 ++++++++++++++++++ clippy_utils/src/lib.rs | 10 + clippy_utils/src/paths.rs | 3 + tests/ui/uninit_vec.rs | 32 ++++ tests/ui/uninit_vec.stderr | 51 +++++ 11 files changed, 278 insertions(+), 12 deletions(-) create mode 100644 clippy_lints/src/uninit_vec.rs create mode 100644 tests/ui/uninit_vec.rs create mode 100644 tests/ui/uninit_vec.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 13067e4e92a..2c69432f31c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3038,6 +3038,7 @@ Released 2018-09-13 [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc [`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init +[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec [`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 3e6e0244754..f0ef0befea0 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -278,6 +278,7 @@ LintId::of(types::VEC_BOX), LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(uninit_vec::UNINIT_VEC), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_ARG), LintId::of(unit_types::UNIT_CMP), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index e0ef7b3b8af..8eb662195e2 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -63,6 +63,7 @@ LintId::of(transmuting_null::TRANSMUTING_NULL), LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), + LintId::of(uninit_vec::UNINIT_VEC), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_CMP), LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 3c4b720671a..401c5b78b38 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -470,6 +470,7 @@ unicode::INVISIBLE_CHARACTERS, unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, + uninit_vec::UNINIT_VEC, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_types::LET_UNIT_VALUE, unit_types::UNIT_ARG, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e1bcbbd0ed..829d5acdfde 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -361,6 +361,7 @@ macro_rules! declare_clippy_lint { mod undocumented_unsafe_blocks; mod undropped_manually_drops; mod unicode; +mod uninit_vec; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -518,6 +519,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch)); store.register_late_pass(|| Box::new(unicode::Unicode)); + store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|| Box::new(strings::StringAdd)); store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 1a5894e48d1..dbd91fb6d9d 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,9 +1,8 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_path_def_path, match_def_path, paths}; +use clippy_utils::{is_expr_path_def_path, is_uninit_ty_valid, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; use super::UNINIT_ASSUMED_INIT; @@ -13,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT); - if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); + if !is_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( cx, @@ -24,12 +23,3 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr } } } - -fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Array(component, _) => is_maybe_uninit_ty_valid(cx, component), - ty::Tuple(types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)), - ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), - _ => false, - } -} diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs new file mode 100644 index 00000000000..ff302289a1f --- /dev/null +++ b/clippy_lints/src/uninit_vec.rs @@ -0,0 +1,174 @@ +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{is_uninit_ty_valid, match_def_path, path_to_local_id, paths, peel_hir_expr_while, SpanlessEq}; +use rustc_hir::def::Res; +use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for the creation of uninitialized `Vec` by calling `set_len()` + /// immediately after `with_capacity()` or `reserve()`. + /// + /// ### Why is this bad? + /// It creates `Vec` that contains uninitialized data, which leads to an + /// undefined behavior with most safe operations. + /// Notably, using uninitialized `Vec` with generic `Read` is unsound. + /// + /// ### Example + /// ```rust,ignore + /// let mut vec: Vec = Vec::with_capacity(1000); + /// unsafe { vec.set_len(1000); } + /// reader.read(&mut vec); // undefined behavior! + /// ``` + /// Use an initialized buffer: + /// ```rust,ignore + /// let mut vec: Vec = vec![0; 1000]; + /// reader.read(&mut vec); + /// ``` + /// Or, wrap the content in `MaybeUninit`: + /// ```rust,ignore + /// let mut vec: Vec> = Vec::with_capacity(1000); + /// unsafe { vec.set_len(1000); } + /// ``` + pub UNINIT_VEC, + correctness, + "Vec with uninitialized data" +} + +declare_lint_pass!(UninitVec => [UNINIT_VEC]); + +impl<'tcx> LateLintPass<'tcx> for UninitVec { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + for w in block.stmts.windows(2) { + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { + handle_pair(cx, &w[0], expr); + } + } + + if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) { + handle_pair(cx, stmt, expr); + } + } +} + +fn handle_pair(cx: &LateContext<'tcx>, first: &'tcx Stmt<'tcx>, second: &'tcx Expr<'tcx>) { + if_chain! { + if let Some(vec) = extract_with_capacity_or_reserve_target(cx, first); + if let Some((set_len_self, call_span)) = extract_set_len_self(cx, second); + if vec.eq_expr(cx, set_len_self); + if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); + if let ty::Adt(_, substs) = vec_ty.kind(); + // Check T of Vec + if !is_uninit_ty_valid(cx, substs.type_at(0)); + then { + span_lint_and_note( + cx, + UNINIT_VEC, + call_span, + "calling `set_len()` immediately after reserving a buffer creates uninitialized values", + Some(first.span), + "the buffer is reserved here" + ); + } + } +} + +#[derive(Clone, Copy, Debug)] +enum LocalOrExpr<'tcx> { + Local(HirId), + Expr(&'tcx Expr<'tcx>), +} + +impl<'tcx> LocalOrExpr<'tcx> { + fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + match self { + LocalOrExpr::Local(hir_id) => path_to_local_id(expr, hir_id), + LocalOrExpr::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr), + } + } +} + +/// Returns the target vec of Vec::with_capacity() or Vec::reserve() +fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stmt<'_>) -> Option> { + match stmt.kind { + StmtKind::Local(local) => { + // let mut x = Vec::with_capacity() + if_chain! { + if let Some(init_expr) = local.init; + if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind; + if is_with_capacity(cx, init_expr); + then { + Some(LocalOrExpr::Local(hir_id)) + } else { + None + } + } + }, + StmtKind::Expr(expr) | StmtKind::Semi(expr) => { + match expr.kind { + ExprKind::Assign(lhs, rhs, _span) if is_with_capacity(cx, rhs) => { + // self.vec = Vec::with_capacity() + Some(LocalOrExpr::Expr(lhs)) + }, + ExprKind::MethodCall(_, _, [vec_expr, _], _) => { + // self.vec.reserve() + if_chain! { + if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if match_def_path(cx, id, &paths::VEC_RESERVE); + then { + Some(LocalOrExpr::Expr(vec_expr)) + } else { + None + } + } + }, + _ => None, + } + }, + _ => None, + } +} + +fn is_with_capacity(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> bool { + if_chain! { + if let ExprKind::Call(path_expr, _) = &expr.kind; + if let ExprKind::Path(qpath) = &path_expr.kind; + if let Res::Def(_, def_id) = cx.qpath_res(qpath, path_expr.hir_id); + then { + match_def_path(cx, def_id, &paths::VEC_WITH_CAPACITY) + } else { + false + } + } +} + +/// Returns self if the expression is Vec::set_len() +fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> { + // peel unsafe blocks in `unsafe { vec.set_len() }` + let expr = peel_hir_expr_while(expr, |e| { + if let ExprKind::Block(block, _) = e.kind { + match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) { + (None, Some(expr)) => Some(expr), + (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), None) => Some(expr), + _ => None, + } + } else { + None + } + }); + match expr.kind { + ExprKind::MethodCall(_, _, [vec_expr, _], _) => { + cx.typeck_results().type_dependent_def_id(expr.hir_id).and_then(|id| { + if match_def_path(cx, id, &paths::VEC_SET_LEN) { + Some((vec_expr, expr.span)) + } else { + None + } + }) + }, + _ => None, + } +} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 09eee78f0d1..00d2098a021 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1470,6 +1470,16 @@ pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { false } +/// Checks if a given type looks safe to be uninitialized. +pub fn is_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + match ty.kind() { + rustc_ty::Array(component, _) => is_uninit_ty_valid(cx, component), + rustc_ty::Tuple(types) => types.types().all(|ty| is_uninit_ty_valid(cx, ty)), + rustc_ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), + _ => false, + } +} + pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator> { (0..decl.inputs.len()).map(move |i| &body.params[i]) } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e43c5756021..dffe30910dd 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -183,5 +183,8 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; +pub const VEC_RESERVE: [&str; 4] = ["alloc", "vec", "Vec", "reserve"]; +pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; +pub const VEC_SET_LEN: [&str; 4] = ["alloc", "vec", "Vec", "set_len"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs new file mode 100644 index 00000000000..5e67288405a --- /dev/null +++ b/tests/ui/uninit_vec.rs @@ -0,0 +1,32 @@ +#![warn(clippy::uninit_vec)] + +use std::mem::MaybeUninit; + +fn main() { + // with_capacity() -> set_len() should be detected + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + vec.set_len(200); + } + + // reserve() -> set_len() should be detected + vec.reserve(1000); + unsafe { + vec.set_len(200); + } + + // test when both calls are enclosed in the same unsafe block + unsafe { + let mut vec: Vec = Vec::with_capacity(1000); + vec.set_len(200); + + vec.reserve(1000); + vec.set_len(200); + } + + // MaybeUninit-wrapped types should not be detected + let mut vec: Vec> = Vec::with_capacity(1000); + unsafe { + vec.set_len(200); + } +} diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr new file mode 100644 index 00000000000..1d7807fcf7d --- /dev/null +++ b/tests/ui/uninit_vec.stderr @@ -0,0 +1,51 @@ +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:9:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::uninit-vec` implied by `-D warnings` +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:7:5 + | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:15:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:13:5 + | +LL | vec.reserve(1000); + | ^^^^^^^^^^^^^^^^^^ + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:21:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:20:9 + | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:24:9 + | +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | +note: the buffer is reserved here + --> $DIR/uninit_vec.rs:23:9 + | +LL | vec.reserve(1000); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + From b8ba7269cd10843e4aebf855c4f72e980a9c0ed6 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Fri, 17 Sep 2021 03:27:31 -0400 Subject: [PATCH 013/100] Fix clippy lints --- clippy_lints/src/uninit_vec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index ff302289a1f..8b1254b60f9 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -91,7 +91,7 @@ fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { } } -/// Returns the target vec of Vec::with_capacity() or Vec::reserve() +/// Returns the target vec of `Vec::with_capacity()` or `Vec::reserve()` fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stmt<'_>) -> Option> { match stmt.kind { StmtKind::Local(local) => { @@ -128,7 +128,7 @@ fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stm _ => None, } }, - _ => None, + StmtKind::Item(_) => None, } } @@ -145,7 +145,7 @@ fn is_with_capacity(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> bool { } } -/// Returns self if the expression is Vec::set_len() +/// Returns self if the expression is `Vec::set_len()` fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> { // peel unsafe blocks in `unsafe { vec.set_len() }` let expr = peel_hir_expr_while(expr, |e| { From 759200b6991b5dac5fdb12bc6c366b16850add00 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Fri, 17 Sep 2021 14:42:32 -0400 Subject: [PATCH 014/100] Handle PR feedbacks first round --- .../src/methods/uninit_assumed_init.rs | 4 +- clippy_lints/src/uninit_vec.rs | 41 +++++++++++-------- clippy_utils/src/lib.rs | 10 ----- clippy_utils/src/paths.rs | 1 - clippy_utils/src/ty.rs | 10 +++++ tests/ui/uninit_vec.rs | 8 +++- 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index dbd91fb6d9d..ce89189bce9 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_path_def_path, is_uninit_ty_valid, paths}; +use clippy_utils::{is_expr_path_def_path, paths, ty::is_uninit_value_valid_for_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT); - if !is_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); + if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( cx, diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 8b1254b60f9..37084f57043 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,11 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_note; -use clippy_utils::{is_uninit_ty_valid, match_def_path, path_to_local_id, paths, peel_hir_expr_while, SpanlessEq}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{ + match_def_path, path_to_local_id, paths, peel_hir_expr_while, ty::is_uninit_value_valid_for_ty, SpanlessEq, +}; use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -44,32 +47,36 @@ impl<'tcx> LateLintPass<'tcx> for UninitVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { for w in block.stmts.windows(2) { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { - handle_pair(cx, &w[0], expr); + handle_uninit_vec_pair(cx, &w[0], expr); } } if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) { - handle_pair(cx, stmt, expr); + handle_uninit_vec_pair(cx, stmt, expr); } } } -fn handle_pair(cx: &LateContext<'tcx>, first: &'tcx Stmt<'tcx>, second: &'tcx Expr<'tcx>) { +fn handle_uninit_vec_pair( + cx: &LateContext<'tcx>, + maybe_with_capacity_or_reserve: &'tcx Stmt<'tcx>, + maybe_set_len: &'tcx Expr<'tcx>, +) { if_chain! { - if let Some(vec) = extract_with_capacity_or_reserve_target(cx, first); - if let Some((set_len_self, call_span)) = extract_set_len_self(cx, second); + if let Some(vec) = extract_with_capacity_or_reserve_target(cx, maybe_with_capacity_or_reserve); + if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len); if vec.eq_expr(cx, set_len_self); if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); if let ty::Adt(_, substs) = vec_ty.kind(); // Check T of Vec - if !is_uninit_ty_valid(cx, substs.type_at(0)); + if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); then { span_lint_and_note( cx, UNINIT_VEC, call_span, "calling `set_len()` immediately after reserving a buffer creates uninitialized values", - Some(first.span), + Some(maybe_with_capacity_or_reserve.span), "the buffer is reserved here" ); } @@ -113,16 +120,14 @@ fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stm // self.vec = Vec::with_capacity() Some(LocalOrExpr::Expr(lhs)) }, - ExprKind::MethodCall(_, _, [vec_expr, _], _) => { + ExprKind::MethodCall(path, _, [self_expr, _], _) => { // self.vec.reserve() - if_chain! { - if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, id, &paths::VEC_RESERVE); - then { - Some(LocalOrExpr::Expr(vec_expr)) - } else { - None - } + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::vec_type) + && path.ident.name.as_str() == "reserve" + { + Some(LocalOrExpr::Expr(self_expr)) + } else { + None } }, _ => None, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 00d2098a021..09eee78f0d1 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1470,16 +1470,6 @@ pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { false } -/// Checks if a given type looks safe to be uninitialized. -pub fn is_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - match ty.kind() { - rustc_ty::Array(component, _) => is_uninit_ty_valid(cx, component), - rustc_ty::Tuple(types) => types.types().all(|ty| is_uninit_ty_valid(cx, ty)), - rustc_ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT), - _ => false, - } -} - pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator> { (0..decl.inputs.len()).map(move |i| &body.params[i]) } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index dffe30910dd..63ec10a3178 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -183,7 +183,6 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; -pub const VEC_RESERVE: [&str; 4] = ["alloc", "vec", "Vec", "reserve"]; pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const VEC_SET_LEN: [&str; 4] = ["alloc", "vec", "Vec", "set_len"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 6ebe1a0028a..ca64ac7de3e 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -367,3 +367,13 @@ pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { _ => a == b, } } + +/// Checks if a given type looks safe to be uninitialized. +pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + match ty.kind() { + ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), + ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), + ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did), + _ => false, + } +} diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 5e67288405a..34b9e07ef1d 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -25,8 +25,14 @@ fn main() { } // MaybeUninit-wrapped types should not be detected - let mut vec: Vec> = Vec::with_capacity(1000); unsafe { + let mut vec: Vec> = Vec::with_capacity(1000); + vec.set_len(200); + + let mut vec: Vec<(MaybeUninit, MaybeUninit)> = Vec::with_capacity(1000); + vec.set_len(200); + + let mut vec: Vec<(MaybeUninit, [MaybeUninit; 2])> = Vec::with_capacity(1000); vec.set_len(200); } } From fdc06d9b2b3e858878b6fd8f6bd815d947e9950a Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Mon, 20 Sep 2021 15:32:53 -0400 Subject: [PATCH 015/100] Improve error messages --- clippy_lints/src/uninit_vec.rs | 14 +++--- tests/ui/uninit_vec.rs | 32 ++++++++++++++ tests/ui/uninit_vec.stderr | 79 +++++++++++++++++++++++----------- 3 files changed, 93 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 37084f57043..b9b575a452b 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ match_def_path, path_to_local_id, paths, peel_hir_expr_while, ty::is_uninit_value_valid_for_ty, SpanlessEq, @@ -71,13 +71,14 @@ fn handle_uninit_vec_pair( // Check T of Vec if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); then { - span_lint_and_note( + span_lint_and_then( cx, UNINIT_VEC, - call_span, + vec![call_span, maybe_with_capacity_or_reserve.span], "calling `set_len()` immediately after reserving a buffer creates uninitialized values", - Some(maybe_with_capacity_or_reserve.span), - "the buffer is reserved here" + |diag| { + diag.help("initialize the buffer or wrap the content in `MaybeUninit`"); + }, ); } } @@ -155,9 +156,10 @@ fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(& // peel unsafe blocks in `unsafe { vec.set_len() }` let expr = peel_hir_expr_while(expr, |e| { if let ExprKind::Block(block, _) = e.kind { + // Extract the first statement/expression match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) { (None, Some(expr)) => Some(expr), - (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), None) => Some(expr), + (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr), _ => None, } } else { diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index 34b9e07ef1d..e60b73a1e30 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -2,6 +2,11 @@ use std::mem::MaybeUninit; +#[derive(Default)] +struct MyVec { + vec: Vec, +} + fn main() { // with_capacity() -> set_len() should be detected let mut vec: Vec = Vec::with_capacity(1000); @@ -24,6 +29,25 @@ fn main() { vec.set_len(200); } + let mut vec: Vec = Vec::with_capacity(1000); + unsafe { + // test the case where there are other statements in the following unsafe block + vec.set_len(200); + assert!(vec.len() == 200); + } + + // handle vec stored in the field of a struct + let mut my_vec = MyVec::default(); + my_vec.vec.reserve(1000); + unsafe { + my_vec.vec.set_len(200); + } + + my_vec.vec = Vec::with_capacity(1000); + unsafe { + my_vec.vec.set_len(200); + } + // MaybeUninit-wrapped types should not be detected unsafe { let mut vec: Vec> = Vec::with_capacity(1000); @@ -35,4 +59,12 @@ fn main() { let mut vec: Vec<(MaybeUninit, [MaybeUninit; 2])> = Vec::with_capacity(1000); vec.set_len(200); } + + // known false negative + let mut vec1: Vec = Vec::with_capacity(1000); + let mut vec2: Vec = Vec::with_capacity(1000); + unsafe { + vec1.reserve(200); + vec2.reserve(200); + } } diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 1d7807fcf7d..31f8ae40350 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -1,51 +1,78 @@ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:9:9 + --> $DIR/uninit_vec.rs:12:5 | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::uninit-vec` implied by `-D warnings` -note: the buffer is reserved here - --> $DIR/uninit_vec.rs:7:5 - | -LL | let mut vec: Vec = Vec::with_capacity(1000); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:15:9 - | -LL | vec.set_len(200); - | ^^^^^^^^^^^^^^^^ - | -note: the buffer is reserved here - --> $DIR/uninit_vec.rs:13:5 + --> $DIR/uninit_vec.rs:18:5 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ - -error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:21:9 - | +LL | unsafe { LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ | -note: the buffer is reserved here - --> $DIR/uninit_vec.rs:20:9 + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:32:5 + | +LL | let mut vec: Vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:41:5 + | +LL | my_vec.vec.reserve(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | my_vec.vec.set_len(200); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:46:5 + | +LL | my_vec.vec = Vec::with_capacity(1000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | my_vec.vec.set_len(200); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:25:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:24:9 - | LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ | -note: the buffer is reserved here - --> $DIR/uninit_vec.rs:23:9 + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:28:9 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors From fec20bf61799764fab2b0d00d4666f4a9a9632c2 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Tue, 21 Sep 2021 09:56:56 -0400 Subject: [PATCH 016/100] Add #allow attribute to suppress FP #7698 --- clippy_lints/src/uninit_vec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index b9b575a452b..4d556d62c9b 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -71,6 +71,8 @@ fn handle_uninit_vec_pair( // Check T of Vec if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); then { + // FIXME: false positive #7698 + #[allow(clippy::collapsible_span_lint_calls)] span_lint_and_then( cx, UNINIT_VEC, From dd9c8d32f2d7984545816ee07e1e7213b36013f0 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Sun, 3 Oct 2021 00:23:57 -0400 Subject: [PATCH 017/100] Extract get_vec_init_kind and share it --- clippy_lints/src/uninit_vec.rs | 116 +++++++++++-------------- clippy_lints/src/vec_init_then_push.rs | 51 ++--------- clippy_utils/src/lib.rs | 49 ++++++++++- clippy_utils/src/paths.rs | 1 - 4 files changed, 105 insertions(+), 112 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 4d556d62c9b..833c95f4940 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,24 +1,24 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::get_vec_init_kind; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{ - match_def_path, path_to_local_id, paths, peel_hir_expr_while, ty::is_uninit_value_valid_for_ty, SpanlessEq, -}; -use rustc_hir::def::Res; -use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; +use clippy_utils::{path_to_local_id, peel_hir_expr_while, ty::is_uninit_value_valid_for_ty, SpanlessEq}; +use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; +// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std declare_clippy_lint! { /// ### What it does - /// Checks for the creation of uninitialized `Vec` by calling `set_len()` - /// immediately after `with_capacity()` or `reserve()`. + /// Checks for `set_len()` call that creates `Vec` with uninitialized elements. + /// This is commonly caused by calling `set_len()` right after after calling + /// `with_capacity()` or `reserve()`. /// /// ### Why is this bad? - /// It creates `Vec` that contains uninitialized data, which leads to an + /// It creates a `Vec` with uninitialized data, which leads to an /// undefined behavior with most safe operations. - /// Notably, using uninitialized `Vec` with generic `Read` is unsound. + /// Notably, uninitialized `Vec` must not be used with generic `Read`. /// /// ### Example /// ```rust,ignore @@ -26,16 +26,25 @@ /// unsafe { vec.set_len(1000); } /// reader.read(&mut vec); // undefined behavior! /// ``` - /// Use an initialized buffer: - /// ```rust,ignore - /// let mut vec: Vec = vec![0; 1000]; - /// reader.read(&mut vec); - /// ``` - /// Or, wrap the content in `MaybeUninit`: - /// ```rust,ignore - /// let mut vec: Vec> = Vec::with_capacity(1000); - /// unsafe { vec.set_len(1000); } - /// ``` + /// + /// ### How to fix? + /// 1. Use an initialized buffer: + /// ```rust,ignore + /// let mut vec: Vec = vec![0; 1000]; + /// reader.read(&mut vec); + /// ``` + /// 2. Wrap the content in `MaybeUninit`: + /// ```rust,ignore + /// let mut vec: Vec> = Vec::with_capacity(1000); + /// vec.set_len(1000); // `MaybeUninit` can be uninitialized + /// ``` + /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available: + /// ```rust,ignore + /// let mut vec: Vec = Vec::with_capacity(1000); + /// let remaining = vec.spare_capacity_mut(); // `&mut [MaybeUninit]` + /// // perform initialization with `remaining` + /// vec.set_len(...); // Safe to call `set_len()` on initialized part + /// ``` pub UNINIT_VEC, correctness, "Vec with uninitialized data" @@ -59,11 +68,11 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { fn handle_uninit_vec_pair( cx: &LateContext<'tcx>, - maybe_with_capacity_or_reserve: &'tcx Stmt<'tcx>, + maybe_init_or_reserve: &'tcx Stmt<'tcx>, maybe_set_len: &'tcx Expr<'tcx>, ) { if_chain! { - if let Some(vec) = extract_with_capacity_or_reserve_target(cx, maybe_with_capacity_or_reserve); + if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve); if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len); if vec.eq_expr(cx, set_len_self); if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); @@ -71,12 +80,12 @@ fn handle_uninit_vec_pair( // Check T of Vec if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); then { - // FIXME: false positive #7698 + // FIXME: #7698, false positive of the internal lints #[allow(clippy::collapsible_span_lint_calls)] span_lint_and_then( cx, UNINIT_VEC, - vec![call_span, maybe_with_capacity_or_reserve.span], + vec![call_span, maybe_init_or_reserve.span], "calling `set_len()` immediately after reserving a buffer creates uninitialized values", |diag| { diag.help("initialize the buffer or wrap the content in `MaybeUninit`"); @@ -101,15 +110,15 @@ fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { } } -/// Returns the target vec of `Vec::with_capacity()` or `Vec::reserve()` -fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stmt<'_>) -> Option> { +/// Finds the target location where the result of `Vec` initialization is stored +/// or `self` expression for `Vec::reserve()`. +fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option> { match stmt.kind { StmtKind::Local(local) => { - // let mut x = Vec::with_capacity() if_chain! { if let Some(init_expr) = local.init; if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind; - if is_with_capacity(cx, init_expr); + if get_vec_init_kind(cx, init_expr).is_some(); then { Some(LocalOrExpr::Local(hir_id)) } else { @@ -117,40 +126,20 @@ fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stm } } }, - StmtKind::Expr(expr) | StmtKind::Semi(expr) => { - match expr.kind { - ExprKind::Assign(lhs, rhs, _span) if is_with_capacity(cx, rhs) => { - // self.vec = Vec::with_capacity() - Some(LocalOrExpr::Expr(lhs)) - }, - ExprKind::MethodCall(path, _, [self_expr, _], _) => { - // self.vec.reserve() - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::vec_type) - && path.ident.name.as_str() == "reserve" - { - Some(LocalOrExpr::Expr(self_expr)) - } else { - None - } - }, - _ => None, - } + StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind { + ExprKind::Assign(lhs, rhs, _span) if get_vec_init_kind(cx, rhs).is_some() => Some(LocalOrExpr::Expr(lhs)), + ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => { + Some(LocalOrExpr::Expr(self_expr)) + }, + _ => None, }, StmtKind::Item(_) => None, } } -fn is_with_capacity(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> bool { - if_chain! { - if let ExprKind::Call(path_expr, _) = &expr.kind; - if let ExprKind::Path(qpath) = &path_expr.kind; - if let Res::Def(_, def_id) = cx.qpath_res(qpath, path_expr.hir_id); - then { - match_def_path(cx, def_id, &paths::VEC_WITH_CAPACITY) - } else { - false - } - } +fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool { + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec) + && path.ident.name.as_str() == "reserve" } /// Returns self if the expression is `Vec::set_len()` @@ -169,14 +158,13 @@ fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(& } }); match expr.kind { - ExprKind::MethodCall(_, _, [vec_expr, _], _) => { - cx.typeck_results().type_dependent_def_id(expr.hir_id).and_then(|id| { - if match_def_path(cx, id, &paths::VEC_SET_LEN) { - Some((vec_expr, expr.span)) - } else { - None - } - }) + ExprKind::MethodCall(path, _, [self_expr, _], _) => { + let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); + if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" { + Some((self_expr, expr.span)) + } else { + None + } }, _ => None, } diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index d8e241d72af..478314c0836 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,16 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, path_to_local, path_to_local_id, paths}; +use clippy_utils::{get_vec_init_kind, path_to_local, path_to_local_id, VecInitKind}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::sym, Span}; -use std::convert::TryInto; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -41,11 +38,6 @@ pub struct VecInitThenPush { searcher: Option, } -#[derive(Clone, Copy)] -enum VecInitKind { - New, - WithCapacity(u64), -} struct VecPushSearcher { local_id: HirId, init: VecInitKind, @@ -58,7 +50,8 @@ impl VecPushSearcher { fn display_err(&self, cx: &LateContext<'_>) { match self.init { _ if self.found == 0 => return, - VecInitKind::WithCapacity(x) if x > self.found => return, + VecInitKind::WithLiteralCapacity(x) if x > self.found => return, + VecInitKind::WithExprCapacity(_) => return, _ => (), }; @@ -152,37 +145,3 @@ fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Block<'tcx>) { } } } - -fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { - if let ExprKind::Call(func, args) = expr.kind { - match func.kind { - ExprKind::Path(QPath::TypeRelative(ty, name)) - if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) => - { - if name.ident.name == sym::new { - return Some(VecInitKind::New); - } else if name.ident.name.as_str() == "with_capacity" { - return args.get(0).and_then(|arg| { - if_chain! { - if let ExprKind::Lit(lit) = &arg.kind; - if let LitKind::Int(num, _) = lit.node; - then { - Some(VecInitKind::WithCapacity(num.try_into().ok()?)) - } else { - None - } - } - }); - } - } - ExprKind::Path(QPath::Resolved(_, path)) - if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) - && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => - { - return Some(VecInitKind::New); - } - _ => (), - } - } - None -} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 09eee78f0d1..b450059e18a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -93,7 +93,7 @@ use rustc_target::abi::Integer; use crate::consts::{constant, Constant}; -use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type}; +use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type, is_type_diagnostic_item}; pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { if let Ok(version) = RustcVersion::parse(msrv) { @@ -1789,6 +1789,53 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { } } +#[derive(Clone, Copy)] +pub enum VecInitKind { + /// `Vec::new()` + New, + /// `Vec::default()` or `Default::default()` + Default, + /// `Vec::with_capacity(123)` + WithLiteralCapacity(u64), + /// `Vec::with_capacity(slice.len())` + WithExprCapacity(HirId), +} + +/// Checks if given expression is an initialization of `Vec` and returns its kind. +pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { + if let ExprKind::Call(func, args) = expr.kind { + match func.kind { + ExprKind::Path(QPath::TypeRelative(ty, name)) + if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) => + { + if name.ident.name == sym::new { + return Some(VecInitKind::New); + } else if name.ident.name.as_str() == "with_capacity" { + return args.get(0).and_then(|arg| { + if_chain! { + if let ExprKind::Lit(lit) = &arg.kind; + if let LitKind::Int(num, _) = lit.node; + then { + Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?)) + } else { + Some(VecInitKind::WithExprCapacity(arg.hir_id)) + } + } + }); + } + } + ExprKind::Path(QPath::Resolved(_, path)) + if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => + { + return Some(VecInitKind::Default); + } + _ => (), + } + } + None +} + /// Gets the node where an expression is either used, or it's type is unified with another branch. pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option> { let mut child_id = expr.hir_id; diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 63ec10a3178..a39c0fc0b10 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -183,7 +183,6 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; -pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const VEC_SET_LEN: [&str; 4] = ["alloc", "vec", "Vec", "set_len"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; From b1aa3064b6d86c5ae90a67e420d88d826bafe8be Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Tue, 5 Oct 2021 11:43:44 -0400 Subject: [PATCH 018/100] Address PR comments --- clippy_lints/src/uninit_vec.rs | 31 ++++++++++----- clippy_lints/src/vec_init_then_push.rs | 3 +- clippy_utils/src/higher.rs | 53 +++++++++++++++++++++++++- clippy_utils/src/lib.rs | 49 +----------------------- clippy_utils/src/paths.rs | 1 - tests/ui/uninit_vec.rs | 11 +++++- 6 files changed, 85 insertions(+), 63 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 833c95f4940..5d6409874d8 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_vec_init_kind; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{path_to_local_id, peel_hir_expr_while, ty::is_uninit_value_valid_for_ty, SpanlessEq}; +use clippy_utils::higher::get_vec_init_kind; +use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; +use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; @@ -16,10 +17,14 @@ /// `with_capacity()` or `reserve()`. /// /// ### Why is this bad? - /// It creates a `Vec` with uninitialized data, which leads to an + /// It creates a `Vec` with uninitialized data, which leads to /// undefined behavior with most safe operations. + /// /// Notably, uninitialized `Vec` must not be used with generic `Read`. /// + /// ### Known Problems + /// This lint only checks directly adjacent statements. + /// /// ### Example /// ```rust,ignore /// let mut vec: Vec = Vec::with_capacity(1000); @@ -52,16 +57,20 @@ declare_lint_pass!(UninitVec => [UNINIT_VEC]); +// FIXME: update to a visitor-based implementation. +// Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368 impl<'tcx> LateLintPass<'tcx> for UninitVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { - for w in block.stmts.windows(2) { - if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { - handle_uninit_vec_pair(cx, &w[0], expr); + if !in_external_macro(cx.tcx.sess, block.span) { + for w in block.stmts.windows(2) { + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { + handle_uninit_vec_pair(cx, &w[0], expr); + } } - } - if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) { - handle_uninit_vec_pair(cx, stmt, expr); + if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) { + handle_uninit_vec_pair(cx, stmt, expr); + } } } } @@ -79,6 +88,8 @@ fn handle_uninit_vec_pair( if let ty::Adt(_, substs) = vec_ty.kind(); // Check T of Vec if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); + // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()` + if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id); then { // FIXME: #7698, false positive of the internal lints #[allow(clippy::collapsible_span_lint_calls)] diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 478314c0836..b92b6ca4f43 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::source::snippet; -use clippy_utils::{get_vec_init_kind, path_to_local, path_to_local_id, VecInitKind}; +use clippy_utils::{path_to_local, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, Stmt, StmtKind}; diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index ba4d50bf744..d60ddbd3c56 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -2,11 +2,14 @@ #![deny(clippy::missing_docs_in_private_items)] +use crate::ty::is_type_diagnostic_item; use crate::{is_expn_of, match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{self, LitKind}; use rustc_hir as hir; -use rustc_hir::{Arm, Block, BorrowKind, Expr, ExprKind, LoopSource, MatchSource, Node, Pat, StmtKind, UnOp}; +use rustc_hir::{ + Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp, +}; use rustc_lint::LateContext; use rustc_span::{sym, ExpnKind, Span, Symbol}; @@ -632,3 +635,51 @@ pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { } } } + +/// A parsed `Vec` initialization expression +#[derive(Clone, Copy)] +pub enum VecInitKind { + /// `Vec::new()` + New, + /// `Vec::default()` or `Default::default()` + Default, + /// `Vec::with_capacity(123)` + WithLiteralCapacity(u64), + /// `Vec::with_capacity(slice.len())` + WithExprCapacity(HirId), +} + +/// Checks if given expression is an initialization of `Vec` and returns its kind. +pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { + if let ExprKind::Call(func, args) = expr.kind { + match func.kind { + ExprKind::Path(QPath::TypeRelative(ty, name)) + if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) => + { + if name.ident.name == sym::new { + return Some(VecInitKind::New); + } else if name.ident.name.as_str() == "with_capacity" { + return args.get(0).and_then(|arg| { + if_chain! { + if let ExprKind::Lit(lit) = &arg.kind; + if let LitKind::Int(num, _) = lit.node; + then { + Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?)) + } else { + Some(VecInitKind::WithExprCapacity(arg.hir_id)) + } + } + }); + } + } + ExprKind::Path(QPath::Resolved(_, path)) + if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => + { + return Some(VecInitKind::Default); + } + _ => (), + } + } + None +} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index b450059e18a..09eee78f0d1 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -93,7 +93,7 @@ use rustc_target::abi::Integer; use crate::consts::{constant, Constant}; -use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type, is_type_diagnostic_item}; +use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type}; pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { if let Ok(version) = RustcVersion::parse(msrv) { @@ -1789,53 +1789,6 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { } } -#[derive(Clone, Copy)] -pub enum VecInitKind { - /// `Vec::new()` - New, - /// `Vec::default()` or `Default::default()` - Default, - /// `Vec::with_capacity(123)` - WithLiteralCapacity(u64), - /// `Vec::with_capacity(slice.len())` - WithExprCapacity(HirId), -} - -/// Checks if given expression is an initialization of `Vec` and returns its kind. -pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { - if let ExprKind::Call(func, args) = expr.kind { - match func.kind { - ExprKind::Path(QPath::TypeRelative(ty, name)) - if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) => - { - if name.ident.name == sym::new { - return Some(VecInitKind::New); - } else if name.ident.name.as_str() == "with_capacity" { - return args.get(0).and_then(|arg| { - if_chain! { - if let ExprKind::Lit(lit) = &arg.kind; - if let LitKind::Int(num, _) = lit.node; - then { - Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?)) - } else { - Some(VecInitKind::WithExprCapacity(arg.hir_id)) - } - } - }); - } - } - ExprKind::Path(QPath::Resolved(_, path)) - if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD) - && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) => - { - return Some(VecInitKind::Default); - } - _ => (), - } - } - None -} - /// Gets the node where an expression is either used, or it's type is unified with another branch. pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option> { let mut child_id = expr.hir_id; diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index a39c0fc0b10..e43c5756021 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -183,6 +183,5 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; -pub const VEC_SET_LEN: [&str; 4] = ["alloc", "vec", "Vec", "set_len"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index e60b73a1e30..c8f9067e549 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -48,6 +48,13 @@ fn main() { my_vec.vec.set_len(200); } + // Test `#[allow(...)]` attributes on inner unsafe block (shouldn't trigger) + let mut vec: Vec = Vec::with_capacity(1000); + #[allow(clippy::uninit_vec)] + unsafe { + vec.set_len(200); + } + // MaybeUninit-wrapped types should not be detected unsafe { let mut vec: Vec> = Vec::with_capacity(1000); @@ -64,7 +71,7 @@ fn main() { let mut vec1: Vec = Vec::with_capacity(1000); let mut vec2: Vec = Vec::with_capacity(1000); unsafe { - vec1.reserve(200); - vec2.reserve(200); + vec1.set_len(200); + vec2.set_len(200); } } From de0d2b15008f0333e432aab9a7b7045ab0157897 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Thu, 7 Oct 2021 11:18:01 -0400 Subject: [PATCH 019/100] Add testcases --- clippy_utils/src/higher.rs | 20 ++++++++--------- tests/ui/uninit_vec.rs | 17 ++++++++++++++ tests/ui/uninit_vec.stderr | 45 +++++++++++++++++++++++++++++++++----- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index d60ddbd3c56..30f6831dcf4 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -658,18 +658,18 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - { if name.ident.name == sym::new { return Some(VecInitKind::New); + } else if name.ident.name.as_str() == "default" { + return Some(VecInitKind::Default); } else if name.ident.name.as_str() == "with_capacity" { - return args.get(0).and_then(|arg| { - if_chain! { - if let ExprKind::Lit(lit) = &arg.kind; - if let LitKind::Int(num, _) = lit.node; - then { - Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?)) - } else { - Some(VecInitKind::WithExprCapacity(arg.hir_id)) - } + let arg = args.get(0)?; + if_chain! { + if let ExprKind::Lit(lit) = &arg.kind; + if let LitKind::Int(num, _) = lit.node; + then { + return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?)) } - }); + } + return Some(VecInitKind::WithExprCapacity(arg.hir_id)); } } ExprKind::Path(QPath::Resolved(_, path)) diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs index c8f9067e549..dc150cf28f2 100644 --- a/tests/ui/uninit_vec.rs +++ b/tests/ui/uninit_vec.rs @@ -20,6 +20,23 @@ fn main() { vec.set_len(200); } + // new() -> set_len() should be detected + let mut vec: Vec = Vec::new(); + unsafe { + vec.set_len(200); + } + + // default() -> set_len() should be detected + let mut vec: Vec = Default::default(); + unsafe { + vec.set_len(200); + } + + let mut vec: Vec = Vec::default(); + unsafe { + vec.set_len(200); + } + // test when both calls are enclosed in the same unsafe block unsafe { let mut vec: Vec = Vec::with_capacity(1000); diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 31f8ae40350..81b91cef92a 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -22,7 +22,40 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:32:5 + --> $DIR/uninit_vec.rs:24:5 + | +LL | let mut vec: Vec = Vec::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:30:5 + | +LL | let mut vec: Vec = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:35:5 + | +LL | let mut vec: Vec = Vec::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $DIR/uninit_vec.rs:49:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +66,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:41:5 + --> $DIR/uninit_vec.rs:58:5 | LL | my_vec.vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +77,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:46:5 + --> $DIR/uninit_vec.rs:63:5 | LL | my_vec.vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +88,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:25:9 + --> $DIR/uninit_vec.rs:42:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +98,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> $DIR/uninit_vec.rs:28:9 + --> $DIR/uninit_vec.rs:45:9 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -74,5 +107,5 @@ LL | vec.set_len(200); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: aborting due to 7 previous errors +error: aborting due to 10 previous errors From 2181387c3ab4d7dc4d6e2c46c8158201a1b1045e Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Thu, 7 Oct 2021 11:53:08 -0400 Subject: [PATCH 020/100] Improved error message for set_len() on empty Vec --- clippy_lints/src/uninit_vec.rs | 103 +++++++++++++++++++++++---------- tests/ui/uninit_vec.stderr | 12 +--- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 5d6409874d8..15c79da6fa9 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -1,5 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::higher::get_vec_init_kind; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::higher::{get_vec_init_kind, VecInitKind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; @@ -83,69 +83,108 @@ fn handle_uninit_vec_pair( if_chain! { if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve); if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len); - if vec.eq_expr(cx, set_len_self); + if vec.location.eq_expr(cx, set_len_self); if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind(); if let ty::Adt(_, substs) = vec_ty.kind(); - // Check T of Vec - if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)); // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()` if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id); then { - // FIXME: #7698, false positive of the internal lints - #[allow(clippy::collapsible_span_lint_calls)] - span_lint_and_then( - cx, - UNINIT_VEC, - vec![call_span, maybe_init_or_reserve.span], - "calling `set_len()` immediately after reserving a buffer creates uninitialized values", - |diag| { - diag.help("initialize the buffer or wrap the content in `MaybeUninit`"); - }, - ); + if vec.has_capacity() { + // with_capacity / reserve -> set_len + + // Check T of Vec + if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) { + // FIXME: #7698, false positive of the internal lints + #[allow(clippy::collapsible_span_lint_calls)] + span_lint_and_then( + cx, + UNINIT_VEC, + vec![call_span, maybe_init_or_reserve.span], + "calling `set_len()` immediately after reserving a buffer creates uninitialized values", + |diag| { + diag.help("initialize the buffer or wrap the content in `MaybeUninit`"); + }, + ); + } + } else { + // new / default -> set_len + span_lint( + cx, + UNINIT_VEC, + vec![call_span, maybe_init_or_reserve.span], + "calling `set_len()` on empty `Vec` creates out-of-bound values", + ) + } } } } -#[derive(Clone, Copy, Debug)] -enum LocalOrExpr<'tcx> { +/// The target `Vec` that is initialized or reserved +#[derive(Clone, Copy)] +struct TargetVec<'tcx> { + location: VecLocation<'tcx>, + /// `None` if `reserve()` + init_kind: Option, +} + +impl TargetVec<'_> { + pub fn has_capacity(self) -> bool { + !matches!(self.init_kind, Some(VecInitKind::New | VecInitKind::Default)) + } +} + +#[derive(Clone, Copy)] +enum VecLocation<'tcx> { Local(HirId), Expr(&'tcx Expr<'tcx>), } -impl<'tcx> LocalOrExpr<'tcx> { - fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { +impl<'tcx> VecLocation<'tcx> { + pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { match self { - LocalOrExpr::Local(hir_id) => path_to_local_id(expr, hir_id), - LocalOrExpr::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr), + VecLocation::Local(hir_id) => path_to_local_id(expr, hir_id), + VecLocation::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr), } } } /// Finds the target location where the result of `Vec` initialization is stored /// or `self` expression for `Vec::reserve()`. -fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option> { +fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option> { match stmt.kind { StmtKind::Local(local) => { if_chain! { if let Some(init_expr) = local.init; if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind; - if get_vec_init_kind(cx, init_expr).is_some(); + if let Some(init_kind) = get_vec_init_kind(cx, init_expr); then { - Some(LocalOrExpr::Local(hir_id)) - } else { - None + return Some(TargetVec { + location: VecLocation::Local(hir_id), + init_kind: Some(init_kind), + }) } } }, StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind { - ExprKind::Assign(lhs, rhs, _span) if get_vec_init_kind(cx, rhs).is_some() => Some(LocalOrExpr::Expr(lhs)), - ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => { - Some(LocalOrExpr::Expr(self_expr)) + ExprKind::Assign(lhs, rhs, _span) => { + if let Some(init_kind) = get_vec_init_kind(cx, rhs) { + return Some(TargetVec { + location: VecLocation::Expr(lhs), + init_kind: Some(init_kind), + }); + } }, - _ => None, + ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => { + return Some(TargetVec { + location: VecLocation::Expr(self_expr), + init_kind: None, + }); + }, + _ => (), }, - StmtKind::Item(_) => None, + StmtKind::Item(_) => (), } + None } fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool { diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr index 81b91cef92a..520bfb26b62 100644 --- a/tests/ui/uninit_vec.stderr +++ b/tests/ui/uninit_vec.stderr @@ -21,7 +21,7 @@ LL | vec.set_len(200); | = help: initialize the buffer or wrap the content in `MaybeUninit` -error: calling `set_len()` immediately after reserving a buffer creates uninitialized values +error: calling `set_len()` on empty `Vec` creates out-of-bound values --> $DIR/uninit_vec.rs:24:5 | LL | let mut vec: Vec = Vec::new(); @@ -29,10 +29,8 @@ LL | let mut vec: Vec = Vec::new(); LL | unsafe { LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ - | - = help: initialize the buffer or wrap the content in `MaybeUninit` -error: calling `set_len()` immediately after reserving a buffer creates uninitialized values +error: calling `set_len()` on empty `Vec` creates out-of-bound values --> $DIR/uninit_vec.rs:30:5 | LL | let mut vec: Vec = Default::default(); @@ -40,10 +38,8 @@ LL | let mut vec: Vec = Default::default(); LL | unsafe { LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ - | - = help: initialize the buffer or wrap the content in `MaybeUninit` -error: calling `set_len()` immediately after reserving a buffer creates uninitialized values +error: calling `set_len()` on empty `Vec` creates out-of-bound values --> $DIR/uninit_vec.rs:35:5 | LL | let mut vec: Vec = Vec::default(); @@ -51,8 +47,6 @@ LL | let mut vec: Vec = Vec::default(); LL | unsafe { LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ - | - = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values --> $DIR/uninit_vec.rs:49:5 From 03fed75c89880e5ed919eec1ba93dbe769d463a2 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Sat, 9 Oct 2021 05:59:53 -0400 Subject: [PATCH 021/100] Address internal lints --- clippy_lints/src/uninit_vec.rs | 2 +- clippy_utils/src/higher.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 15c79da6fa9..2573209d1b6 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -113,7 +113,7 @@ fn handle_uninit_vec_pair( UNINIT_VEC, vec![call_span, maybe_init_or_reserve.span], "calling `set_len()` on empty `Vec` creates out-of-bound values", - ) + ); } } } diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 30f6831dcf4..1ff282de950 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -11,7 +11,7 @@ Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp, }; use rustc_lint::LateContext; -use rustc_span::{sym, ExpnKind, Span, Symbol}; +use rustc_span::{sym, symbol, ExpnKind, Span, Symbol}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`. @@ -658,7 +658,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - { if name.ident.name == sym::new { return Some(VecInitKind::New); - } else if name.ident.name.as_str() == "default" { + } else if name.ident.name == symbol::kw::Default { return Some(VecInitKind::Default); } else if name.ident.name.as_str() == "with_capacity" { let arg = args.get(0)?; From 7aaed02b8c4cad724506a44a53b5205132ff4d20 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 9 Oct 2021 14:56:33 +0200 Subject: [PATCH 022/100] Fix false positive when `Drop` and `Copy` involved --- clippy_lints/src/default.rs | 8 +++ tests/ui/field_reassign_with_default.rs | 64 +++++++++++++++++++++ tests/ui/field_reassign_with_default.stderr | 26 ++++++++- 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index db8f2171348..cde27d3ad2a 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; +use clippy_utils::ty::{has_drop, is_copy}; use clippy_utils::{any_parent_is_automatically_derived, contains_name, in_macro, match_def_path, paths}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; @@ -139,6 +140,13 @@ fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { .fields .iter() .all(|field| field.vis.is_accessible_from(module_did, cx.tcx)); + let all_fields_are_copy = variant + .fields + .iter() + .all(|field| { + is_copy(cx, cx.tcx.type_of(field.did)) + }); + if !has_drop(cx, binding_type) || all_fields_are_copy; then { (local, variant, ident.name, binding_type, expr.span) } else { diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 787053fb000..7367910eaa1 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -183,3 +183,67 @@ struct WrapperMulti { i: T, j: U, } + +mod issue6312 { + use std::sync::atomic::AtomicBool; + use std::sync::Arc; + + // do not lint: type implements `Drop` but not all fields are `Copy` + #[derive(Clone, Default)] + pub struct ImplDropNotAllCopy { + name: String, + delay_data_sync: Arc, + } + + impl Drop for ImplDropNotAllCopy { + fn drop(&mut self) { + self.close() + } + } + + impl ImplDropNotAllCopy { + fn new(name: &str) -> Self { + let mut f = ImplDropNotAllCopy::default(); + f.name = name.to_owned(); + f + } + fn close(&self) {} + } + + // lint: type implements `Drop` and all fields are `Copy` + #[derive(Clone, Default)] + pub struct ImplDropAllCopy { + name: usize, + delay_data_sync: bool, + } + + impl Drop for ImplDropAllCopy { + fn drop(&mut self) { + self.close() + } + } + + impl ImplDropAllCopy { + fn new(name: &str) -> Self { + let mut f = ImplDropAllCopy::default(); + f.name = name.len(); + f + } + fn close(&self) {} + } + + // lint: type does not implement `Drop` though all fields are `Copy` + #[derive(Clone, Default)] + pub struct NoDropAllCopy { + name: usize, + delay_data_sync: bool, + } + + impl NoDropAllCopy { + fn new(name: &str) -> Self { + let mut f = NoDropAllCopy::default(); + f.name = name.len(); + f + } + } +} diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr index b56db08ec8a..3ce4b91a548 100644 --- a/tests/ui/field_reassign_with_default.stderr +++ b/tests/ui/field_reassign_with_default.stderr @@ -107,5 +107,29 @@ note: consider initializing the variable with `WrapperMulti:: { i: 42, LL | let mut a: WrapperMulti = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:229:13 + | +LL | f.name = name.len(); + | ^^^^^^^^^^^^^^^^^^^^ + | +note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:228:13 + | +LL | let mut f = ImplDropAllCopy::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:245:13 + | +LL | f.name = name.len(); + | ^^^^^^^^^^^^^^^^^^^^ + | +note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:244:13 + | +LL | let mut f = NoDropAllCopy::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors From 1e18b8a269f58b15da39a1ffa9f4c29b2a55bae8 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 9 Oct 2021 15:54:16 +0200 Subject: [PATCH 023/100] Fix FP in external macros for `mut_mut` lint --- clippy_lints/src/mut_mut.rs | 4 ++++ tests/ui/auxiliary/macro_rules.rs | 7 +++++++ tests/ui/mut_mut.rs | 10 ++++++++++ tests/ui/mut_mut.stderr | 18 +++++++++--------- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 610152a217f..7c4cac29ba8 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -82,6 +82,10 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { } fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { + if in_external_macro(self.cx.sess(), ty.span) { + return; + } + if let hir::TyKind::Rptr( _, hir::MutTy { diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 170955e726c..0251fada9e8 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -113,3 +113,10 @@ macro_rules! default_numeric_fallback { let x = 22; }; } + +#[macro_export] +macro_rules! mut_mut { + () => { + let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32; + }; +} diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 8965cef66de..be854d94183 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,6 +1,11 @@ +// aux-build:macro_rules.rs + #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] #![warn(clippy::mut_mut)] +#[macro_use] +extern crate macro_rules; + fn fun(x: &mut &mut u32) -> bool { **x > 0 } @@ -47,3 +52,8 @@ fn issue939() { println!(":{}", arg); } } + +fn issue6922() { + // do not lint from an external macro + mut_mut!(); +} diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 0fed6953cb8..6820a85aa54 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -1,5 +1,5 @@ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:4:11 + --> $DIR/mut_mut.rs:9:11 | LL | fn fun(x: &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn fun(x: &mut &mut u32) -> bool { = note: `-D clippy::mut-mut` implied by `-D warnings` error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:20:17 + --> $DIR/mut_mut.rs:25:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:14:9 + --> $DIR/mut_mut.rs:19:9 | LL | &mut $p | ^^^^^^^ @@ -24,37 +24,37 @@ LL | let mut z = mut_ptr!(&mut 3u32); = note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> $DIR/mut_mut.rs:22:21 + --> $DIR/mut_mut.rs:27:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:26:32 + --> $DIR/mut_mut.rs:31:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:26:16 + --> $DIR/mut_mut.rs:31:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:37 + --> $DIR/mut_mut.rs:36:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:16 + --> $DIR/mut_mut.rs:36:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:31:21 + --> $DIR/mut_mut.rs:36:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ From fc324255215066afd4f4dfff6f39e76e2c80fc4b Mon Sep 17 00:00:00 2001 From: 1nF0rmed Date: Sat, 9 Oct 2021 22:30:12 +0530 Subject: [PATCH 024/100] Refactor to check for multiple reference patterns --- clippy_lints/src/matches.rs | 10 ++-- tests/ui/match_expr_like_matches_macro.stderr | 35 +---------- tests/ui/match_ref_pats.stderr | 58 +------------------ 3 files changed, 7 insertions(+), 96 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 56d4163a6b3..b643fba5d32 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1187,7 +1187,7 @@ fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, 'b: 'a, I: Clone + Iterator>, { - if !has_only_ref_pats(pats.clone()) { + if !has_multiple_ref_pats(pats.clone()) { return; } @@ -1693,12 +1693,12 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option(pats: I) -> bool +fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool where 'b: 'a, I: Iterator>, { - let mut at_least_one_is_true = false; + let mut ref_count = 0; for opt in pats.map(|pat| match pat.kind { PatKind::Ref(..) => Some(true), // &-patterns PatKind::Wild => Some(false), // an "anything" wildcard is also fine @@ -1706,13 +1706,13 @@ fn has_only_ref_pats<'a, 'b, I>(pats: I) -> bool }) { if let Some(inner) = opt { if inner { - at_least_one_is_true = true; + ref_count += 1; } } else { return false; } } - at_least_one_is_true + ref_count > 1 } pub fn overlapping(ranges: &[SpannedRange]) -> Option<(&SpannedRange, &SpannedRange)> diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr index 366ef36c367..d7cedf9f9f1 100644 --- a/tests/ui/match_expr_like_matches_macro.stderr +++ b/tests/ui/match_expr_like_matches_macro.stderr @@ -110,23 +110,6 @@ LL | | _ => false, LL | | }; | |_________^ help: try this: `matches!(&val, &Some(ref _a))` -error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_expr_like_matches_macro.rs:166:20 - | -LL | let _res = match &val { - | ____________________^ -LL | | &Some(ref _a) => true, -LL | | _ => false, -LL | | }; - | |_________^ - | - = note: `-D clippy::match-ref-pats` implied by `-D warnings` -help: try - | -LL ~ let _res = match val { -LL ~ Some(ref _a) => true, - | - error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:178:20 | @@ -137,21 +120,5 @@ LL | | _ => false, LL | | }; | |_________^ help: try this: `matches!(&val, &Some(ref _a))` -error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_expr_like_matches_macro.rs:178:20 - | -LL | let _res = match &val { - | ____________________^ -LL | | &Some(ref _a) => true, -LL | | _ => false, -LL | | }; - | |_________^ - | -help: try - | -LL ~ let _res = match val { -LL ~ Some(ref _a) => true, - | - -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index 072aff445e9..e4e13c32d74 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -15,21 +15,6 @@ LL ~ Some(v) => println!("{:?}", v), LL ~ None => println!("none"), | -error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:18:5 - | -LL | / match tup { -LL | | &(v, 1) => println!("{}", v), -LL | | _ => println!("none"), -LL | | } - | |_____^ - | -help: instead of prefixing all patterns with `&`, you can dereference the expression - | -LL ~ match *tup { -LL ~ (v, 1) => println!("{}", v), - | - error: you don't need to add `&` to both the expression and the patterns --> $DIR/match_ref_pats.rs:24:5 | @@ -54,52 +39,11 @@ LL | if let &None = a { | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` -error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:36:5 - | -LL | / if let &None = a { -LL | | println!("none"); -LL | | } - | |_____^ - | -help: instead of prefixing all patterns with `&`, you can dereference the expression - | -LL | if let None = *a { - | ~~~~ ~~ - error: redundant pattern matching, consider using `is_none()` --> $DIR/match_ref_pats.rs:41:12 | LL | if let &None = &b { | -------^^^^^----- help: try this: `if b.is_none()` -error: you don't need to add `&` to both the expression and the patterns - --> $DIR/match_ref_pats.rs:41:5 - | -LL | / if let &None = &b { -LL | | println!("none"); -LL | | } - | |_____^ - | -help: try - | -LL | if let None = b { - | ~~~~ ~ - -error: you don't need to add `&` to all patterns - --> $DIR/match_ref_pats.rs:68:9 - | -LL | / match foo_variant!(0) { -LL | | &Foo::A => println!("A"), -LL | | _ => println!("Wild"), -LL | | } - | |_________^ - | -help: instead of prefixing all patterns with `&`, you can dereference the expression - | -LL ~ match *foo_variant!(0) { -LL ~ Foo::A => println!("A"), - | - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors From 1080f6c70c132ef20bf0310c1845c92f55a3d5b5 Mon Sep 17 00:00:00 2001 From: 1nF0rmed Date: Sun, 10 Oct 2021 14:46:28 +0530 Subject: [PATCH 025/100] Adds additional tests for lint --- tests/ui/match_ref_pats.rs | 42 ++++++++++++++++++++++++++++++++++ tests/ui/match_ref_pats.stderr | 21 ++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 6cbb4d32b0d..50246486bb6 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -72,4 +72,46 @@ fn ice_3719() { } } +mod issue_7740 { + macro_rules! foobar_variant( + ($idx:expr) => (FooBar::get($idx).unwrap()) + ); + + enum FooBar { + Foo, + Bar, + FooBar, + BarFoo, + } + + impl FooBar { + fn get(idx: u8) -> Option<&'static Self> { + match idx { + 0 => Some(&FooBar::Foo), + 1 => Some(&FooBar::Bar), + 2 => Some(&FooBar::FooBar), + 3 => Some(&FooBar::BarFoo), + _ => None, + } + } + } + + fn issue_7740() { + // Issue #7740 + match foobar_variant!(0) { + &FooBar::Foo => println!("Foo"), + &FooBar::Bar => println!("Bar"), + &FooBar::FooBar => println!("FooBar"), + _ => println!("Wild"), + } + + // This shouldn't trigger + if let &FooBar::BarFoo = foobar_variant!(3) { + println!("BarFoo"); + } else { + println!("Wild"); + } + } +} + fn main() {} diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index e4e13c32d74..901820077e2 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -45,5 +45,24 @@ error: redundant pattern matching, consider using `is_none()` LL | if let &None = &b { | -------^^^^^----- help: try this: `if b.is_none()` -error: aborting due to 4 previous errors +error: you don't need to add `&` to all patterns + --> $DIR/match_ref_pats.rs:101:9 + | +LL | / match foobar_variant!(0) { +LL | | &FooBar::Foo => println!("Foo"), +LL | | &FooBar::Bar => println!("Bar"), +LL | | &FooBar::FooBar => println!("FooBar"), +LL | | _ => println!("Wild"), +LL | | } + | |_________^ + | +help: instead of prefixing all patterns with `&`, you can dereference the expression + | +LL ~ match *foobar_variant!(0) { +LL ~ FooBar::Foo => println!("Foo"), +LL ~ FooBar::Bar => println!("Bar"), +LL ~ FooBar::FooBar => println!("FooBar"), + | + +error: aborting due to 5 previous errors From 857a4073b8b76bd29ff9504b5f015e5021b5d9b2 Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 11 Oct 2021 08:25:30 +0100 Subject: [PATCH 026/100] Add reason config example for disallowed_type Co-authored-by: James Hinshelwood --- clippy_lints/src/disallowed_type.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/disallowed_type.rs b/clippy_lints/src/disallowed_type.rs index 261e9af11c8..8113c388018 100644 --- a/clippy_lints/src/disallowed_type.rs +++ b/clippy_lints/src/disallowed_type.rs @@ -21,7 +21,15 @@ /// An example clippy.toml configuration: /// ```toml /// # clippy.toml - /// disallowed-types = ["std::collections::BTreeMap"] + /// disallowed-types = [ + /// # Can use a string as the path of the disallowed type. + /// "std::collections::BTreeMap", + /// # Can also use an inline table with a `path` key. + /// { path = "std::net::TcpListener" }, + /// # When using an inline table, can add a `reason` for why the type + /// # is disallowed. + /// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" }, + /// ] /// ``` /// /// ```rust,ignore From 886cbb18821bdd9a5548dedbe6caa0ccb2dafb3f Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 11 Oct 2021 08:28:32 +0100 Subject: [PATCH 027/100] Rename `disallowed` to `conf_disallowed` Co-authored-by: James Hinshelwood --- clippy_lints/src/disallowed_type.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/disallowed_type.rs b/clippy_lints/src/disallowed_type.rs index 8113c388018..48f781516f4 100644 --- a/clippy_lints/src/disallowed_type.rs +++ b/clippy_lints/src/disallowed_type.rs @@ -48,15 +48,15 @@ } #[derive(Clone, Debug)] pub struct DisallowedType { - disallowed: Vec, + conf_disallowed: Vec, def_ids: FxHashMap>, prim_tys: FxHashMap>, } impl DisallowedType { - pub fn new(disallowed: Vec) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { - disallowed, + conf_disallowed, def_ids: FxHashMap::default(), prim_tys: FxHashMap::default(), } @@ -83,7 +83,7 @@ fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { impl<'tcx> LateLintPass<'tcx> for DisallowedType { fn check_crate(&mut self, cx: &LateContext<'_>) { - for conf in &self.disallowed { + for conf in &self.conf_disallowed { let (path, reason) = match conf { conf::DisallowedType::Simple(path) => (path, None), conf::DisallowedType::WithReason { path, reason } => ( From f44a904a56b92415c189be16e8d628e6c1473935 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 11 Oct 2021 10:10:16 +0200 Subject: [PATCH 028/100] Deprecate mem_discriminant_non_enum This lint has been uplifted and is now included in enum_intrinsics_non_enums. --- CHANGELOG.md | 5 +- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_correctness.rs | 1 - clippy_lints/src/lib.register_lints.rs | 1 - clippy_lints/src/lib.rs | 3 +- clippy_lints/src/mem_discriminant.rs | 82 ----------------- tests/ui/mem_discriminant.fixed | 45 ---------- tests/ui/mem_discriminant.rs | 45 ---------- tests/ui/mem_discriminant.stderr | 94 -------------------- tests/ui/mem_discriminant_unfixable.rs | 16 ---- tests/ui/mem_discriminant_unfixable.stderr | 20 ----- tests/ui/rename.fixed | 1 + tests/ui/rename.rs | 1 + tests/ui/rename.stderr | 14 ++- 14 files changed, 15 insertions(+), 314 deletions(-) delete mode 100644 clippy_lints/src/mem_discriminant.rs delete mode 100644 tests/ui/mem_discriminant.fixed delete mode 100644 tests/ui/mem_discriminant.rs delete mode 100644 tests/ui/mem_discriminant.stderr delete mode 100644 tests/ui/mem_discriminant_unfixable.rs delete mode 100644 tests/ui/mem_discriminant_unfixable.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fdb300c977..e700e5f0d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1873,10 +1873,10 @@ Released 2019-01-17 [2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be) -* New lints: [`slow_vector_initialization`], [`mem_discriminant_non_enum`], +* New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`, [`redundant_clone`], [`wildcard_dependencies`], [`into_iter_on_ref`], `into_iter_on_array`, [`deprecated_cfg_attr`], - [`mem_discriminant_non_enum`], [`cargo_common_metadata`] + [`cargo_common_metadata`] * Add support for `u128` and `i128` to integer related lints * Add float support to `mistyped_literal_suffixes` * Fix false positives in `use_self` @@ -2839,7 +2839,6 @@ Released 2018-09-13 [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter -[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 3e6e0244754..6a3ee35b41a 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -127,7 +127,6 @@ LintId::of(matches::REDUNDANT_PATTERN_MATCHING), LintId::of(matches::SINGLE_MATCH), LintId::of(matches::WILDCARD_IN_OR_PATTERNS), - LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index e0ef7b3b8af..bbe47a0e772 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -36,7 +36,6 @@ LintId::of(loops::ITER_NEXT_LOOP), LintId::of(loops::NEVER_LOOP), LintId::of(loops::WHILE_IMMUTABLE_CONDITION), - LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 2ba2b3da55c..b0be3b65366 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -241,7 +241,6 @@ matches::SINGLE_MATCH_ELSE, matches::WILDCARD_ENUM_MATCH_ARM, matches::WILDCARD_IN_OR_PATTERNS, - mem_discriminant::MEM_DISCRIMINANT_NON_ENUM, mem_forget::MEM_FORGET, mem_replace::MEM_REPLACE_OPTION_WITH_NONE, mem_replace::MEM_REPLACE_WITH_DEFAULT, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9fc6a9e0ccc..5534f9c94f3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -266,7 +266,6 @@ macro_rules! declare_clippy_lint { mod match_on_vec_items; mod match_result_ok; mod matches; -mod mem_discriminant; mod mem_forget; mod mem_replace; mod methods; @@ -600,7 +599,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); store.register_late_pass(|| Box::new(neg_multiply::NegMultiply)); - store.register_late_pass(|| Box::new(mem_discriminant::MemDiscriminant)); store.register_late_pass(|| Box::new(mem_forget::MemForget)); store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default())); store.register_late_pass(|| Box::new(assign_ops::AssignOps)); @@ -850,6 +848,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) { ls.register_renamed("clippy::panic_params", "non_fmt_panics"); ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints"); ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"); + ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"); } // only exists to let the dogfood integration test works. diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs deleted file mode 100644 index 59176c4b846..00000000000 --- a/clippy_lints/src/mem_discriminant.rs +++ /dev/null @@ -1,82 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; -use clippy_utils::ty::walk_ptrs_ty_depth; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls of `mem::discriminant()` on a non-enum type. - /// - /// ### Why is this bad? - /// The value of `mem::discriminant()` on non-enum types - /// is unspecified. - /// - /// ### Example - /// ```rust - /// use std::mem; - /// - /// mem::discriminant(&"hello"); - /// mem::discriminant(&&Some(2)); - /// ``` - pub MEM_DISCRIMINANT_NON_ENUM, - correctness, - "calling `mem::descriminant` on non-enum type" -} - -declare_lint_pass!(MemDiscriminant => [MEM_DISCRIMINANT_NON_ENUM]); - -impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(func, func_args) = expr.kind; - // is `mem::discriminant` - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::MEM_DISCRIMINANT); - // type is non-enum - let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0); - if !ty_param.is_enum(); - - then { - span_lint_and_then( - cx, - MEM_DISCRIMINANT_NON_ENUM, - expr.span, - &format!("calling `mem::discriminant` on non-enum type `{}`", ty_param), - |diag| { - // if this is a reference to an enum, suggest dereferencing - let (base_ty, ptr_depth) = walk_ptrs_ty_depth(ty_param); - if ptr_depth >= 1 && base_ty.is_enum() { - let param = &func_args[0]; - - // cancel out '&'s first - let mut derefs_needed = ptr_depth; - let mut cur_expr = param; - while derefs_needed > 0 { - if let ExprKind::AddrOf(BorrowKind::Ref, _, inner_expr) = cur_expr.kind { - derefs_needed -= 1; - cur_expr = inner_expr; - } else { - break; - } - } - - let derefs = "*".repeat(derefs_needed); - diag.span_suggestion( - param.span, - "try dereferencing", - format!("{}{}", derefs, snippet(cx, cur_expr.span, "")), - Applicability::MachineApplicable, - ); - } - }, - ) - } - } - } -} diff --git a/tests/ui/mem_discriminant.fixed b/tests/ui/mem_discriminant.fixed deleted file mode 100644 index 69a8f286d05..00000000000 --- a/tests/ui/mem_discriminant.fixed +++ /dev/null @@ -1,45 +0,0 @@ -// run-rustfix - -#![deny(clippy::mem_discriminant_non_enum)] - -use std::mem; - -enum Foo { - One(usize), - Two(u8), -} - -fn main() { - // bad - mem::discriminant(&Some(2)); - mem::discriminant(&None::); - mem::discriminant(&Foo::One(5)); - mem::discriminant(&Foo::Two(5)); - - let ro = &Some(3); - let rro = &ro; - mem::discriminant(ro); - mem::discriminant(*rro); - mem::discriminant(*rro); - - macro_rules! mem_discriminant_but_in_a_macro { - ($param:expr) => { - mem::discriminant($param) - }; - } - - mem_discriminant_but_in_a_macro!(*rro); - - let rrrrro = &&&rro; - mem::discriminant(****rrrrro); - mem::discriminant(****rrrrro); - - // ok - mem::discriminant(&Some(2)); - mem::discriminant(&None::); - mem::discriminant(&Foo::One(5)); - mem::discriminant(&Foo::Two(5)); - mem::discriminant(ro); - mem::discriminant(*rro); - mem::discriminant(****rrrrro); -} diff --git a/tests/ui/mem_discriminant.rs b/tests/ui/mem_discriminant.rs deleted file mode 100644 index 55db50fcdc7..00000000000 --- a/tests/ui/mem_discriminant.rs +++ /dev/null @@ -1,45 +0,0 @@ -// run-rustfix - -#![deny(clippy::mem_discriminant_non_enum)] - -use std::mem; - -enum Foo { - One(usize), - Two(u8), -} - -fn main() { - // bad - mem::discriminant(&&Some(2)); - mem::discriminant(&&None::); - mem::discriminant(&&Foo::One(5)); - mem::discriminant(&&Foo::Two(5)); - - let ro = &Some(3); - let rro = &ro; - mem::discriminant(&ro); - mem::discriminant(rro); - mem::discriminant(&rro); - - macro_rules! mem_discriminant_but_in_a_macro { - ($param:expr) => { - mem::discriminant($param) - }; - } - - mem_discriminant_but_in_a_macro!(&rro); - - let rrrrro = &&&rro; - mem::discriminant(&rrrrro); - mem::discriminant(*rrrrro); - - // ok - mem::discriminant(&Some(2)); - mem::discriminant(&None::); - mem::discriminant(&Foo::One(5)); - mem::discriminant(&Foo::Two(5)); - mem::discriminant(ro); - mem::discriminant(*rro); - mem::discriminant(****rrrrro); -} diff --git a/tests/ui/mem_discriminant.stderr b/tests/ui/mem_discriminant.stderr deleted file mode 100644 index 36a225b7594..00000000000 --- a/tests/ui/mem_discriminant.stderr +++ /dev/null @@ -1,94 +0,0 @@ -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:14:5 - | -LL | mem::discriminant(&&Some(2)); - | ^^^^^^^^^^^^^^^^^^---------^ - | | - | help: try dereferencing: `&Some(2)` - | -note: the lint level is defined here - --> $DIR/mem_discriminant.rs:3:9 - | -LL | #![deny(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:15:5 - | -LL | mem::discriminant(&&None::); - | ^^^^^^^^^^^^^^^^^^------------^ - | | - | help: try dereferencing: `&None::` - -error: calling `mem::discriminant` on non-enum type `&Foo` - --> $DIR/mem_discriminant.rs:16:5 - | -LL | mem::discriminant(&&Foo::One(5)); - | ^^^^^^^^^^^^^^^^^^-------------^ - | | - | help: try dereferencing: `&Foo::One(5)` - -error: calling `mem::discriminant` on non-enum type `&Foo` - --> $DIR/mem_discriminant.rs:17:5 - | -LL | mem::discriminant(&&Foo::Two(5)); - | ^^^^^^^^^^^^^^^^^^-------------^ - | | - | help: try dereferencing: `&Foo::Two(5)` - -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:21:5 - | -LL | mem::discriminant(&ro); - | ^^^^^^^^^^^^^^^^^^---^ - | | - | help: try dereferencing: `ro` - -error: calling `mem::discriminant` on non-enum type `&std::option::Option` - --> $DIR/mem_discriminant.rs:22:5 - | -LL | mem::discriminant(rro); - | ^^^^^^^^^^^^^^^^^^---^ - | | - | help: try dereferencing: `*rro` - -error: calling `mem::discriminant` on non-enum type `&&std::option::Option` - --> $DIR/mem_discriminant.rs:23:5 - | -LL | mem::discriminant(&rro); - | ^^^^^^^^^^^^^^^^^^----^ - | | - | help: try dereferencing: `*rro` - -error: calling `mem::discriminant` on non-enum type `&&std::option::Option` - --> $DIR/mem_discriminant.rs:27:13 - | -LL | mem::discriminant($param) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | mem_discriminant_but_in_a_macro!(&rro); - | --------------------------------------- - | | | - | | help: try dereferencing: `*rro` - | in this macro invocation - | - = note: this error originates in the macro `mem_discriminant_but_in_a_macro` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: calling `mem::discriminant` on non-enum type `&&&&&std::option::Option` - --> $DIR/mem_discriminant.rs:34:5 - | -LL | mem::discriminant(&rrrrro); - | ^^^^^^^^^^^^^^^^^^-------^ - | | - | help: try dereferencing: `****rrrrro` - -error: calling `mem::discriminant` on non-enum type `&&&std::option::Option` - --> $DIR/mem_discriminant.rs:35:5 - | -LL | mem::discriminant(*rrrrro); - | ^^^^^^^^^^^^^^^^^^-------^ - | | - | help: try dereferencing: `****rrrrro` - -error: aborting due to 10 previous errors - diff --git a/tests/ui/mem_discriminant_unfixable.rs b/tests/ui/mem_discriminant_unfixable.rs deleted file mode 100644 index e245d3257d5..00000000000 --- a/tests/ui/mem_discriminant_unfixable.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![deny(clippy::mem_discriminant_non_enum)] - -use std::mem; - -enum Foo { - One(usize), - Two(u8), -} - -struct A(Foo); - -fn main() { - // bad - mem::discriminant(&"hello"); - mem::discriminant(&A(Foo::One(0))); -} diff --git a/tests/ui/mem_discriminant_unfixable.stderr b/tests/ui/mem_discriminant_unfixable.stderr deleted file mode 100644 index e2de3776f2c..00000000000 --- a/tests/ui/mem_discriminant_unfixable.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: calling `mem::discriminant` on non-enum type `&str` - --> $DIR/mem_discriminant_unfixable.rs:14:5 - | -LL | mem::discriminant(&"hello"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/mem_discriminant_unfixable.rs:1:9 - | -LL | #![deny(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: calling `mem::discriminant` on non-enum type `A` - --> $DIR/mem_discriminant_unfixable.rs:15:5 - | -LL | mem::discriminant(&A(Foo::One(0))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 13fbb6e2a6e..a66c2e587c8 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -8,6 +8,7 @@ #![allow(clippy::redundant_static_lifetimes)] // warn for the old lint name here, to test if the renaming worked #![warn(clippy::cognitive_complexity)] +#![warn(enum_intrinsics_non_enums)] #[warn(clippy::module_name_repetitions)] fn main() {} diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index cbd3b1e9166..fa81201a2da 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -8,6 +8,7 @@ #![allow(clippy::redundant_static_lifetimes)] // warn for the old lint name here, to test if the renaming worked #![warn(clippy::cyclomatic_complexity)] +#![warn(clippy::mem_discriminant_non_enum)] #[warn(clippy::stutter)] fn main() {} diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index c5d633ff86b..05c7854074c 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -6,23 +6,29 @@ LL | #![warn(clippy::cyclomatic_complexity)] | = note: `-D renamed-and-removed-lints` implied by `-D warnings` +error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` + --> $DIR/rename.rs:11:9 + | +LL | #![warn(clippy::mem_discriminant_non_enum)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` + error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:12:8 + --> $DIR/rename.rs:13:8 | LL | #[warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:15:8 + --> $DIR/rename.rs:16:8 | LL | #[warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:18:8 + --> $DIR/rename.rs:19:8 | LL | #[warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From 44db27127249cf30a4d7a2e6e62762762e38a3cb Mon Sep 17 00:00:00 2001 From: John Kugelman Date: Mon, 11 Oct 2021 10:13:50 -0400 Subject: [PATCH 029/100] Add #[must_use] to From::from and Into::into --- tests/ui/cast_lossless_float.fixed | 22 ++--- tests/ui/cast_lossless_float.rs | 22 ++--- tests/ui/cast_lossless_float.stderr | 66 +++++++-------- tests/ui/cast_lossless_integer.fixed | 38 ++++----- tests/ui/cast_lossless_integer.rs | 38 ++++----- tests/ui/cast_lossless_integer.stderr | 114 +++++++++++++------------- 6 files changed, 150 insertions(+), 150 deletions(-) diff --git a/tests/ui/cast_lossless_float.fixed b/tests/ui/cast_lossless_float.fixed index 709d58b596c..32a9c1c4ae1 100644 --- a/tests/ui/cast_lossless_float.fixed +++ b/tests/ui/cast_lossless_float.fixed @@ -6,24 +6,24 @@ fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; - f32::from(x0); - f64::from(x0); + let _ = f32::from(x0); + let _ = f64::from(x0); let x1 = 1u8; - f32::from(x1); - f64::from(x1); + let _ = f32::from(x1); + let _ = f64::from(x1); let x2 = 1i16; - f32::from(x2); - f64::from(x2); + let _ = f32::from(x2); + let _ = f64::from(x2); let x3 = 1u16; - f32::from(x3); - f64::from(x3); + let _ = f32::from(x3); + let _ = f64::from(x3); let x4 = 1i32; - f64::from(x4); + let _ = f64::from(x4); let x5 = 1u32; - f64::from(x5); + let _ = f64::from(x5); // Test with casts from floating-point types - f64::from(1.0f32); + let _ = f64::from(1.0f32); } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_float.rs b/tests/ui/cast_lossless_float.rs index eb0aab88642..6f5ddcfe09c 100644 --- a/tests/ui/cast_lossless_float.rs +++ b/tests/ui/cast_lossless_float.rs @@ -6,24 +6,24 @@ fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; - x0 as f32; - x0 as f64; + let _ = x0 as f32; + let _ = x0 as f64; let x1 = 1u8; - x1 as f32; - x1 as f64; + let _ = x1 as f32; + let _ = x1 as f64; let x2 = 1i16; - x2 as f32; - x2 as f64; + let _ = x2 as f32; + let _ = x2 as f64; let x3 = 1u16; - x3 as f32; - x3 as f64; + let _ = x3 as f32; + let _ = x3 as f64; let x4 = 1i32; - x4 as f64; + let _ = x4 as f64; let x5 = 1u32; - x5 as f64; + let _ = x5 as f64; // Test with casts from floating-point types - 1.0f32 as f64; + let _ = 1.0f32 as f64; } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_float.stderr b/tests/ui/cast_lossless_float.stderr index 0ed09f3083c..8326d40be71 100644 --- a/tests/ui/cast_lossless_float.stderr +++ b/tests/ui/cast_lossless_float.stderr @@ -1,70 +1,70 @@ error: casting `i8` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:9:5 + --> $DIR/cast_lossless_float.rs:9:13 | -LL | x0 as f32; - | ^^^^^^^^^ help: try: `f32::from(x0)` +LL | let _ = x0 as f32; + | ^^^^^^^^^ help: try: `f32::from(x0)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting `i8` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:10:5 + --> $DIR/cast_lossless_float.rs:10:13 | -LL | x0 as f64; - | ^^^^^^^^^ help: try: `f64::from(x0)` +LL | let _ = x0 as f64; + | ^^^^^^^^^ help: try: `f64::from(x0)` error: casting `u8` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:12:5 + --> $DIR/cast_lossless_float.rs:12:13 | -LL | x1 as f32; - | ^^^^^^^^^ help: try: `f32::from(x1)` +LL | let _ = x1 as f32; + | ^^^^^^^^^ help: try: `f32::from(x1)` error: casting `u8` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:13:5 + --> $DIR/cast_lossless_float.rs:13:13 | -LL | x1 as f64; - | ^^^^^^^^^ help: try: `f64::from(x1)` +LL | let _ = x1 as f64; + | ^^^^^^^^^ help: try: `f64::from(x1)` error: casting `i16` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:15:5 + --> $DIR/cast_lossless_float.rs:15:13 | -LL | x2 as f32; - | ^^^^^^^^^ help: try: `f32::from(x2)` +LL | let _ = x2 as f32; + | ^^^^^^^^^ help: try: `f32::from(x2)` error: casting `i16` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:16:5 + --> $DIR/cast_lossless_float.rs:16:13 | -LL | x2 as f64; - | ^^^^^^^^^ help: try: `f64::from(x2)` +LL | let _ = x2 as f64; + | ^^^^^^^^^ help: try: `f64::from(x2)` error: casting `u16` to `f32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:18:5 + --> $DIR/cast_lossless_float.rs:18:13 | -LL | x3 as f32; - | ^^^^^^^^^ help: try: `f32::from(x3)` +LL | let _ = x3 as f32; + | ^^^^^^^^^ help: try: `f32::from(x3)` error: casting `u16` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:19:5 + --> $DIR/cast_lossless_float.rs:19:13 | -LL | x3 as f64; - | ^^^^^^^^^ help: try: `f64::from(x3)` +LL | let _ = x3 as f64; + | ^^^^^^^^^ help: try: `f64::from(x3)` error: casting `i32` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:21:5 + --> $DIR/cast_lossless_float.rs:21:13 | -LL | x4 as f64; - | ^^^^^^^^^ help: try: `f64::from(x4)` +LL | let _ = x4 as f64; + | ^^^^^^^^^ help: try: `f64::from(x4)` error: casting `u32` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:23:5 + --> $DIR/cast_lossless_float.rs:23:13 | -LL | x5 as f64; - | ^^^^^^^^^ help: try: `f64::from(x5)` +LL | let _ = x5 as f64; + | ^^^^^^^^^ help: try: `f64::from(x5)` error: casting `f32` to `f64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_float.rs:26:5 + --> $DIR/cast_lossless_float.rs:26:13 | -LL | 1.0f32 as f64; - | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` +LL | let _ = 1.0f32 as f64; + | ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)` error: aborting due to 11 previous errors diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed index 03e49adb117..72a708b4073 100644 --- a/tests/ui/cast_lossless_integer.fixed +++ b/tests/ui/cast_lossless_integer.fixed @@ -5,27 +5,27 @@ fn main() { // Test clippy::cast_lossless with casts to integer types - i16::from(1i8); - i32::from(1i8); - i64::from(1i8); - i16::from(1u8); - i32::from(1u8); - i64::from(1u8); - u16::from(1u8); - u32::from(1u8); - u64::from(1u8); - i32::from(1i16); - i64::from(1i16); - i32::from(1u16); - i64::from(1u16); - u32::from(1u16); - u64::from(1u16); - i64::from(1i32); - i64::from(1u32); - u64::from(1u32); + let _ = i16::from(1i8); + let _ = i32::from(1i8); + let _ = i64::from(1i8); + let _ = i16::from(1u8); + let _ = i32::from(1u8); + let _ = i64::from(1u8); + let _ = u16::from(1u8); + let _ = u32::from(1u8); + let _ = u64::from(1u8); + let _ = i32::from(1i16); + let _ = i64::from(1i16); + let _ = i32::from(1u16); + let _ = i64::from(1u16); + let _ = u32::from(1u16); + let _ = u64::from(1u16); + let _ = i64::from(1i32); + let _ = i64::from(1u32); + let _ = u64::from(1u32); // Test with an expression wrapped in parens - u16::from(1u8 + 1u8); + let _ = u16::from(1u8 + 1u8); } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs index 6a984d24596..34bb47181e6 100644 --- a/tests/ui/cast_lossless_integer.rs +++ b/tests/ui/cast_lossless_integer.rs @@ -5,27 +5,27 @@ fn main() { // Test clippy::cast_lossless with casts to integer types - 1i8 as i16; - 1i8 as i32; - 1i8 as i64; - 1u8 as i16; - 1u8 as i32; - 1u8 as i64; - 1u8 as u16; - 1u8 as u32; - 1u8 as u64; - 1i16 as i32; - 1i16 as i64; - 1u16 as i32; - 1u16 as i64; - 1u16 as u32; - 1u16 as u64; - 1i32 as i64; - 1u32 as i64; - 1u32 as u64; + let _ = 1i8 as i16; + let _ = 1i8 as i32; + let _ = 1i8 as i64; + let _ = 1u8 as i16; + let _ = 1u8 as i32; + let _ = 1u8 as i64; + let _ = 1u8 as u16; + let _ = 1u8 as u32; + let _ = 1u8 as u64; + let _ = 1i16 as i32; + let _ = 1i16 as i64; + let _ = 1u16 as i32; + let _ = 1u16 as i64; + let _ = 1u16 as u32; + let _ = 1u16 as u64; + let _ = 1i32 as i64; + let _ = 1u32 as i64; + let _ = 1u32 as u64; // Test with an expression wrapped in parens - (1u8 + 1u8) as u16; + let _ = (1u8 + 1u8) as u16; } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/tests/ui/cast_lossless_integer.stderr b/tests/ui/cast_lossless_integer.stderr index 8e2890f9c28..721b94876cb 100644 --- a/tests/ui/cast_lossless_integer.stderr +++ b/tests/ui/cast_lossless_integer.stderr @@ -1,118 +1,118 @@ error: casting `i8` to `i16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:8:5 + --> $DIR/cast_lossless_integer.rs:8:13 | -LL | 1i8 as i16; - | ^^^^^^^^^^ help: try: `i16::from(1i8)` +LL | let _ = 1i8 as i16; + | ^^^^^^^^^^ help: try: `i16::from(1i8)` | = note: `-D clippy::cast-lossless` implied by `-D warnings` error: casting `i8` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:9:5 + --> $DIR/cast_lossless_integer.rs:9:13 | -LL | 1i8 as i32; - | ^^^^^^^^^^ help: try: `i32::from(1i8)` +LL | let _ = 1i8 as i32; + | ^^^^^^^^^^ help: try: `i32::from(1i8)` error: casting `i8` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:10:5 + --> $DIR/cast_lossless_integer.rs:10:13 | -LL | 1i8 as i64; - | ^^^^^^^^^^ help: try: `i64::from(1i8)` +LL | let _ = 1i8 as i64; + | ^^^^^^^^^^ help: try: `i64::from(1i8)` error: casting `u8` to `i16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:11:5 + --> $DIR/cast_lossless_integer.rs:11:13 | -LL | 1u8 as i16; - | ^^^^^^^^^^ help: try: `i16::from(1u8)` +LL | let _ = 1u8 as i16; + | ^^^^^^^^^^ help: try: `i16::from(1u8)` error: casting `u8` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:12:5 + --> $DIR/cast_lossless_integer.rs:12:13 | -LL | 1u8 as i32; - | ^^^^^^^^^^ help: try: `i32::from(1u8)` +LL | let _ = 1u8 as i32; + | ^^^^^^^^^^ help: try: `i32::from(1u8)` error: casting `u8` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:13:5 + --> $DIR/cast_lossless_integer.rs:13:13 | -LL | 1u8 as i64; - | ^^^^^^^^^^ help: try: `i64::from(1u8)` +LL | let _ = 1u8 as i64; + | ^^^^^^^^^^ help: try: `i64::from(1u8)` error: casting `u8` to `u16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:14:5 + --> $DIR/cast_lossless_integer.rs:14:13 | -LL | 1u8 as u16; - | ^^^^^^^^^^ help: try: `u16::from(1u8)` +LL | let _ = 1u8 as u16; + | ^^^^^^^^^^ help: try: `u16::from(1u8)` error: casting `u8` to `u32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:15:5 + --> $DIR/cast_lossless_integer.rs:15:13 | -LL | 1u8 as u32; - | ^^^^^^^^^^ help: try: `u32::from(1u8)` +LL | let _ = 1u8 as u32; + | ^^^^^^^^^^ help: try: `u32::from(1u8)` error: casting `u8` to `u64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:16:5 + --> $DIR/cast_lossless_integer.rs:16:13 | -LL | 1u8 as u64; - | ^^^^^^^^^^ help: try: `u64::from(1u8)` +LL | let _ = 1u8 as u64; + | ^^^^^^^^^^ help: try: `u64::from(1u8)` error: casting `i16` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:17:5 + --> $DIR/cast_lossless_integer.rs:17:13 | -LL | 1i16 as i32; - | ^^^^^^^^^^^ help: try: `i32::from(1i16)` +LL | let _ = 1i16 as i32; + | ^^^^^^^^^^^ help: try: `i32::from(1i16)` error: casting `i16` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:18:5 + --> $DIR/cast_lossless_integer.rs:18:13 | -LL | 1i16 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1i16)` +LL | let _ = 1i16 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1i16)` error: casting `u16` to `i32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:19:5 + --> $DIR/cast_lossless_integer.rs:19:13 | -LL | 1u16 as i32; - | ^^^^^^^^^^^ help: try: `i32::from(1u16)` +LL | let _ = 1u16 as i32; + | ^^^^^^^^^^^ help: try: `i32::from(1u16)` error: casting `u16` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:20:5 + --> $DIR/cast_lossless_integer.rs:20:13 | -LL | 1u16 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1u16)` +LL | let _ = 1u16 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1u16)` error: casting `u16` to `u32` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:21:5 + --> $DIR/cast_lossless_integer.rs:21:13 | -LL | 1u16 as u32; - | ^^^^^^^^^^^ help: try: `u32::from(1u16)` +LL | let _ = 1u16 as u32; + | ^^^^^^^^^^^ help: try: `u32::from(1u16)` error: casting `u16` to `u64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:22:5 + --> $DIR/cast_lossless_integer.rs:22:13 | -LL | 1u16 as u64; - | ^^^^^^^^^^^ help: try: `u64::from(1u16)` +LL | let _ = 1u16 as u64; + | ^^^^^^^^^^^ help: try: `u64::from(1u16)` error: casting `i32` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:23:5 + --> $DIR/cast_lossless_integer.rs:23:13 | -LL | 1i32 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1i32)` +LL | let _ = 1i32 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1i32)` error: casting `u32` to `i64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:24:5 + --> $DIR/cast_lossless_integer.rs:24:13 | -LL | 1u32 as i64; - | ^^^^^^^^^^^ help: try: `i64::from(1u32)` +LL | let _ = 1u32 as i64; + | ^^^^^^^^^^^ help: try: `i64::from(1u32)` error: casting `u32` to `u64` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:25:5 + --> $DIR/cast_lossless_integer.rs:25:13 | -LL | 1u32 as u64; - | ^^^^^^^^^^^ help: try: `u64::from(1u32)` +LL | let _ = 1u32 as u64; + | ^^^^^^^^^^^ help: try: `u64::from(1u32)` error: casting `u8` to `u16` may become silently lossy if you later change the type - --> $DIR/cast_lossless_integer.rs:28:5 + --> $DIR/cast_lossless_integer.rs:28:13 | -LL | (1u8 + 1u8) as u16; - | ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)` +LL | let _ = (1u8 + 1u8) as u16; + | ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)` error: aborting due to 19 previous errors From 9e0ce14700070a5cf61ebdb542cefd70a1dd9b0c Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Mon, 11 Oct 2021 20:19:34 -0400 Subject: [PATCH 030/100] Add match_str_case_mismatch lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_correctness.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/match_str_case_mismatch.rs | 166 +++++++++++++++++++ tests/ui/match_str_case_mismatch.rs | 98 +++++++++++ tests/ui/match_str_case_mismatch.stderr | 53 ++++++ 8 files changed, 323 insertions(+) create mode 100644 clippy_lints/src/match_str_case_mismatch.rs create mode 100644 tests/ui/match_str_case_mismatch.rs create mode 100644 tests/ui/match_str_case_mismatch.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 13067e4e92a..1f79d9e73db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2837,6 +2837,7 @@ Released 2018-09-13 [`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms [`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding +[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 3e6e0244754..e544c6607e8 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -118,6 +118,7 @@ LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(match_result_ok::MATCH_RESULT_OK), + LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH), LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(matches::MATCH_AS_REF), LintId::of(matches::MATCH_LIKE_MATCHES_MACRO), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index e0ef7b3b8af..1c2441d1af2 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -36,6 +36,7 @@ LintId::of(loops::ITER_NEXT_LOOP), LintId::of(loops::NEVER_LOOP), LintId::of(loops::WHILE_IMMUTABLE_CONDITION), + LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH), LintId::of(mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 3c4b720671a..d5673ad2c7c 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -226,6 +226,7 @@ map_unit_fn::RESULT_MAP_UNIT_FN, match_on_vec_items::MATCH_ON_VEC_ITEMS, match_result_ok::MATCH_RESULT_OK, + match_str_case_mismatch::MATCH_STR_CASE_MISMATCH, matches::INFALLIBLE_DESTRUCTURING_MATCH, matches::MATCH_AS_REF, matches::MATCH_BOOL, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7e1bcbbd0ed..73d21eb5b52 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -265,6 +265,7 @@ macro_rules! declare_clippy_lint { mod map_unit_fn; mod match_on_vec_items; mod match_result_ok; +mod match_str_case_mismatch; mod matches; mod mem_discriminant; mod mem_forget; @@ -771,6 +772,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send))); store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); + store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); } #[rustfmt::skip] diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/match_str_case_mismatch.rs new file mode 100644 index 00000000000..dd8b5cb4a21 --- /dev/null +++ b/clippy_lints/src/match_str_case_mismatch.rs @@ -0,0 +1,166 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_ast::ast::LitKind; +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `match` expressions modifying the case of a string with non-compliant arms + /// + /// ### Why is this bad? + /// The arm is unreachable, which is likely a mistake + /// + /// ### Example + /// ```rust + /// match &*text.to_ascii_lowercase() { + /// "foo" => {}, + /// "Bar" => {}, + /// _ => {}, + /// } + /// ``` + /// Use instead: + /// ```rust + /// match &*text.to_ascii_lowercase() { + /// "foo" => {}, + /// "bar" => {}, + /// _ => {}, + /// } + /// ``` + pub MATCH_STR_CASE_MISMATCH, + correctness, + "creation of a case altering match expression with non-compliant arms" +} + +declare_lint_pass!(MatchStrCaseMismatch => [MATCH_STR_CASE_MISMATCH]); + +#[derive(Debug)] +enum CaseMethod { + LowerCase, + AsciiLowerCase, + UpperCase, + AsciiUppercase, +} + +impl LateLintPass<'_> for MatchStrCaseMismatch { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + if !in_external_macro(cx.tcx.sess, expr.span); + if let ExprKind::Match(match_expr, arms, MatchSource::Normal) = expr.kind; + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(match_expr).kind(); + if let ty::Str = ty.kind(); + then { + let mut visitor = MatchExprVisitor { + cx, + case_method: None, + }; + + visitor.visit_expr(match_expr); + + if let Some(case_method) = visitor.case_method { + if let Some(bad_case) = verify_case(&case_method, arms) { + lint(cx, expr.span, &case_method, bad_case); + } + } + } + } + } +} + +struct MatchExprVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + case_method: Option, +} + +impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { + match ex.kind { + ExprKind::MethodCall(segment, _, [receiver], _) + if self.case_altered(&*segment.ident.as_str(), receiver) => {}, + _ => walk_expr(self, ex), + } + } +} + +impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> { + fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool { + if let Some(case_method) = get_case_method(segment_ident) { + let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); + + if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str { + self.case_method = Some(case_method); + return true; + } + } + + false + } +} + +fn get_case_method(segment_ident_str: &str) -> Option { + match segment_ident_str { + "to_lowercase" => Some(CaseMethod::LowerCase), + "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase), + "to_uppercase" => Some(CaseMethod::UpperCase), + "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase), + _ => None, + } +} + +fn verify_case(case_method: &CaseMethod, arms: &'_ [Arm<'_>]) -> Option { + let mut bad_case = None; + + let case_check = match case_method { + CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) }, + CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) }, + CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) }, + CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) }, + }; + + for arm in arms { + if_chain! { + if let PatKind::Lit(Expr { + kind: ExprKind::Lit(lit), + .. + }) = arm.pat.kind; + if let LitKind::Str(symbol, _) = lit.node; + if !case_check(&symbol.as_str()); + then { + bad_case = Some(lit.span); + break; + } + } + } + + bad_case +} + +fn lint(cx: &LateContext<'_>, expr_span: Span, case_method: &CaseMethod, bad_case_span: Span) { + let method_str = match case_method { + CaseMethod::LowerCase => "to_lower_case", + CaseMethod::AsciiLowerCase => "to_ascii_lowercase", + CaseMethod::UpperCase => "to_uppercase", + CaseMethod::AsciiUppercase => "to_ascii_uppercase", + }; + + span_lint_and_help( + cx, + MATCH_STR_CASE_MISMATCH, + expr_span, + "this `match` expression alters case, but has non-compliant arms", + Some(bad_case_span), + &*format!("consider changing the case of this arm to respect `{}`", method_str), + ); +} diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs new file mode 100644 index 00000000000..208a4bba3d2 --- /dev/null +++ b/tests/ui/match_str_case_mismatch.rs @@ -0,0 +1,98 @@ +#![warn(clippy::match_str_case_mismatch)] + +// Valid + +fn as_str_match() { + let var = "BAR"; + + match var.to_ascii_lowercase().as_str() { + "foo" => {}, + "bar" => {}, + _ => {}, + } +} + +fn addrof_unary_match() { + let var = "BAR"; + + match &*var.to_ascii_lowercase() { + "foo" => {}, + "bar" => {}, + _ => {}, + } +} + +fn alternating_chain() { + let var = "BAR"; + + match &*var + .to_ascii_lowercase() + .to_uppercase() + .to_lowercase() + .to_ascii_uppercase() + { + "FOO" => {}, + "BAR" => {}, + _ => {}, + } +} + +fn unrelated_method() { + struct Item { + a: String, + } + + impl Item { + #[allow(clippy::wrong_self_convention)] + fn to_lowercase(self) -> String { + self.a + } + } + + let item = Item { a: String::from("BAR") }; + + match &*item.to_lowercase() { + "FOO" => {}, + "BAR" => {}, + _ => {}, + } +} + +// Invalid + +fn as_str_match_mismatch() { + let var = "BAR"; + + match var.to_ascii_lowercase().as_str() { + "foo" => {}, + "Bar" => {}, + _ => {}, + } +} + +fn addrof_unary_match_mismatch() { + let var = "BAR"; + + match &*var.to_ascii_lowercase() { + "foo" => {}, + "Bar" => {}, + _ => {}, + } +} + +fn alternating_chain_mismatch() { + let var = "BAR"; + + match &*var + .to_ascii_lowercase() + .to_uppercase() + .to_lowercase() + .to_ascii_uppercase() + { + "FOO" => {}, + "bAR" => {}, + _ => {}, + } +} + +fn main() {} diff --git a/tests/ui/match_str_case_mismatch.stderr b/tests/ui/match_str_case_mismatch.stderr new file mode 100644 index 00000000000..a5eab1f72f3 --- /dev/null +++ b/tests/ui/match_str_case_mismatch.stderr @@ -0,0 +1,53 @@ +error: this `match` expression alters case, but has non-compliant arms + --> $DIR/match_str_case_mismatch.rs:66:5 + | +LL | / match var.to_ascii_lowercase().as_str() { +LL | | "foo" => {}, +LL | | "Bar" => {}, +LL | | _ => {}, +LL | | } + | |_____^ + | + = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings` +help: consider changing the case of this arm to respect `to_ascii_lowercase` + --> $DIR/match_str_case_mismatch.rs:68:9 + | +LL | "Bar" => {}, + | ^^^^^ + +error: this `match` expression alters case, but has non-compliant arms + --> $DIR/match_str_case_mismatch.rs:76:5 + | +LL | / match &*var.to_ascii_lowercase() { +LL | | "foo" => {}, +LL | | "Bar" => {}, +LL | | _ => {}, +LL | | } + | |_____^ + | +help: consider changing the case of this arm to respect `to_ascii_lowercase` + --> $DIR/match_str_case_mismatch.rs:78:9 + | +LL | "Bar" => {}, + | ^^^^^ + +error: this `match` expression alters case, but has non-compliant arms + --> $DIR/match_str_case_mismatch.rs:86:5 + | +LL | / match &*var +LL | | .to_ascii_lowercase() +LL | | .to_uppercase() +LL | | .to_lowercase() +... | +LL | | _ => {}, +LL | | } + | |_____^ + | +help: consider changing the case of this arm to respect `to_ascii_uppercase` + --> $DIR/match_str_case_mismatch.rs:93:9 + | +LL | "bAR" => {}, + | ^^^^^ + +error: aborting due to 3 previous errors + From 99bfee720119240d8eb64c2fd395aeaecc683b9a Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Mon, 11 Oct 2021 20:40:13 -0400 Subject: [PATCH 031/100] Don't run examples --- clippy_lints/src/match_str_case_mismatch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/match_str_case_mismatch.rs index dd8b5cb4a21..ae6d2b6c79d 100644 --- a/clippy_lints/src/match_str_case_mismatch.rs +++ b/clippy_lints/src/match_str_case_mismatch.rs @@ -18,7 +18,7 @@ /// The arm is unreachable, which is likely a mistake /// /// ### Example - /// ```rust + /// ```rust,no_run /// match &*text.to_ascii_lowercase() { /// "foo" => {}, /// "Bar" => {}, @@ -26,7 +26,7 @@ /// } /// ``` /// Use instead: - /// ```rust + /// ```rust,no_run /// match &*text.to_ascii_lowercase() { /// "foo" => {}, /// "bar" => {}, From 5adf17cb43d62e7e02c13f32def548b724bf2148 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 12 Oct 2021 09:42:42 +0200 Subject: [PATCH 032/100] Bring `manual_split_once` docs in line with other lint docs --- clippy_lints/src/methods/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b26d11c0d6b..26c29fbb289 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1777,14 +1777,13 @@ } declare_clippy_lint! { - /// **What it does:** Checks for usages of `str::splitn(2, _)` + /// ### What it does + /// Checks for usages of `str::splitn(2, _)` /// - /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient. - /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Why is this bad? + /// `split_once` is both clearer in intent and slightly more efficient. /// + /// ### Example /// ```rust,ignore /// // Bad /// let (key, value) = _.splitn(2, '=').next_tuple()?; From 0c99de0ab2a83740c921e4b4bfc67177c787ff36 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Tue, 12 Oct 2021 07:13:19 -0400 Subject: [PATCH 033/100] Add a suggestion --- clippy_lints/src/match_str_case_mismatch.rs | 49 ++++++++++--------- tests/ui/match_str_case_mismatch.stderr | 53 +++++++-------------- 2 files changed, 45 insertions(+), 57 deletions(-) diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/match_str_case_mismatch.rs index ae6d2b6c79d..a83f38e3d51 100644 --- a/clippy_lints/src/match_str_case_mismatch.rs +++ b/clippy_lints/src/match_str_case_mismatch.rs @@ -1,6 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -8,6 +9,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::SymbolStr; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -18,7 +20,9 @@ /// The arm is unreachable, which is likely a mistake /// /// ### Example - /// ```rust,no_run + /// ```rust + /// # let text = "Foo"; + /// /// match &*text.to_ascii_lowercase() { /// "foo" => {}, /// "Bar" => {}, @@ -26,7 +30,9 @@ /// } /// ``` /// Use instead: - /// ```rust,no_run + /// ```rust + /// # let text = "Foo"; + /// /// match &*text.to_ascii_lowercase() { /// "foo" => {}, /// "bar" => {}, @@ -64,8 +70,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { visitor.visit_expr(match_expr); if let Some(case_method) = visitor.case_method { - if let Some(bad_case) = verify_case(&case_method, arms) { - lint(cx, expr.span, &case_method, bad_case); + if let Some((bad_case_span, bad_case_str)) = verify_case(&case_method, arms) { + lint(cx, &case_method, bad_case_span, &bad_case_str); } } } @@ -119,9 +125,7 @@ fn get_case_method(segment_ident_str: &str) -> Option { } } -fn verify_case(case_method: &CaseMethod, arms: &'_ [Arm<'_>]) -> Option { - let mut bad_case = None; - +fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> { let case_check = match case_method { CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) }, CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) }, @@ -136,31 +140,32 @@ fn verify_case(case_method: &CaseMethod, arms: &'_ [Arm<'_>]) -> Option { .. }) = arm.pat.kind; if let LitKind::Str(symbol, _) = lit.node; - if !case_check(&symbol.as_str()); + let input = symbol.as_str(); + if !case_check(&input); then { - bad_case = Some(lit.span); - break; + return Some((lit.span, input)); } } } - bad_case + None } -fn lint(cx: &LateContext<'_>, expr_span: Span, case_method: &CaseMethod, bad_case_span: Span) { - let method_str = match case_method { - CaseMethod::LowerCase => "to_lower_case", - CaseMethod::AsciiLowerCase => "to_ascii_lowercase", - CaseMethod::UpperCase => "to_uppercase", - CaseMethod::AsciiUppercase => "to_ascii_uppercase", +fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) { + let (method_str, suggestion) = match case_method { + CaseMethod::LowerCase => ("to_lower_case", bad_case_str.to_lowercase()), + CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()), + CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()), + CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()), }; - span_lint_and_help( + span_lint_and_sugg( cx, MATCH_STR_CASE_MISMATCH, - expr_span, - "this `match` expression alters case, but has non-compliant arms", - Some(bad_case_span), + bad_case_span, + "this `match` arm has a differing case than its expression", &*format!("consider changing the case of this arm to respect `{}`", method_str), + format!("\"{}\"", suggestion), + Applicability::MachineApplicable, ); } diff --git a/tests/ui/match_str_case_mismatch.stderr b/tests/ui/match_str_case_mismatch.stderr index a5eab1f72f3..fa023477a9c 100644 --- a/tests/ui/match_str_case_mismatch.stderr +++ b/tests/ui/match_str_case_mismatch.stderr @@ -1,53 +1,36 @@ -error: this `match` expression alters case, but has non-compliant arms - --> $DIR/match_str_case_mismatch.rs:66:5 - | -LL | / match var.to_ascii_lowercase().as_str() { -LL | | "foo" => {}, -LL | | "Bar" => {}, -LL | | _ => {}, -LL | | } - | |_____^ - | - = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings` -help: consider changing the case of this arm to respect `to_ascii_lowercase` +error: this `match` arm has a differing case than its expression --> $DIR/match_str_case_mismatch.rs:68:9 | LL | "Bar" => {}, | ^^^^^ - -error: this `match` expression alters case, but has non-compliant arms - --> $DIR/match_str_case_mismatch.rs:76:5 - | -LL | / match &*var.to_ascii_lowercase() { -LL | | "foo" => {}, -LL | | "Bar" => {}, -LL | | _ => {}, -LL | | } - | |_____^ | + = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings` help: consider changing the case of this arm to respect `to_ascii_lowercase` + | +LL | "bar" => {}, + | ~~~~~ + +error: this `match` arm has a differing case than its expression --> $DIR/match_str_case_mismatch.rs:78:9 | LL | "Bar" => {}, | ^^^^^ + | +help: consider changing the case of this arm to respect `to_ascii_lowercase` + | +LL | "bar" => {}, + | ~~~~~ -error: this `match` expression alters case, but has non-compliant arms - --> $DIR/match_str_case_mismatch.rs:86:5 - | -LL | / match &*var -LL | | .to_ascii_lowercase() -LL | | .to_uppercase() -LL | | .to_lowercase() -... | -LL | | _ => {}, -LL | | } - | |_____^ - | -help: consider changing the case of this arm to respect `to_ascii_uppercase` +error: this `match` arm has a differing case than its expression --> $DIR/match_str_case_mismatch.rs:93:9 | LL | "bAR" => {}, | ^^^^^ + | +help: consider changing the case of this arm to respect `to_ascii_uppercase` + | +LL | "BAR" => {}, + | ~~~~~ error: aborting due to 3 previous errors From 4ed3a4fe2f681660cac9a4fad6385c6d92a89de1 Mon Sep 17 00:00:00 2001 From: Yechan Bae Date: Tue, 12 Oct 2021 16:01:58 -0400 Subject: [PATCH 034/100] Update lint description for new() and default() --- clippy_lints/src/uninit_vec.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 2573209d1b6..f3e8b688105 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -13,14 +13,16 @@ declare_clippy_lint! { /// ### What it does /// Checks for `set_len()` call that creates `Vec` with uninitialized elements. - /// This is commonly caused by calling `set_len()` right after after calling - /// `with_capacity()` or `reserve()`. + /// This is commonly caused by calling `set_len()` right after allocating or + /// reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`. /// /// ### Why is this bad? /// It creates a `Vec` with uninitialized data, which leads to - /// undefined behavior with most safe operations. + /// undefined behavior with most safe operations. Notably, uninitialized + /// `Vec` must not be used with generic `Read`. /// - /// Notably, uninitialized `Vec` must not be used with generic `Read`. + /// Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()` + /// creates out-of-bound values that lead to heap memory corruption when used. /// /// ### Known Problems /// This lint only checks directly adjacent statements. From 049ab82662d4f63bd88bdcba97b172421f906dd5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 13 Oct 2021 11:06:14 +0000 Subject: [PATCH 035/100] Update clippy ui output --- tests/ui/crashes/ice-6256.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/crashes/ice-6256.stderr b/tests/ui/crashes/ice-6256.stderr index d35d459168f..ae4e6cad332 100644 --- a/tests/ui/crashes/ice-6256.stderr +++ b/tests/ui/crashes/ice-6256.stderr @@ -6,7 +6,7 @@ LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types | = note: expected reference `&(dyn TT + 'static)` found reference `&dyn TT` -note: the anonymous lifetime #1 defined on the body at 13:13... +note: the anonymous lifetime #1 defined here... --> $DIR/ice-6256.rs:13:13 | LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types From 58969807ab7a79caecf33ad8a03df8a9793a23ad Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 11 Oct 2021 23:46:49 +0100 Subject: [PATCH 036/100] Add lint transmute_num_to_bytes Closes #7803 changelog: [`transmute_num_to_bytes`] new lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/transmute/mod.rs | 25 +++++ .../src/transmute/transmute_num_to_bytes.rs | 49 ++++++++++ tests/ui/transmute.rs | 27 ++++++ tests/ui/transmute.stderr | 92 ++++++++++++++++++- 8 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 clippy_lints/src/transmute/transmute_num_to_bytes.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 13067e4e92a..4c0b1991fd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3024,6 +3024,7 @@ Released 2018-09-13 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float +[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref [`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 3e6e0244754..8d0a3e7423b 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -266,6 +266,7 @@ LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES), LintId::of(transmute::TRANSMUTE_PTR_TO_REF), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 64b82fc0faa..c51341bdf0c 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -82,6 +82,7 @@ LintId::of(transmute::TRANSMUTE_INT_TO_BOOL), LintId::of(transmute::TRANSMUTE_INT_TO_CHAR), LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), + LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES), LintId::of(transmute::TRANSMUTE_PTR_TO_REF), LintId::of(types::BORROWED_BOX), LintId::of(types::TYPE_COMPLEXITY), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 3c4b720671a..8d17317c38e 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -449,6 +449,7 @@ transmute::TRANSMUTE_INT_TO_BOOL, transmute::TRANSMUTE_INT_TO_CHAR, transmute::TRANSMUTE_INT_TO_FLOAT, + transmute::TRANSMUTE_NUM_TO_BYTES, transmute::TRANSMUTE_PTR_TO_PTR, transmute::TRANSMUTE_PTR_TO_REF, transmute::UNSOUND_COLLECTION_TRANSMUTE, diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 33ec9c331ce..374999473a4 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -3,6 +3,7 @@ mod transmute_int_to_bool; mod transmute_int_to_char; mod transmute_int_to_float; +mod transmute_num_to_bytes; mod transmute_ptr_to_ptr; mod transmute_ptr_to_ref; mod transmute_ref_to_ref; @@ -261,6 +262,28 @@ "transmutes from a float to an integer" } +declare_clippy_lint! { + /// # What it does + /// Checks for transmutes from a number to an array of `u8` + /// + /// ### Why this is bad? + /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes` + /// is intuitive and safe. + /// + /// ### Example + /// ```rust + /// unsafe { + /// let x: [u8; 8] = std::mem::transmute(1i64); + /// } + /// + /// // should be + /// let x: [u8; 8] = 0i64.to_ne_bytes(); + /// ``` + pub TRANSMUTE_NUM_TO_BYTES, + complexity, + "transmutes from a number to an array of `u8`" +} + declare_clippy_lint! { /// ### What it does /// Checks for transmutes from a pointer to a pointer, or @@ -330,6 +353,7 @@ TRANSMUTE_INT_TO_BOOL, TRANSMUTE_INT_TO_FLOAT, TRANSMUTE_FLOAT_TO_INT, + TRANSMUTE_NUM_TO_BYTES, UNSOUND_COLLECTION_TRANSMUTE, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, ]); @@ -365,6 +389,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args); linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context); linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context); + linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context); linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty); if !linted { diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs new file mode 100644 index 00000000000..dd5ded1c91a --- /dev/null +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -0,0 +1,49 @@ +use super::TRANSMUTE_NUM_TO_BYTES; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty, UintTy}; + +/// Checks for `transmute_int_to_float` lint. +/// Returns `true` if it's triggered, otherwise returns `false`. +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, + args: &'tcx [Expr<'_>], + const_context: bool, +) -> bool { + match (&from_ty.kind(), &to_ty.kind()) { + (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => { + if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) { + return false; + } + if matches!(from_ty.kind(), ty::Float(_)) && const_context { + // TODO: Remove when const_float_bits_conv is stabilized + // rust#72447 + return false; + } + + span_lint_and_then( + cx, + TRANSMUTE_NUM_TO_BYTES, + e.span, + &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + |diag| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + diag.span_suggestion( + e.span, + "consider using `to_ne_bytes()`", + format!("{}.to_ne_bytes()", arg.to_string()), + Applicability::Unspecified, + ); + }, + ); + true + }, + _ => false, + } +} diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index bce4c81b78a..6a7037d8f38 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -103,6 +103,33 @@ const fn from_bits_64(v: u64) -> f64 { } } +mod num_to_bytes { + fn test() { + unsafe { + let _: [u8; 1] = std::mem::transmute(0u8); + let _: [u8; 4] = std::mem::transmute(0u32); + let _: [u8; 16] = std::mem::transmute(0u128); + let _: [u8; 1] = std::mem::transmute(0i8); + let _: [u8; 4] = std::mem::transmute(0i32); + let _: [u8; 16] = std::mem::transmute(0i128); + let _: [u8; 4] = std::mem::transmute(0.0f32); + let _: [u8; 8] = std::mem::transmute(0.0f64); + } + } + const fn test_const() { + unsafe { + let _: [u8; 1] = std::mem::transmute(0u8); + let _: [u8; 4] = std::mem::transmute(0u32); + let _: [u8; 16] = std::mem::transmute(0u128); + let _: [u8; 1] = std::mem::transmute(0i8); + let _: [u8; 4] = std::mem::transmute(0i32); + let _: [u8; 16] = std::mem::transmute(0i128); + let _: [u8; 4] = std::mem::transmute(0.0f32); + let _: [u8; 8] = std::mem::transmute(0.0f64); + } + } +} + fn bytes_to_str(b: &[u8], mb: &mut [u8]) { let _: &str = unsafe { std::mem::transmute(b) }; let _: &mut str = unsafe { std::mem::transmute(mb) }; diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index e31accb982a..86537153e32 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -140,8 +140,94 @@ error: transmute from a `i64` to a `f64` LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` +error: transmute from a `u8` to a `[u8; 1]` + --> $DIR/transmute.rs:109:30 + | +LL | let _: [u8; 1] = std::mem::transmute(0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` + | + = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings` + +error: transmute from a `u32` to a `[u8; 4]` + --> $DIR/transmute.rs:110:30 + | +LL | let _: [u8; 4] = std::mem::transmute(0u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` + +error: transmute from a `u128` to a `[u8; 16]` + --> $DIR/transmute.rs:111:31 + | +LL | let _: [u8; 16] = std::mem::transmute(0u128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` + +error: transmute from a `i8` to a `[u8; 1]` + --> $DIR/transmute.rs:112:30 + | +LL | let _: [u8; 1] = std::mem::transmute(0i8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` + +error: transmute from a `i32` to a `[u8; 4]` + --> $DIR/transmute.rs:113:30 + | +LL | let _: [u8; 4] = std::mem::transmute(0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` + +error: transmute from a `i128` to a `[u8; 16]` + --> $DIR/transmute.rs:114:31 + | +LL | let _: [u8; 16] = std::mem::transmute(0i128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` + +error: transmute from a `f32` to a `[u8; 4]` + --> $DIR/transmute.rs:115:30 + | +LL | let _: [u8; 4] = std::mem::transmute(0.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()` + +error: transmute from a `f64` to a `[u8; 8]` + --> $DIR/transmute.rs:116:30 + | +LL | let _: [u8; 8] = std::mem::transmute(0.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()` + +error: transmute from a `u8` to a `[u8; 1]` + --> $DIR/transmute.rs:121:30 + | +LL | let _: [u8; 1] = std::mem::transmute(0u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` + +error: transmute from a `u32` to a `[u8; 4]` + --> $DIR/transmute.rs:122:30 + | +LL | let _: [u8; 4] = std::mem::transmute(0u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()` + +error: transmute from a `u128` to a `[u8; 16]` + --> $DIR/transmute.rs:123:31 + | +LL | let _: [u8; 16] = std::mem::transmute(0u128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()` + +error: transmute from a `i8` to a `[u8; 1]` + --> $DIR/transmute.rs:124:30 + | +LL | let _: [u8; 1] = std::mem::transmute(0i8); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()` + +error: transmute from a `i32` to a `[u8; 4]` + --> $DIR/transmute.rs:125:30 + | +LL | let _: [u8; 4] = std::mem::transmute(0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()` + +error: transmute from a `i128` to a `[u8; 16]` + --> $DIR/transmute.rs:126:31 + | +LL | let _: [u8; 16] = std::mem::transmute(0i128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` + error: transmute from a `&[u8]` to a `&str` - --> $DIR/transmute.rs:107:28 + --> $DIR/transmute.rs:134:28 | LL | let _: &str = unsafe { std::mem::transmute(b) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()` @@ -149,10 +235,10 @@ LL | let _: &str = unsafe { std::mem::transmute(b) }; = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` error: transmute from a `&mut [u8]` to a `&mut str` - --> $DIR/transmute.rs:108:32 + --> $DIR/transmute.rs:135:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` -error: aborting due to 24 previous errors +error: aborting due to 38 previous errors From 09aa4ad6dca75be43ef782884fab36176cb785f0 Mon Sep 17 00:00:00 2001 From: nhamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Wed, 13 Oct 2021 12:12:46 -0700 Subject: [PATCH 037/100] Fix typo in example for `match_result_ok` --- clippy_lints/src/match_result_ok.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 3db1f0421ea..ecf6ad316a4 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -35,7 +35,7 @@ /// } /// /// if let Ok(value) = iter.next() { - /// vec.push_value) + /// vec.push(value) /// } /// ``` pub MATCH_RESULT_OK, From e664a76add1636f6a629b947e884790e526b178f Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Fri, 15 Oct 2021 06:20:28 +0200 Subject: [PATCH 038/100] Refactor overlapping arm tests Make the `println!`s match the patterns. Currently they are using the deprecated syntax for inclusive ranges and extra spacing. --- tests/ui/match_overlapping_arm.rs | 48 +++++++++++++-------------- tests/ui/match_overlapping_arm.stderr | 20 +++++------ 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index 846d665d1d8..d8a65496b25 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -10,81 +10,81 @@ fn overlapping() { const FOO: u64 = 2; match 42 { - 0..=10 => println!("0 ... 10"), - 0..=11 => println!("0 ... 11"), + 0..=10 => println!("0..=10"), + 0..=11 => println!("0..=11"), _ => (), } match 42 { - 0..=5 => println!("0 ... 5"), - 6..=7 => println!("6 ... 7"), - FOO..=11 => println!("0 ... 11"), + 0..=5 => println!("0..=5"), + 6..=7 => println!("6..=7"), + FOO..=11 => println!("FOO..=11"), _ => (), } match 42 { 2 => println!("2"), - 0..=5 => println!("0 ... 5"), + 0..=5 => println!("0..=5"), _ => (), } match 42 { 2 => println!("2"), - 0..=2 => println!("0 ... 2"), + 0..=2 => println!("0..=2"), _ => (), } match 42 { - 0..=10 => println!("0 ... 10"), - 11..=50 => println!("11 ... 50"), + 0..=10 => println!("0..=10"), + 11..=50 => println!("11..=50"), _ => (), } match 42 { 2 => println!("2"), - 0..2 => println!("0 .. 2"), + 0..2 => println!("0..2"), _ => (), } match 42 { - 0..10 => println!("0 .. 10"), - 10..50 => println!("10 .. 50"), + 0..10 => println!("0..10"), + 10..50 => println!("10..50"), _ => (), } match 42 { - 0..11 => println!("0 .. 11"), - 0..=11 => println!("0 ... 11"), + 0..11 => println!("0..11"), + 0..=11 => println!("0..=11"), _ => (), } match 42 { - 5..7 => println!("5 .. 7"), - 0..10 => println!("0 .. 10"), + 5..7 => println!("5..7"), + 0..10 => println!("0..10"), _ => (), } match 42 { - 5..10 => println!("5 .. 10"), - 0..=10 => println!("0 ... 10"), + 5..10 => println!("5..10"), + 0..=10 => println!("0..=10"), _ => (), } match 42 { - 0..14 => println!("0 .. 14"), - 5..10 => println!("5 .. 10"), + 0..14 => println!("0..14"), + 5..10 => println!("5..10"), _ => (), } match 42 { - 5..14 => println!("5 .. 14"), - 0..=10 => println!("0 ... 10"), + 5..14 => println!("5..14"), + 0..=10 => println!("0..=10"), _ => (), } match 42 { - 0..7 => println!("0 .. 7"), - 0..=10 => println!("0 ... 10"), + 0..7 => println!("0..7"), + 0..=10 => println!("0..=10"), _ => (), } diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr index 359fa49f51b..5d3f1637e94 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -1,62 +1,62 @@ error: some ranges overlap --> $DIR/match_overlapping_arm.rs:13:9 | -LL | 0..=10 => println!("0 ... 10"), +LL | 0..=10 => println!("0..=10"), | ^^^^^^ | = note: `-D clippy::match-overlapping-arm` implied by `-D warnings` note: overlaps with this --> $DIR/match_overlapping_arm.rs:14:9 | -LL | 0..=11 => println!("0 ... 11"), +LL | 0..=11 => println!("0..=11"), | ^^^^^^ error: some ranges overlap --> $DIR/match_overlapping_arm.rs:19:9 | -LL | 0..=5 => println!("0 ... 5"), +LL | 0..=5 => println!("0..=5"), | ^^^^^ | note: overlaps with this --> $DIR/match_overlapping_arm.rs:21:9 | -LL | FOO..=11 => println!("0 ... 11"), +LL | FOO..=11 => println!("FOO..=11"), | ^^^^^^^^ error: some ranges overlap --> $DIR/match_overlapping_arm.rs:56:9 | -LL | 0..11 => println!("0 .. 11"), +LL | 0..11 => println!("0..11"), | ^^^^^ | note: overlaps with this --> $DIR/match_overlapping_arm.rs:57:9 | -LL | 0..=11 => println!("0 ... 11"), +LL | 0..=11 => println!("0..=11"), | ^^^^^^ error: some ranges overlap --> $DIR/match_overlapping_arm.rs:81:9 | -LL | 0..=10 => println!("0 ... 10"), +LL | 0..=10 => println!("0..=10"), | ^^^^^^ | note: overlaps with this --> $DIR/match_overlapping_arm.rs:80:9 | -LL | 5..14 => println!("5 .. 14"), +LL | 5..14 => println!("5..14"), | ^^^^^ error: some ranges overlap --> $DIR/match_overlapping_arm.rs:86:9 | -LL | 0..7 => println!("0 .. 7"), +LL | 0..7 => println!("0..7"), | ^^^^ | note: overlaps with this --> $DIR/match_overlapping_arm.rs:87:9 | -LL | 0..=10 => println!("0 ... 10"), +LL | 0..=10 => println!("0..=10"), | ^^^^^^ error: aborting due to 5 previous errors From 28a249b53e0874e87ba53f491acf11bbddff0789 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Fri, 15 Oct 2021 06:25:11 +0200 Subject: [PATCH 039/100] Add unbounded pats to `match_overlapping_arm` tests --- tests/ui/match_overlapping_arm.rs | 11 ++++------- tests/ui/match_overlapping_arm.stderr | 14 +++++++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index d8a65496b25..ff91c4498ec 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -88,20 +88,17 @@ fn overlapping() { _ => (), } - /* - // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns match 42 { - 0.. => println!("0 .. 42"), - 3.. => println!("3 .. 42"), + 3.. => println!("3.."), + 0.. => println!("0.."), _ => (), } match 42 { - ..=23 => println!("0 ... 23"), - ..26 => println!("0 .. 26"), + ..=23 => println!("..=23"), + ..26 => println!("..26"), _ => (), } - */ if let None = Some(42) { // nothing diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr index 5d3f1637e94..c2b3f173c2b 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -59,5 +59,17 @@ note: overlaps with this LL | 0..=10 => println!("0..=10"), | ^^^^^^ -error: aborting due to 5 previous errors +error: some ranges overlap + --> $DIR/match_overlapping_arm.rs:98:9 + | +LL | ..=23 => println!("..=23"), + | ^^^^^ + | +note: overlaps with this + --> $DIR/match_overlapping_arm.rs:99:9 + | +LL | ..26 => println!("..26"), + | ^^^^ + +error: aborting due to 6 previous errors From 0a23fff82d44153c5756ec81fc8fe47f595dc2ee Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 14 Oct 2021 13:28:30 -0500 Subject: [PATCH 040/100] Fix clippy with changed macro statement spans --- clippy_lints/src/copies.rs | 18 ++++---- clippy_lints/src/format.rs | 7 +-- clippy_lints/src/needless_continue.rs | 13 +++--- .../conf_nonstandard_macro_braces.stderr | 6 +-- tests/ui/asm_syntax.stderr | 10 ++--- tests/ui/assertions_on_constants.stderr | 18 ++++---- tests/ui/bool_assert_comparison.stderr | 44 +++++++++---------- .../checked_unwrap/simple_conditionals.stderr | 2 +- tests/ui/collapsible_match2.stderr | 2 +- tests/ui/crashes/ice-6255.stderr | 2 +- .../others.stderr | 2 +- .../traits.stderr | 2 +- tests/ui/default_numeric_fallback_f64.stderr | 2 +- tests/ui/default_numeric_fallback_i32.stderr | 2 +- tests/ui/doc_unsafe.stderr | 2 +- tests/ui/eq_op_macros.stderr | 8 ++-- tests/ui/fallible_impl_from.stderr | 8 ++-- tests/ui/format.stderr | 26 +++++------ tests/ui/implicit_hasher.stderr | 6 +-- tests/ui/item_after_statement.stderr | 2 +- tests/ui/mem_replace_macro.stderr | 2 +- tests/ui/missing_panics_doc.stderr | 4 +- tests/ui/panic_in_result_fn.stderr | 12 ++--- tests/ui/panic_in_result_fn_assertions.stderr | 6 +-- tests/ui/panicking_macros.stderr | 32 +++++++------- tests/ui/pattern_type_mismatch/syntax.stderr | 2 +- tests/ui/toplevel_ref_arg.stderr | 2 +- tests/ui/toplevel_ref_arg_non_rustfix.stderr | 2 +- tests/ui/try_err.stderr | 4 +- tests/ui/unit_cmp.stderr | 8 ++-- 30 files changed, 126 insertions(+), 130 deletions(-) diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 6ded2f233ef..b7385dcfbca 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -9,7 +9,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{source_map::Span, symbol::Symbol, BytePos}; @@ -432,10 +432,11 @@ fn emit_branches_sharing_code_lint( let mut add_expr_note = false; // Construct suggestions + let sm = cx.sess().source_map(); if start_stmts > 0 { let block = blocks[0]; let span_start = first_line_of_span(cx, if_expr.span).shrink_to_lo(); - let span_end = block.stmts[start_stmts - 1].span.source_callsite(); + let span_end = sm.stmt_span(block.stmts[start_stmts - 1].span, block.span); let cond_span = first_line_of_span(cx, if_expr.span).until(block.span); let cond_snippet = reindent_multiline(snippet(cx, cond_span, "_"), false, None); @@ -454,15 +455,16 @@ fn emit_branches_sharing_code_lint( let span_end = block.span.shrink_to_hi(); let moved_start = if end_stmts == 0 && block.expr.is_some() { - block.expr.unwrap().span + block.expr.unwrap().span.source_callsite() } else { - block.stmts[block.stmts.len() - end_stmts].span - } - .source_callsite(); + sm.stmt_span(block.stmts[block.stmts.len() - end_stmts].span, block.span) + }; let moved_end = block .expr - .map_or_else(|| block.stmts[block.stmts.len() - 1].span, |expr| expr.span) - .source_callsite(); + .map_or_else( + || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span), + |expr| expr.span.source_callsite(), + ); let moved_span = moved_start.to(moved_end); let moved_snipped = reindent_multiline(snippet(cx, moved_span, "_"), true, None); diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8df7f91ce59..37d9ea3bdc1 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -90,12 +90,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { } } -fn span_useless_format(cx: &LateContext<'_>, span: Span, mut sugg: String, mut applicability: Applicability) { - // The callsite span contains the statement semicolon for some reason. - if snippet_with_applicability(cx, span, "..", &mut applicability).ends_with(';') { - sugg.push(';'); - } - +fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) { span_lint_and_sugg( cx, USELESS_FORMAT, diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 5a50cc48d61..7aa93ed7839 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -36,9 +36,8 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::Span; declare_clippy_lint! { @@ -270,7 +269,7 @@ struct LintData<'a> { /// The 0-based index of the `if` statement in the containing loop block. stmt_idx: usize, /// The statements of the loop block. - block_stmts: &'a [ast::Stmt], + loop_block: &'a ast::Block, } const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant"; @@ -343,10 +342,10 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: let indent = span_of_first_expr_in_block(data.if_block) .and_then(|span| indent_of(cx, span)) .unwrap_or(0); - let to_annex = data.block_stmts[data.stmt_idx + 1..] + let to_annex = data.loop_block.stmts[data.stmt_idx + 1..] .iter() - .map(|stmt| original_sp(stmt.span, DUMMY_SP)) - .map(|span| { + .map(|stmt| { + let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span); let snip = snippet_block(cx, span, "..", None).into_owned(); snip.lines() .map(|line| format!("{}{}", " ".repeat(indent), line)) @@ -393,7 +392,7 @@ fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) { if_cond: cond, if_block: then_block, else_expr, - block_stmts: &loop_block.stmts, + loop_block, }; if needless_continue_in_else(else_expr, label) { emit_warning( diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index 87e962b9228..039b23b1bdb 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -82,13 +82,13 @@ error: use of irregular braces for `eprint!` macro --> $DIR/conf_nonstandard_macro_braces.rs:57:5 | LL | eprint!("test if user config overrides defaults"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: consider writing `eprint!["test if user config overrides defaults"];` +help: consider writing `eprint!["test if user config overrides defaults"]` --> $DIR/conf_nonstandard_macro_braces.rs:57:5 | LL | eprint!("test if user config overrides defaults"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/asm_syntax.stderr b/tests/ui/asm_syntax.stderr index e3abbe08658..409f4db76bc 100644 --- a/tests/ui/asm_syntax.stderr +++ b/tests/ui/asm_syntax.stderr @@ -2,7 +2,7 @@ error: Intel x86 assembly syntax used --> $DIR/asm_syntax.rs:9:9 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^^^^^^ | = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` = help: use AT&T x86 assembly syntax @@ -11,7 +11,7 @@ error: Intel x86 assembly syntax used --> $DIR/asm_syntax.rs:10:9 | LL | asm!("", options()); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = help: use AT&T x86 assembly syntax @@ -19,7 +19,7 @@ error: Intel x86 assembly syntax used --> $DIR/asm_syntax.rs:11:9 | LL | asm!("", options(nostack)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use AT&T x86 assembly syntax @@ -27,7 +27,7 @@ error: AT&T x86 assembly syntax used --> $DIR/asm_syntax.rs:23:9 | LL | asm!("", options(att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` = help: use Intel x86 assembly syntax @@ -36,7 +36,7 @@ error: AT&T x86 assembly syntax used --> $DIR/asm_syntax.rs:24:9 | LL | asm!("", options(nostack, att_syntax)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use Intel x86 assembly syntax diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index 1eb87d89fad..4ca1e6f6e88 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -2,7 +2,7 @@ error: `assert!(true)` will be optimized out by the compiler --> $DIR/assertions_on_constants.rs:11:5 | LL | assert!(true); - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: `-D clippy::assertions-on-constants` implied by `-D warnings` = help: remove it @@ -12,7 +12,7 @@ error: `assert!(false)` should probably be replaced --> $DIR/assertions_on_constants.rs:12:5 | LL | assert!(false); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: use `panic!()` or `unreachable!()` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -21,7 +21,7 @@ error: `assert!(true)` will be optimized out by the compiler --> $DIR/assertions_on_constants.rs:13:5 | LL | assert!(true, "true message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: remove it = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -30,7 +30,7 @@ error: `assert!(false, "false message")` should probably be replaced --> $DIR/assertions_on_constants.rs:14:5 | LL | assert!(false, "false message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `panic!("false message")` or `unreachable!("false message")` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -39,7 +39,7 @@ error: `assert!(false, msg.to_uppercase())` should probably be replaced --> $DIR/assertions_on_constants.rs:17:5 | LL | assert!(false, msg.to_uppercase()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -48,7 +48,7 @@ error: `assert!(true)` will be optimized out by the compiler --> $DIR/assertions_on_constants.rs:20:5 | LL | assert!(B); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: remove it = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -57,7 +57,7 @@ error: `assert!(false)` should probably be replaced --> $DIR/assertions_on_constants.rs:23:5 | LL | assert!(C); - | ^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: use `panic!()` or `unreachable!()` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -66,7 +66,7 @@ error: `assert!(false, "C message")` should probably be replaced --> $DIR/assertions_on_constants.rs:24:5 | LL | assert!(C, "C message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `panic!("C message")` or `unreachable!("C message")` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -75,7 +75,7 @@ error: `debug_assert!(true)` will be optimized out by the compiler --> $DIR/assertions_on_constants.rs:26:5 | LL | debug_assert!(true); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = help: remove it = note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/bool_assert_comparison.stderr b/tests/ui/bool_assert_comparison.stderr index da9b56aa779..377d51be4cd 100644 --- a/tests/ui/bool_assert_comparison.stderr +++ b/tests/ui/bool_assert_comparison.stderr @@ -2,7 +2,7 @@ error: used `assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:69:5 | LL | assert_eq!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = note: `-D clippy::bool-assert-comparison` implied by `-D warnings` @@ -10,127 +10,127 @@ error: used `assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:70:5 | LL | assert_eq!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:71:5 | LL | assert_eq!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:76:5 | LL | assert_eq!(b, true); - | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:79:5 | LL | assert_ne!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:80:5 | LL | assert_ne!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:81:5 | LL | assert_ne!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:86:5 | LL | assert_ne!(b, true); - | ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `debug_assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:89:5 | LL | debug_assert_eq!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:90:5 | LL | debug_assert_eq!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:91:5 | LL | debug_assert_eq!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:96:5 | LL | debug_assert_eq!(b, true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:99:5 | LL | debug_assert_ne!("a".is_empty(), false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:100:5 | LL | debug_assert_ne!("".is_empty(), true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:101:5 | LL | debug_assert_ne!(true, "".is_empty()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_ne!` with a literal bool --> $DIR/bool_assert_comparison.rs:106:5 | LL | debug_assert_ne!(b, true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:111:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:112:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:113:5 | LL | assert_eq!(false, "a".is_empty(), "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` error: used `debug_assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:118:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:119:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: used `debug_assert_eq!` with a literal bool --> $DIR/bool_assert_comparison.rs:120:5 | LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)` error: aborting due to 22 previous errors diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index 82f26954380..34131592802 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -71,7 +71,7 @@ LL | $a.unwrap(); // unnecessary | ^^^^^^^^^^^ ... LL | m!(x); - | ------ in this macro invocation + | ----- in this macro invocation | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/collapsible_match2.stderr b/tests/ui/collapsible_match2.stderr index 55e70dce208..46b645aea13 100644 --- a/tests/ui/collapsible_match2.stderr +++ b/tests/ui/collapsible_match2.stderr @@ -46,7 +46,7 @@ LL | | }, | |_____________________^ ... LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); - | ------------------------------------------------- in this macro invocation + | ------------------------------------------------ in this macro invocation | help: the outer pattern can be modified to include the inner pattern --> $DIR/collapsible_match2.rs:46:28 diff --git a/tests/ui/crashes/ice-6255.stderr b/tests/ui/crashes/ice-6255.stderr index 5dbf9d440dd..db0cb25e34a 100644 --- a/tests/ui/crashes/ice-6255.stderr +++ b/tests/ui/crashes/ice-6255.stderr @@ -5,7 +5,7 @@ LL | extern crate std as core; | ^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | define_other_core!(); - | --------------------- in this macro invocation + | -------------------- in this macro invocation | = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index 7c9d705fa98..fd0689dfc4c 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -31,7 +31,7 @@ LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ ... LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - | ------------------------------------------ in this macro invocation + | ----------------------------------------- in this macro invocation | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr index bed385b5273..7debe059ff4 100644 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -13,7 +13,7 @@ LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ ... LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable - | ----------------------------------------------------------- in this macro invocation + | ---------------------------------------------------------- in this macro invocation | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/default_numeric_fallback_f64.stderr b/tests/ui/default_numeric_fallback_f64.stderr index 961c7cb57c5..f8a2407b693 100644 --- a/tests/ui/default_numeric_fallback_f64.stderr +++ b/tests/ui/default_numeric_fallback_f64.stderr @@ -139,7 +139,7 @@ LL | let x = 22.; | ^^^ help: consider adding suffix: `22.0_f64` ... LL | internal_macro!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/default_numeric_fallback_i32.stderr b/tests/ui/default_numeric_fallback_i32.stderr index 5edf48b2020..6f9e124704b 100644 --- a/tests/ui/default_numeric_fallback_i32.stderr +++ b/tests/ui/default_numeric_fallback_i32.stderr @@ -151,7 +151,7 @@ LL | let x = 22; | ^^ help: consider adding suffix: `22_i32` ... LL | internal_macro!(); - | ------------------ in this macro invocation + | ----------------- in this macro invocation | = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/doc_unsafe.stderr b/tests/ui/doc_unsafe.stderr index 34ca37a6efd..d68b8a0c67b 100644 --- a/tests/ui/doc_unsafe.stderr +++ b/tests/ui/doc_unsafe.stderr @@ -47,7 +47,7 @@ LL | | } | |_________^ ... LL | very_unsafe!(); - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: this error originates in the macro `very_unsafe` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/eq_op_macros.stderr b/tests/ui/eq_op_macros.stderr index a28961e7568..885415b42c7 100644 --- a/tests/ui/eq_op_macros.stderr +++ b/tests/ui/eq_op_macros.stderr @@ -5,7 +5,7 @@ LL | assert_eq!(a, a); | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: `-D clippy::eq-op` implied by `-D warnings` = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -17,7 +17,7 @@ LL | assert_ne!(a, a); | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -52,7 +52,7 @@ LL | debug_assert_eq!(a, a); | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -63,7 +63,7 @@ LL | debug_assert_ne!(a, a); | ^^^^ ... LL | assert_in_macro_def!(); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index 8b8054586e6..f5d0b98c108 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -37,7 +37,7 @@ note: potential failure(s) --> $DIR/fallible_impl_from.rs:30:13 | LL | panic!(); - | ^^^^^^^^^ + | ^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead @@ -60,11 +60,11 @@ LL | let s = s.unwrap(); | ^^^^^^^^^^ LL | if !s.is_empty() { LL | panic!("42"); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ LL | } else if s.parse::().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead @@ -86,7 +86,7 @@ note: potential failure(s) LL | if s.parse::().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 496a083497d..701399b32d6 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -2,7 +2,7 @@ error: useless use of `format!` --> $DIR/format.rs:13:5 | LL | format!("foo"); - | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` | = note: `-D clippy::useless-format` implied by `-D warnings` @@ -10,13 +10,13 @@ error: useless use of `format!` --> $DIR/format.rs:14:5 | LL | format!("{{}}"); - | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string();` + | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` --> $DIR/format.rs:15:5 | LL | format!("{{}} abc {{}}"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` --> $DIR/format.rs:16:5 @@ -25,61 +25,61 @@ LL | / format!( LL | | r##"foo {{}} LL | | " bar"## LL | | ); - | |______^ + | |_____^ | help: consider using `.to_string()` | LL ~ r##"foo {} -LL + " bar"##.to_string(); +LL ~ " bar"##.to_string(); | error: useless use of `format!` --> $DIR/format.rs:21:5 | LL | format!("{}", "foo"); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` --> $DIR/format.rs:25:5 | LL | format!("{:+}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` --> $DIR/format.rs:26:5 | LL | format!("{:<}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` --> $DIR/format.rs:31:5 | LL | format!("{}", arg); - | ^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();` + | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` --> $DIR/format.rs:35:5 | LL | format!("{:+}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` --> $DIR/format.rs:36:5 | LL | format!("{:<}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string();` + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` --> $DIR/format.rs:63:5 | LL | format!("{}", 42.to_string()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` --> $DIR/format.rs:65:5 | LL | format!("{}", x.display().to_string()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string();` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` --> $DIR/format.rs:69:18 diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index dad5ab71f15..3f5f56b923f 100644 --- a/tests/ui/implicit_hasher.stderr +++ b/tests/ui/implicit_hasher.stderr @@ -107,7 +107,7 @@ LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ ... LL | gen!(impl); - | ----------- in this macro invocation + | ---------- in this macro invocation | = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter @@ -126,7 +126,7 @@ LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) | ^^^^^^^^^^^^^^^^^ ... LL | gen!(fn bar); - | ------------- in this macro invocation + | ------------ in this macro invocation | = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter @@ -141,7 +141,7 @@ LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) | ^^^^^^^^^^^^ ... LL | gen!(fn bar); - | ------------- in this macro invocation + | ------------ in this macro invocation | = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider adding a type parameter diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/item_after_statement.stderr index bcb163d4bc1..ab4a6374c73 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/item_after_statement.stderr @@ -25,7 +25,7 @@ LL | | } | |_____________^ ... LL | b!(); - | ----- in this macro invocation + | ---- in this macro invocation | = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/mem_replace_macro.stderr b/tests/ui/mem_replace_macro.stderr index b4963acc455..dd69ab8b5ef 100644 --- a/tests/ui/mem_replace_macro.stderr +++ b/tests/ui/mem_replace_macro.stderr @@ -5,7 +5,7 @@ LL | std::mem::replace($s, Default::default()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | take!(s); - | --------- in this macro invocation + | -------- in this macro invocation | = note: `-D clippy::mem-replace-with-default` implied by `-D warnings` = note: this error originates in the macro `take` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/missing_panics_doc.stderr b/tests/ui/missing_panics_doc.stderr index 8d882cc6e0d..b863063b626 100644 --- a/tests/ui/missing_panics_doc.stderr +++ b/tests/ui/missing_panics_doc.stderr @@ -91,7 +91,7 @@ note: first possible panic found here --> $DIR/missing_panics_doc.rs:39:5 | LL | assert_eq!(x, 0); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section @@ -107,7 +107,7 @@ note: first possible panic found here --> $DIR/missing_panics_doc.rs:45:5 | LL | assert_ne!(x, 0); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 7 previous errors diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index 8d6e40c30a1..f56c2d03c66 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -13,7 +13,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:9:9 | LL | panic!("error"); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -30,7 +30,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:14:9 | LL | unimplemented!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -47,7 +47,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:19:9 | LL | unreachable!(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -64,7 +64,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:24:9 | LL | todo!("Finish this"); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -81,7 +81,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:55:5 | LL | panic!("error"); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -98,7 +98,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn.rs:69:5 | LL | todo!("finish main method"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 6 previous errors diff --git a/tests/ui/panic_in_result_fn_assertions.stderr b/tests/ui/panic_in_result_fn_assertions.stderr index 4c39b37d879..7501d6d85ed 100644 --- a/tests/ui/panic_in_result_fn_assertions.stderr +++ b/tests/ui/panic_in_result_fn_assertions.stderr @@ -14,7 +14,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn_assertions.rs:9:9 | LL | assert!(x == 5, "wrong argument"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -32,7 +32,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn_assertions.rs:15:9 | LL | assert_eq!(x, 5); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` @@ -50,7 +50,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn_assertions.rs:21:9 | LL | assert_ne!(x, 1); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr index 2e83c305a67..2b607ff5888 100644 --- a/tests/ui/panicking_macros.stderr +++ b/tests/ui/panicking_macros.stderr @@ -2,7 +2,7 @@ error: `panic` should not be present in production code --> $DIR/panicking_macros.rs:8:5 | LL | panic!(); - | ^^^^^^^^^ + | ^^^^^^^^ | = note: `-D clippy::panic` implied by `-D warnings` @@ -10,19 +10,19 @@ error: `panic` should not be present in production code --> $DIR/panicking_macros.rs:9:5 | LL | panic!("message"); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code --> $DIR/panicking_macros.rs:10:5 | LL | panic!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:16:5 | LL | todo!(); - | ^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::todo` implied by `-D warnings` = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -31,7 +31,7 @@ error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:17:5 | LL | todo!("message"); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -39,7 +39,7 @@ error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:18:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -47,7 +47,7 @@ error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:24:5 | LL | unimplemented!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: `-D clippy::unimplemented` implied by `-D warnings` = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -56,7 +56,7 @@ error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:25:5 | LL | unimplemented!("message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -64,7 +64,7 @@ error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:26:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -72,7 +72,7 @@ error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:32:5 | LL | unreachable!(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = note: `-D clippy::unreachable` implied by `-D warnings` = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -81,7 +81,7 @@ error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:33:5 | LL | unreachable!("message"); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `$crate::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -89,7 +89,7 @@ error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:34:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -97,13 +97,13 @@ error: `panic` should not be present in production code --> $DIR/panicking_macros.rs:40:5 | LL | panic!(); - | ^^^^^^^^^ + | ^^^^^^^^ error: `todo` should not be present in production code --> $DIR/panicking_macros.rs:41:5 | LL | todo!(); - | ^^^^^^^^ + | ^^^^^^^ | = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -111,7 +111,7 @@ error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:42:5 | LL | unimplemented!(); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -119,7 +119,7 @@ error: usage of the `unreachable!` macro --> $DIR/panicking_macros.rs:43:5 | LL | unreachable!(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/pattern_type_mismatch/syntax.stderr b/tests/ui/pattern_type_mismatch/syntax.stderr index f309b273982..12b3d3a8bd0 100644 --- a/tests/ui/pattern_type_mismatch/syntax.stderr +++ b/tests/ui/pattern_type_mismatch/syntax.stderr @@ -70,7 +70,7 @@ LL | Some(_) => (), | ^^^^^^^ ... LL | matching_macro!(value); - | ----------------------- in this macro invocation + | ---------------------- in this macro invocation | = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings = note: this error originates in the macro `matching_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index 48e7d9ddd5a..9c853020ab0 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -37,7 +37,7 @@ LL | let ref _y = 42; | ----^^^^^^------ help: try: `let _y = &42;` ... LL | gen_binding!(); - | --------------- in this macro invocation + | -------------- in this macro invocation | = note: this error originates in the macro `gen_binding` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/tests/ui/toplevel_ref_arg_non_rustfix.stderr index 31f8c103ede..e97011c7fd5 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -13,7 +13,7 @@ LL | fn fun_example(ref _x: usize) {} | ^^^^^^ ... LL | gen_function!(); - | ---------------- in this macro invocation + | --------------- in this macro invocation | = note: this error originates in the macro `gen_function` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 09efc16c154..0cb1328fbfc 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -35,7 +35,7 @@ LL | Err(_) => Err(1)?, | ^^^^^^^ help: try this: `return Err(1)` ... LL | try_validation!(Ok::<_, i32>(5)); - | --------------------------------- in this macro invocation + | -------------------------------- in this macro invocation | = note: this error originates in the macro `try_validation` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -46,7 +46,7 @@ LL | Err(_) => Err(ret_one!())?, | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` ... LL | try_validation_in_macro!(Ok::<_, i32>(5)); - | ------------------------------------------ in this macro invocation + | ----------------------------------------- in this macro invocation | = note: this error originates in the macro `try_validation_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index 75017cab057..2b5a7b348b9 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -32,7 +32,7 @@ LL | | }, ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -46,7 +46,7 @@ LL | | }, ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `$crate::assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -60,7 +60,7 @@ LL | | }, ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -74,7 +74,7 @@ LL | | }, ... | LL | | } LL | | ); - | |______^ + | |_____^ | = note: this error originates in the macro `$crate::assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) From ec5071931eb68a981d14eefd7f6c39bb16c59596 Mon Sep 17 00:00:00 2001 From: dswij Date: Fri, 15 Oct 2021 18:00:02 +0800 Subject: [PATCH 041/100] `unnecessary_sort_by` only warns if argument impl `Ord` trait --- clippy_lints/src/unnecessary_sort_by.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index dd74bf367f3..26b56e0f2f3 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; @@ -193,10 +193,15 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); let unstable = name == "sort_unstable_by"; + if_chain! { if let ExprKind::Path(QPath::Resolved(_, Path { segments: [PathSegment { ident: left_name, .. }], .. - })) = &left_expr.kind { - if left_name == left_ident { + })) = &left_expr.kind; + if left_name == left_ident; + if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) + }); + then { return Some(LintTrigger::Sort(SortDetection { vec_name, unstable })); } } From e4ac4c2e1a162eedd2f5ec1737fc3260a97268a2 Mon Sep 17 00:00:00 2001 From: dswij Date: Fri, 15 Oct 2021 18:06:02 +0800 Subject: [PATCH 042/100] Add test on `unnecessary_sort_by` when argument does not implement `Ord` --- tests/ui/unnecessary_sort_by.fixed | 5 +++++ tests/ui/unnecessary_sort_by.rs | 5 +++++ tests/ui/unnecessary_sort_by.stderr | 24 ++++++++++++------------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index b45b27d8f23..d806d620b17 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -2,6 +2,7 @@ #![allow(clippy::stable_sort_primitive)] +use std::cell::Ref; use std::cmp::Reverse; fn unnecessary_sort_by() { @@ -33,6 +34,10 @@ fn unnecessary_sort_by() { // `Reverse(b)` would borrow in the following cases, don't lint vec.sort_by(|a, b| b.cmp(a)); vec.sort_unstable_by(|a, b| b.cmp(a)); + + // No warning if element does not implement `Ord` + let mut vec: Vec> = Vec::new(); + vec.sort_unstable_by(|a, b| a.cmp(b)); } // Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index be2abe7f701..6ee9c3af455 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -2,6 +2,7 @@ #![allow(clippy::stable_sort_primitive)] +use std::cell::Ref; use std::cmp::Reverse; fn unnecessary_sort_by() { @@ -33,6 +34,10 @@ fn id(x: isize) -> isize { // `Reverse(b)` would borrow in the following cases, don't lint vec.sort_by(|a, b| b.cmp(a)); vec.sort_unstable_by(|a, b| b.cmp(a)); + + // No warning if element does not implement `Ord` + let mut vec: Vec> = Vec::new(); + vec.sort_unstable_by(|a, b| a.cmp(b)); } // Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key` diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index 50607933e18..ca9641e8803 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -1,5 +1,5 @@ error: use Vec::sort here instead - --> $DIR/unnecessary_sort_by.rs:14:5 + --> $DIR/unnecessary_sort_by.rs:15:5 | LL | vec.sort_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()` @@ -7,67 +7,67 @@ LL | vec.sort_by(|a, b| a.cmp(b)); = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` error: use Vec::sort here instead - --> $DIR/unnecessary_sort_by.rs:15:5 + --> $DIR/unnecessary_sort_by.rs:16:5 | LL | vec.sort_unstable_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:16:5 + --> $DIR/unnecessary_sort_by.rs:17:5 | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:17:5 + --> $DIR/unnecessary_sort_by.rs:18:5 | LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:20:5 + --> $DIR/unnecessary_sort_by.rs:21:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| Reverse((b + 5).abs()))` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:21:5 + --> $DIR/unnecessary_sort_by.rs:22:5 | LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| Reverse(id(-b)))` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:31:5 + --> $DIR/unnecessary_sort_by.rs:32:5 | LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:32:5 + --> $DIR/unnecessary_sort_by.rs:33:5 | LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:88:9 + --> $DIR/unnecessary_sort_by.rs:93:9 | LL | args.sort_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:89:9 + --> $DIR/unnecessary_sort_by.rs:94:9 | LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:91:9 + --> $DIR/unnecessary_sort_by.rs:96:9 | LL | args.sort_by(|a, b| b.name().cmp(&a.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| Reverse(b.name()))` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:92:9 + --> $DIR/unnecessary_sort_by.rs:97:9 | LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| Reverse(b.name()))` From c9599d79a3b741b7c42353dc45eab6f1c461891f Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Thu, 30 Sep 2021 07:45:03 -0400 Subject: [PATCH 043/100] Add `format_in_format_args` and `to_string_in_format_args` lints Fixes #7667 and #7729 --- CHANGELOG.md | 2 + clippy_lints/src/format.rs | 51 +----- clippy_lints/src/format_args.rs | 223 +++++++++++++++++++++++++ clippy_lints/src/lib.register_all.rs | 2 + clippy_lints/src/lib.register_lints.rs | 2 + clippy_lints/src/lib.register_perf.rs | 2 + clippy_lints/src/lib.rs | 2 + clippy_utils/src/higher.rs | 102 ++++++++++- clippy_utils/src/paths.rs | 20 +++ tests/ui/format_args.fixed | 105 ++++++++++++ tests/ui/format_args.rs | 105 ++++++++++++ tests/ui/format_args.stderr | 106 ++++++++++++ tests/ui/format_args_unfixable.rs | 60 +++++++ tests/ui/format_args_unfixable.stderr | 175 +++++++++++++++++++ 14 files changed, 908 insertions(+), 49 deletions(-) create mode 100644 clippy_lints/src/format_args.rs create mode 100644 tests/ui/format_args.fixed create mode 100644 tests/ui/format_args.rs create mode 100644 tests/ui/format_args.stderr create mode 100644 tests/ui/format_args_unfixable.rs create mode 100644 tests/ui/format_args_unfixable.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e837d363a..f6a883311c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2736,6 +2736,7 @@ Released 2018-09-13 [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref +[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args [`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect [`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into [`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10 @@ -3015,6 +3016,7 @@ Released 2018-09-13 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display +[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 8df7f91ce59..472db6f5731 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::FormatExpn; -use clippy_utils::last_path_segment; use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, QPath}; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -69,8 +68,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { ty::Str => true, _ => false, }; - if format_args.args.iter().all(is_display_arg); - if format_args.fmt_expr.map_or(true, check_unformatted); + if let Some(args) = format_args.args(); + if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting()); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, @@ -106,47 +105,3 @@ fn span_useless_format(cx: &LateContext<'_>, span: Span, mut sugg: String, mut a applicability, ); } - -fn is_display_arg(expr: &Expr<'_>) -> bool { - if_chain! { - if let ExprKind::Call(_, [_, fmt]) = expr.kind; - if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind; - if let [.., t, _] = path.segments; - if t.ident.name == sym::Display; - then { true } else { false } - } -} - -/// Checks if the expression matches -/// ```rust,ignore -/// &[_ { -/// format: _ { -/// width: _::Implied, -/// precision: _::Implied, -/// ... -/// }, -/// ..., -/// }] -/// ``` -fn check_unformatted(expr: &Expr<'_>) -> bool { - if_chain! { - if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind; - if let ExprKind::Array([expr]) = expr.kind; - // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = expr.kind; - if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); - // struct `core::fmt::rt::v1::FormatSpec` - if let ExprKind::Struct(_, fields, _) = format_field.expr.kind; - if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision); - if let ExprKind::Path(ref precision_path) = precision_field.expr.kind; - if last_path_segment(precision_path).ident.name == sym::Implied; - if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width); - if let ExprKind::Path(ref width_qpath) = width_field.expr.kind; - if last_path_segment(width_qpath).ident.name == sym::Implied; - then { - return true; - } - } - - false -} diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs new file mode 100644 index 00000000000..8b27442aa94 --- /dev/null +++ b/clippy_lints/src/format_args.rs @@ -0,0 +1,223 @@ +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn}; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::implements_trait; +use clippy_utils::{is_diag_trait_item, match_def_path, paths}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; +use rustc_middle::ty::Ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Detects `format!` within the arguments of another macro that does + /// formatting such as `format!` itself, `write!` or `println!`. Suggests + /// inlining the `format!` call. + /// + /// ### Why is this bad? + /// The recommended code is both shorter and avoids a temporary allocation. + /// + /// ### Example + /// ```rust + /// # use std::panic::Location; + /// println!("error: {}", format!("something failed at {}", Location::caller())); + /// ``` + /// Use instead: + /// ```rust + /// # use std::panic::Location; + /// println!("error: something failed at {}", Location::caller()); + /// ``` + pub FORMAT_IN_FORMAT_ARGS, + perf, + "`format!` used in a macro that does formatting" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string) + /// applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) + /// in a macro that does formatting. + /// + /// ### Why is this bad? + /// Since the type implements `Display`, the use of `to_string` is + /// unnecessary. + /// + /// ### Example + /// ```rust + /// # use std::panic::Location; + /// println!("error: something failed at {}", Location::caller().to_string()); + /// ``` + /// Use instead: + /// ```rust + /// # use std::panic::Location; + /// println!("error: something failed at {}", Location::caller()); + /// ``` + pub TO_STRING_IN_FORMAT_ARGS, + perf, + "`to_string` applied to a type that implements `Display` in format args" +} + +declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]); + +const FORMAT_MACRO_PATHS: &[&[&str]] = &[ + &paths::FORMAT_ARGS_MACRO, + &paths::ASSERT_EQ_MACRO, + &paths::ASSERT_MACRO, + &paths::ASSERT_NE_MACRO, + &paths::EPRINT_MACRO, + &paths::EPRINTLN_MACRO, + &paths::PRINT_MACRO, + &paths::PRINTLN_MACRO, + &paths::WRITE_MACRO, + &paths::WRITELN_MACRO, +]; + +const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_macro]; + +impl<'tcx> LateLintPass<'tcx> for FormatArgs { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if let Some(format_args) = FormatArgsExpn::parse(expr); + let expr_expn_data = expr.span.ctxt().outer_expn_data(); + let outermost_expn_data = outermost_expn_data(expr_expn_data); + if let Some(macro_def_id) = outermost_expn_data.macro_def_id; + if FORMAT_MACRO_PATHS + .iter() + .any(|path| match_def_path(cx, macro_def_id, path)) + || FORMAT_MACRO_DIAG_ITEMS + .iter() + .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, macro_def_id)); + if let ExpnKind::Macro(_, name) = outermost_expn_data.kind; + if let Some(args) = format_args.args(); + then { + for (i, arg) in args.iter().enumerate() { + if !arg.is_display() { + continue; + } + if arg.has_string_formatting() { + continue; + } + if is_aliased(&args, i) { + continue; + } + check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg); + check_to_string_in_format_args(cx, name, arg); + } + } + } + } +} + +fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { + if expn_data.call_site.from_expansion() { + outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data()) + } else { + expn_data + } +} + +fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) { + if_chain! { + if FormatExpn::parse(arg.value).is_some(); + if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion(); + then { + span_lint_and_then( + cx, + FORMAT_IN_FORMAT_ARGS, + trim_semicolon(cx, call_site), + &format!("`format!` in `{}!` args", name), + |diag| { + diag.help(&format!( + "combine the `format!(..)` arguments with the outer `{}!(..)` call", + name + )); + diag.help("or consider changing `format!` to `format_args!`"); + }, + ); + } + } +} + +fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) { + let value = arg.value; + if_chain! { + if !value.span.from_expansion(); + if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind; + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id); + if is_diag_trait_item(cx, method_def_id, sym::ToString); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display); + if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); + then { + let (n_needed_derefs, target) = count_needed_derefs( + receiver_ty, + cx.typeck_results().expr_adjustments(receiver).iter(), + ); + if implements_trait(cx, target, display_trait_id, &[]) { + if n_needed_derefs == 0 { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + value.span.with_lo(receiver.span.hi()), + &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name), + "remove this", + String::new(), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + value.span, + &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name), + "use this", + format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs), + Applicability::MachineApplicable, + ); + } + } + } + } +} + +// Returns true if `args[i]` "refers to" or "is referred to by" another argument. +fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool { + let value = args[i].value; + args.iter() + .enumerate() + .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value)) +} + +fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span { + snippet_opt(cx, span).map_or(span, |snippet| { + let snippet = snippet.trim_end_matches(';'); + span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap())) + }) +} + +fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) +where + I: Iterator>, +{ + let mut n_total = 0; + let mut n_needed = 0; + loop { + if let Some(Adjustment { + kind: Adjust::Deref(overloaded_deref), + target, + }) = iter.next() + { + n_total += 1; + if overloaded_deref.is_some() { + n_needed = n_total; + } + ty = target; + } else { + return (n_needed, ty); + } + } +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 7c8733f9022..4c2dfbd1d84 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -60,6 +60,8 @@ LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(float_literal::EXCESSIVE_PRECISION), LintId::of(format::USELESS_FORMAT), + LintId::of(format_args::FORMAT_IN_FORMAT_ARGS), + LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS), LintId::of(formatting::POSSIBLE_MISSING_COMMA), LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 7d81fafe4c9..f334f723f6b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -139,6 +139,8 @@ floating_point_arithmetic::IMPRECISE_FLOPS, floating_point_arithmetic::SUBOPTIMAL_FLOPS, format::USELESS_FORMAT, + format_args::FORMAT_IN_FORMAT_ARGS, + format_args::TO_STRING_IN_FORMAT_ARGS, formatting::POSSIBLE_MISSING_COMMA, formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, formatting::SUSPICIOUS_ELSE_FORMATTING, diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index 5432345760b..a0d5cf9418e 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -5,6 +5,8 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(entry::MAP_ENTRY), LintId::of(escape::BOXED_LOCAL), + LintId::of(format_args::FORMAT_IN_FORMAT_ARGS), + LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS), LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(loops::MANUAL_MEMCPY), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6ab59b1b12f..9794d74e198 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -218,6 +218,7 @@ macro_rules! declare_clippy_lint { mod float_literal; mod floating_point_arithmetic; mod format; +mod format_args; mod formatting; mod from_over_into; mod from_str_radix_10; @@ -775,6 +776,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send))); store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); + store.register_late_pass(move || Box::new(format_args::FormatArgs)); } #[rustfmt::skip] diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 1ff282de950..fb4d53e2845 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -3,7 +3,7 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::ty::is_type_diagnostic_item; -use crate::{is_expn_of, match_def_path, paths}; +use crate::{is_expn_of, last_path_segment, match_def_path, paths}; use if_chain::if_chain; use rustc_ast::ast::{self, LitKind}; use rustc_hir as hir; @@ -572,6 +572,106 @@ pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { } } } + + /// Returns a vector of `FormatArgsArg`. + pub fn args(&self) -> Option>> { + if let Some(expr) = self.fmt_expr { + if_chain! { + if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind; + if let ExprKind::Array(exprs) = expr.kind; + then { + exprs.iter().map(|fmt| { + if_chain! { + // struct `core::fmt::rt::v1::Argument` + if let ExprKind::Struct(_, fields, _) = fmt.kind; + if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position); + if let ExprKind::Lit(lit) = &position_field.expr.kind; + if let LitKind::Int(position, _) = lit.node; + then { + let i = usize::try_from(position).unwrap(); + Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) }) + } else { + None + } + } + }).collect() + } else { + None + } + } + } else { + Some( + self.value_args + .iter() + .zip(self.args.iter()) + .map(|(value, arg)| FormatArgsArg { value, arg, fmt: None }) + .collect(), + ) + } + } +} + +/// Type representing a `FormatArgsExpn`'s format arguments +pub struct FormatArgsArg<'tcx> { + /// An element of `value_args` according to `position` + pub value: &'tcx Expr<'tcx>, + /// An element of `args` according to `position` + pub arg: &'tcx Expr<'tcx>, + /// An element of `fmt_expn` + pub fmt: Option<&'tcx Expr<'tcx>>, +} + +impl<'tcx> FormatArgsArg<'tcx> { + /// Returns true if any formatting parameters are used that would have an effect on strings, + /// like `{:+2}` instead of just `{}`. + pub fn has_string_formatting(&self) -> bool { + self.fmt.map_or(false, |fmt| { + // `!` because these conditions check that `self` is unformatted. + !if_chain! { + // struct `core::fmt::rt::v1::Argument` + if let ExprKind::Struct(_, fields, _) = fmt.kind; + if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); + // struct `core::fmt::rt::v1::FormatSpec` + if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind; + let mut precision_found = false; + let mut width_found = false; + if subfields.iter().all(|field| { + match field.ident.name { + sym::precision => { + precision_found = true; + if let ExprKind::Path(ref precision_path) = field.expr.kind { + last_path_segment(precision_path).ident.name == sym::Implied + } else { + false + } + } + sym::width => { + width_found = true; + if let ExprKind::Path(ref width_qpath) = field.expr.kind { + last_path_segment(width_qpath).ident.name == sym::Implied + } else { + false + } + } + _ => true, + } + }); + if precision_found && width_found; + then { true } else { false } + } + }) + } + + /// Returns true if the argument is formatted using `Display::fmt`. + pub fn is_display(&self) -> bool { + if_chain! { + if let ExprKind::Call(_, [_, format_field]) = self.arg.kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = format_field.kind; + if let [.., t, _] = path.segments; + if t.ident.name == sym::Display; + then { true } else { false } + } + } } /// Checks if a `let` statement is from a `for` loop desugaring. diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e43c5756021..7c61288f661 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -17,6 +17,12 @@ #[cfg(feature = "metadata-collector-lint")] pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"]; pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const ASSERT_EQ_MACRO: [&str; 3] = ["core", "macros", "assert_eq"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const ASSERT_MACRO: [&str; 4] = ["core", "macros", "builtin", "assert"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const ASSERT_NE_MACRO: [&str; 3] = ["core", "macros", "assert_ne"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; @@ -42,11 +48,17 @@ pub const DURATION: [&str; 3] = ["core", "time", "Duration"]; #[cfg(feature = "internal-lints")] pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const EPRINT_MACRO: [&str; 3] = ["std", "macros", "eprint"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const EPRINTLN_MACRO: [&str; 3] = ["std", "macros", "eprintln"]; pub const EXIT: [&str; 3] = ["std", "process", "exit"]; pub const F32_EPSILON: [&str; 4] = ["core", "f32", "", "EPSILON"]; pub const F64_EPSILON: [&str; 4] = ["core", "f64", "", "EPSILON"]; pub const FILE: [&str; 3] = ["std", "fs", "File"]; pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const FORMAT_ARGS_MACRO: [&str; 4] = ["core", "macros", "builtin", "format_args"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; @@ -109,6 +121,10 @@ pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"]; pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"]; pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const PRINT_MACRO: [&str; 3] = ["std", "macros", "print"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const PRINTLN_MACRO: [&str; 3] = ["std", "macros", "println"]; pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"]; pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"]; @@ -185,3 +201,7 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"]; +#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros +pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"]; diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed new file mode 100644 index 00000000000..8376566c4d6 --- /dev/null +++ b/tests/ui/format_args.fixed @@ -0,0 +1,105 @@ +// run-rustfix + +#![allow(unreachable_code)] +#![allow(unused_macros)] +#![allow(unused_variables)] +#![allow(clippy::assertions_on_constants)] +#![allow(clippy::eq_op)] +#![warn(clippy::to_string_in_format_args)] + +use std::io::{stdout, Write}; +use std::ops::Deref; +use std::panic::Location; + +struct Somewhere; + +impl ToString for Somewhere { + fn to_string(&self) -> String { + String::from("somewhere") + } +} + +struct X(u32); + +impl Deref for X { + type Target = u32; + + fn deref(&self) -> &u32 { + &self.0 + } +} + +struct Y<'a>(&'a X); + +impl<'a> Deref for Y<'a> { + type Target = &'a X; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +struct Z(u32); + +impl Deref for Z { + type Target = u32; + + fn deref(&self) -> &u32 { + &self.0 + } +} + +impl std::fmt::Display for Z { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Z") + } +} + +macro_rules! my_macro { + () => { + // here be dragons, do not enter (or lint) + println!("error: something failed at {}", Location::caller().to_string()); + }; +} + +macro_rules! my_other_macro { + () => { + Location::caller().to_string() + }; +} + +fn main() { + let x = &X(1); + let x_ref = &x; + + let _ = format!("error: something failed at {}", Location::caller()); + let _ = write!( + stdout(), + "error: something failed at {}", + Location::caller() + ); + let _ = writeln!( + stdout(), + "error: something failed at {}", + Location::caller() + ); + print!("error: something failed at {}", Location::caller()); + println!("error: something failed at {}", Location::caller()); + eprint!("error: something failed at {}", Location::caller()); + eprintln!("error: something failed at {}", Location::caller()); + let _ = format_args!("error: something failed at {}", Location::caller()); + assert!(true, "error: something failed at {}", Location::caller()); + assert_eq!(0, 0, "error: something failed at {}", Location::caller()); + assert_ne!(0, 0, "error: something failed at {}", Location::caller()); + panic!("error: something failed at {}", Location::caller()); + println!("{}", *X(1)); + println!("{}", ***Y(&X(1))); + println!("{}", Z(1)); + println!("{}", **x); + println!("{}", ***x_ref); + + println!("error: something failed at {}", Somewhere.to_string()); + println!("{} and again {0}", x.to_string()); + my_macro!(); + println!("error: something failed at {}", my_other_macro!()); +} diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs new file mode 100644 index 00000000000..164cc07066d --- /dev/null +++ b/tests/ui/format_args.rs @@ -0,0 +1,105 @@ +// run-rustfix + +#![allow(unreachable_code)] +#![allow(unused_macros)] +#![allow(unused_variables)] +#![allow(clippy::assertions_on_constants)] +#![allow(clippy::eq_op)] +#![warn(clippy::to_string_in_format_args)] + +use std::io::{stdout, Write}; +use std::ops::Deref; +use std::panic::Location; + +struct Somewhere; + +impl ToString for Somewhere { + fn to_string(&self) -> String { + String::from("somewhere") + } +} + +struct X(u32); + +impl Deref for X { + type Target = u32; + + fn deref(&self) -> &u32 { + &self.0 + } +} + +struct Y<'a>(&'a X); + +impl<'a> Deref for Y<'a> { + type Target = &'a X; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +struct Z(u32); + +impl Deref for Z { + type Target = u32; + + fn deref(&self) -> &u32 { + &self.0 + } +} + +impl std::fmt::Display for Z { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Z") + } +} + +macro_rules! my_macro { + () => { + // here be dragons, do not enter (or lint) + println!("error: something failed at {}", Location::caller().to_string()); + }; +} + +macro_rules! my_other_macro { + () => { + Location::caller().to_string() + }; +} + +fn main() { + let x = &X(1); + let x_ref = &x; + + let _ = format!("error: something failed at {}", Location::caller().to_string()); + let _ = write!( + stdout(), + "error: something failed at {}", + Location::caller().to_string() + ); + let _ = writeln!( + stdout(), + "error: something failed at {}", + Location::caller().to_string() + ); + print!("error: something failed at {}", Location::caller().to_string()); + println!("error: something failed at {}", Location::caller().to_string()); + eprint!("error: something failed at {}", Location::caller().to_string()); + eprintln!("error: something failed at {}", Location::caller().to_string()); + let _ = format_args!("error: something failed at {}", Location::caller().to_string()); + assert!(true, "error: something failed at {}", Location::caller().to_string()); + assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); + assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); + panic!("error: something failed at {}", Location::caller().to_string()); + println!("{}", X(1).to_string()); + println!("{}", Y(&X(1)).to_string()); + println!("{}", Z(1).to_string()); + println!("{}", x.to_string()); + println!("{}", x_ref.to_string()); + + println!("error: something failed at {}", Somewhere.to_string()); + println!("{} and again {0}", x.to_string()); + my_macro!(); + println!("error: something failed at {}", my_other_macro!()); +} diff --git a/tests/ui/format_args.stderr b/tests/ui/format_args.stderr new file mode 100644 index 00000000000..9cfc97edeaf --- /dev/null +++ b/tests/ui/format_args.stderr @@ -0,0 +1,106 @@ +error: `to_string` applied to a type that implements `Display` in `format!` args + --> $DIR/format_args.rs:75:72 + | +LL | let _ = format!("error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + | + = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` + +error: `to_string` applied to a type that implements `Display` in `write!` args + --> $DIR/format_args.rs:79:27 + | +LL | Location::caller().to_string() + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `writeln!` args + --> $DIR/format_args.rs:84:27 + | +LL | Location::caller().to_string() + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `print!` args + --> $DIR/format_args.rs:86:63 + | +LL | print!("error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:87:65 + | +LL | println!("error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `eprint!` args + --> $DIR/format_args.rs:88:64 + | +LL | eprint!("error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `eprintln!` args + --> $DIR/format_args.rs:89:66 + | +LL | eprintln!("error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `format_args!` args + --> $DIR/format_args.rs:90:77 + | +LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `assert!` args + --> $DIR/format_args.rs:91:70 + | +LL | assert!(true, "error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `assert_eq!` args + --> $DIR/format_args.rs:92:73 + | +LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `assert_ne!` args + --> $DIR/format_args.rs:93:73 + | +LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `panic!` args + --> $DIR/format_args.rs:94:63 + | +LL | panic!("error: something failed at {}", Location::caller().to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:95:20 + | +LL | println!("{}", X(1).to_string()); + | ^^^^^^^^^^^^^^^^ help: use this: `*X(1)` + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:96:20 + | +LL | println!("{}", Y(&X(1)).to_string()); + | ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))` + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:97:24 + | +LL | println!("{}", Z(1).to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:98:20 + | +LL | println!("{}", x.to_string()); + | ^^^^^^^^^^^^^ help: use this: `**x` + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:99:20 + | +LL | println!("{}", x_ref.to_string()); + | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref` + +error: aborting due to 17 previous errors + diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs new file mode 100644 index 00000000000..a8c06c2bde6 --- /dev/null +++ b/tests/ui/format_args_unfixable.rs @@ -0,0 +1,60 @@ +#![allow(clippy::assertions_on_constants)] +#![allow(clippy::eq_op)] +#![warn(clippy::format_in_format_args)] +#![warn(clippy::to_string_in_format_args)] + +use std::io::{stdout, Error, ErrorKind, Write}; +use std::ops::Deref; +use std::panic::Location; + +macro_rules! my_macro { + () => { + // here be dragons, do not enter (or lint) + println!("error: {}", format!("something failed at {}", Location::caller())); + }; +} + +macro_rules! my_other_macro { + () => { + format!("something failed at {}", Location::caller()) + }; +} + +fn main() { + let error = Error::new(ErrorKind::Other, "bad thing"); + let x = 'x'; + + println!("error: {}", format!("something failed at {}", Location::caller())); + println!("{}: {}", error, format!("something failed at {}", Location::caller())); + println!("{:?}: {}", error, format!("something failed at {}", Location::caller())); + println!("{{}}: {}", format!("something failed at {}", Location::caller())); + println!(r#"error: "{}""#, format!("something failed at {}", Location::caller())); + println!("error: {}", format!(r#"something failed at "{}""#, Location::caller())); + println!("error: {}", format!("something failed at {} {0}", Location::caller())); + let _ = format!("error: {}", format!("something failed at {}", Location::caller())); + let _ = write!( + stdout(), + "error: {}", + format!("something failed at {}", Location::caller()) + ); + let _ = writeln!( + stdout(), + "error: {}", + format!("something failed at {}", Location::caller()) + ); + print!("error: {}", format!("something failed at {}", Location::caller())); + eprint!("error: {}", format!("something failed at {}", Location::caller())); + eprintln!("error: {}", format!("something failed at {}", Location::caller())); + let _ = format_args!("error: {}", format!("something failed at {}", Location::caller())); + assert!(true, "error: {}", format!("something failed at {}", Location::caller())); + assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); + assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); + panic!("error: {}", format!("something failed at {}", Location::caller())); + + println!("error: {}", format_args!("something failed at {}", Location::caller())); + println!("error: {:>70}", format!("something failed at {}", Location::caller())); + println!("error: {} {0}", format!("something failed at {}", Location::caller())); + println!("{} and again {0}", format!("hi {}", x)); + my_macro!(); + println!("error: {}", my_other_macro!()); +} diff --git a/tests/ui/format_args_unfixable.stderr b/tests/ui/format_args_unfixable.stderr new file mode 100644 index 00000000000..4476218ad58 --- /dev/null +++ b/tests/ui/format_args_unfixable.stderr @@ -0,0 +1,175 @@ +error: `format!` in `println!` args + --> $DIR/format_args_unfixable.rs:27:5 + | +LL | println!("error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::format-in-format-args` implied by `-D warnings` + = help: combine the `format!(..)` arguments with the outer `println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `println!` args + --> $DIR/format_args_unfixable.rs:28:5 + | +LL | println!("{}: {}", error, format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `println!` args + --> $DIR/format_args_unfixable.rs:29:5 + | +LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `println!` args + --> $DIR/format_args_unfixable.rs:30:5 + | +LL | println!("{{}}: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `println!` args + --> $DIR/format_args_unfixable.rs:31:5 + | +LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `println!` args + --> $DIR/format_args_unfixable.rs:32:5 + | +LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `println!` args + --> $DIR/format_args_unfixable.rs:33:5 + | +LL | println!("error: {}", format!("something failed at {} {0}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `println!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `format!` args + --> $DIR/format_args_unfixable.rs:34:13 + | +LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `format!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `write!` args + --> $DIR/format_args_unfixable.rs:35:13 + | +LL | let _ = write!( + | _____________^ +LL | | stdout(), +LL | | "error: {}", +LL | | format!("something failed at {}", Location::caller()) +LL | | ); + | |_____^ + | + = help: combine the `format!(..)` arguments with the outer `write!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `writeln!` args + --> $DIR/format_args_unfixable.rs:40:13 + | +LL | let _ = writeln!( + | _____________^ +LL | | stdout(), +LL | | "error: {}", +LL | | format!("something failed at {}", Location::caller()) +LL | | ); + | |_____^ + | + = help: combine the `format!(..)` arguments with the outer `writeln!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `print!` args + --> $DIR/format_args_unfixable.rs:45:5 + | +LL | print!("error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `print!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `eprint!` args + --> $DIR/format_args_unfixable.rs:46:5 + | +LL | eprint!("error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `eprint!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `eprintln!` args + --> $DIR/format_args_unfixable.rs:47:5 + | +LL | eprintln!("error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `eprintln!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `format_args!` args + --> $DIR/format_args_unfixable.rs:48:13 + | +LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `format_args!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `assert!` args + --> $DIR/format_args_unfixable.rs:49:5 + | +LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `assert!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `assert_eq!` args + --> $DIR/format_args_unfixable.rs:50:5 + | +LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `assert_eq!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `assert_ne!` args + --> $DIR/format_args_unfixable.rs:51:5 + | +LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `assert_ne!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: `format!` in `panic!` args + --> $DIR/format_args_unfixable.rs:52:5 + | +LL | panic!("error: {}", format!("something failed at {}", Location::caller())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: combine the `format!(..)` arguments with the outer `panic!(..)` call + = help: or consider changing `format!` to `format_args!` + +error: aborting due to 18 previous errors + From 47014d81a1e1adbd5dcfbc4d6df5d116d1b36104 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Thu, 30 Sep 2021 07:40:46 -0400 Subject: [PATCH 044/100] Fix adjacent tests --- tests/ui/expect_fun_call.fixed | 1 + tests/ui/expect_fun_call.rs | 1 + tests/ui/expect_fun_call.stderr | 24 ++++++++++++------------ tests/ui/format.fixed | 2 +- tests/ui/format.rs | 2 +- tests/ui/to_string_in_display.rs | 2 +- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index a756d1cf506..cf923a6a594 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::expect_fun_call)] +#![allow(clippy::to_string_in_format_args)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 60bbaa89d42..e6f252259df 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::expect_fun_call)] +#![allow(clippy::to_string_in_format_args)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index 6dc796f5cee..ac48a06671c 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:28:26 + --> $DIR/expect_fun_call.rs:29:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -7,67 +7,67 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = note: `-D clippy::expect-fun-call` implied by `-D warnings` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:31:26 + --> $DIR/expect_fun_call.rs:32:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:41:25 + --> $DIR/expect_fun_call.rs:42:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:44:25 + --> $DIR/expect_fun_call.rs:45:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:56:17 + --> $DIR/expect_fun_call.rs:57:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:77:21 + --> $DIR/expect_fun_call.rs:78:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:78:21 + --> $DIR/expect_fun_call.rs:79:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:79:21 + --> $DIR/expect_fun_call.rs:80:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:81:21 + --> $DIR/expect_fun_call.rs:82:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:82:21 + --> $DIR/expect_fun_call.rs:83:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:86:16 + --> $DIR/expect_fun_call.rs:87:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:92:17 + --> $DIR/expect_fun_call.rs:93:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))` diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 5dd64140e81..73fc750511c 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(clippy::print_literal, clippy::redundant_clone)] +#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)] #![warn(clippy::useless_format)] struct Foo(pub String); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 4599fb5207e..2f4595650cb 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(clippy::print_literal, clippy::redundant_clone)] +#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)] #![warn(clippy::useless_format)] struct Foo(pub String); diff --git a/tests/ui/to_string_in_display.rs b/tests/ui/to_string_in_display.rs index eb8105c6b6d..3ccdcd1117b 100644 --- a/tests/ui/to_string_in_display.rs +++ b/tests/ui/to_string_in_display.rs @@ -1,5 +1,5 @@ #![warn(clippy::to_string_in_display)] -#![allow(clippy::inherent_to_string_shadow_display)] +#![allow(clippy::inherent_to_string_shadow_display, clippy::to_string_in_format_args)] use std::fmt; From 75e9f8cbd6d8c704ec89d12e3ddc382402a13119 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Thu, 30 Sep 2021 07:38:03 -0400 Subject: [PATCH 045/100] Remove redundant `to_string`s --- clippy_dev/src/update_lints.rs | 4 ++-- clippy_lints/src/if_then_panic.rs | 4 ++-- clippy_lints/src/inherent_to_string.rs | 8 ++++---- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/transmute/transmute_int_to_char.rs | 2 +- clippy_lints/src/transmute/transmute_int_to_float.rs | 2 +- clippy_lints/src/transmute/transmute_num_to_bytes.rs | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 10d859988f6..23f58bc4915 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -619,8 +619,8 @@ fn test_gen_changelog_lint_list() { Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"), ]; let expected = vec![ - format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()), - format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()), + format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK), + format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK), ]; assert_eq!(expected, gen_changelog_lint_list(lints.iter())); } diff --git a/clippy_lints/src/if_then_panic.rs b/clippy_lints/src/if_then_panic.rs index 10bca59e6d0..e8cea5529e8 100644 --- a/clippy_lints/src/if_then_panic.rs +++ b/clippy_lints/src/if_then_panic.rs @@ -78,10 +78,10 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e { sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string() } else { - format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par().to_string()) + format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par()) } } else { - format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par().to_string()) + format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par()) }; span_lint_and_sugg( diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 3c40ca50a09..61dd0eb4af7 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -138,10 +138,10 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { item.span, &format!( "type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`", - self_type.to_string() + self_type ), None, - &format!("remove the inherent method from type `{}`", self_type.to_string()), + &format!("remove the inherent method from type `{}`", self_type), ); } else { span_lint_and_help( @@ -150,10 +150,10 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) { item.span, &format!( "implementation of inherent method `to_string(&self) -> String` for type `{}`", - self_type.to_string() + self_type ), None, - &format!("implement trait `Display` for type `{}` instead", self_type.to_string()), + &format!("implement trait `Display` for type `{}` instead", self_type), ); } } diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 44d5ff0b63a..201aa067824 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -678,7 +678,7 @@ fn suggestion_with_swapped_ident( Some(format!( "{}{}{}", snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability), - new_ident.to_string(), + new_ident, snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability), )) }) diff --git a/clippy_lints/src/transmute/transmute_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 8f884e6a4a1..e83d2e06b9a 100644 --- a/clippy_lints/src/transmute/transmute_int_to_char.rs +++ b/clippy_lints/src/transmute/transmute_int_to_char.rs @@ -33,7 +33,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("std::char::from_u32({}).unwrap()", arg.to_string()), + format!("std::char::from_u32({}).unwrap()", arg), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_int_to_float.rs b/clippy_lints/src/transmute/transmute_int_to_float.rs index 2b6a4cff81e..05eee380d6f 100644 --- a/clippy_lints/src/transmute/transmute_int_to_float.rs +++ b/clippy_lints/src/transmute/transmute_int_to_float.rs @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using", - format!("{}::from_bits({})", to_ty, arg.to_string()), + format!("{}::from_bits({})", to_ty, arg), Applicability::Unspecified, ); }, diff --git a/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/clippy_lints/src/transmute/transmute_num_to_bytes.rs index dd5ded1c91a..5ba58a76494 100644 --- a/clippy_lints/src/transmute/transmute_num_to_bytes.rs +++ b/clippy_lints/src/transmute/transmute_num_to_bytes.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( diag.span_suggestion( e.span, "consider using `to_ne_bytes()`", - format!("{}.to_ne_bytes()", arg.to_string()), + format!("{}.to_ne_bytes()", arg), Applicability::Unspecified, ); }, From 25ff7ce1283c45a330793ce74cfa5190c4ab68f8 Mon Sep 17 00:00:00 2001 From: Matthias Kaak Date: Sat, 16 Oct 2021 15:23:34 +0000 Subject: [PATCH 046/100] Fixed naive doc formatting for `#[must_use]` lints --- clippy_lints/src/functions/mod.rs | 12 +++--------- clippy_lints/src/let_underscore.rs | 7 +++---- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 04fc5887e8e..d7c5ec9ba35 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -91,11 +91,9 @@ declare_clippy_lint! { /// ### What it does - /// Checks for a [`#[must_use]`] attribute on + /// Checks for a `#[must_use]` attribute on /// unit-returning functions and methods. /// - /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute - /// /// ### Why is this bad? /// Unit values are useless. The attribute is likely /// a remnant of a refactoring that removed the return type. @@ -112,12 +110,10 @@ declare_clippy_lint! { /// ### What it does - /// Checks for a [`#[must_use]`] attribute without + /// Checks for a `#[must_use]` attribute without /// further information on functions and methods that return a type already /// marked as `#[must_use]`. /// - /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute - /// /// ### Why is this bad? /// The attribute isn't needed. Not using the result /// will already be reported. Alternatively, one can add some text to the @@ -138,11 +134,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for public functions that have no - /// [`#[must_use]`] attribute, but return something not already marked + /// `#[must_use]` attribute, but return something not already marked /// must-use, have no mutable arg and mutate no statics. /// - /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute - /// /// ### Why is this bad? /// Not bad at all, this lint just shows places where /// you could add the attribute. diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 89146b4dd2c..9efd7aba7e8 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -10,12 +10,11 @@ declare_clippy_lint! { /// ### What it does - /// Checks for `let _ = ` - /// where expr is #[must_use] + /// Checks for `let _ = ` where expr is `#[must_use]` /// /// ### Why is this bad? - /// It's better to explicitly - /// handle the value of a #[must_use] expr + /// It's better to explicitly handle the value of a `#[must_use]` + /// expr /// /// ### Example /// ```rust From 599d9126a292d1f6944e473b1d47dde65cb7f993 Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Sun, 17 Oct 2021 12:04:01 +0200 Subject: [PATCH 047/100] Some "parenthesis" and "parentheses" fixes --- clippy_lints/src/manual_unwrap_or.rs | 2 +- clippy_utils/src/sugg.rs | 6 +++--- tests/ui/manual_unwrap_or.fixed | 4 ++-- tests/ui/manual_unwrap_or.rs | 4 ++-- tests/ui/useless_conversion.fixed | 2 +- tests/ui/useless_conversion.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 2ae9cb4f9c1..42478e3416e 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -98,7 +98,7 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&' reindent_multiline(or_body_snippet.into(), true, Some(indent)); let suggestion = if scrutinee.span.from_expansion() { - // we don't want parenthesis around macro, e.g. `(some_macro!()).unwrap_or(0)` + // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)` sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..") } else { diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 5b0efb1fd71..01fb944cc36 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -16,10 +16,10 @@ use std::fmt::Display; use std::ops::{Add, Neg, Not, Sub}; -/// A helper type to build suggestion correctly handling parenthesis. +/// A helper type to build suggestion correctly handling parentheses. #[derive(Clone, PartialEq)] pub enum Sugg<'a> { - /// An expression that never needs parenthesis such as `1337` or `[0; 42]`. + /// An expression that never needs parentheses such as `1337` or `[0; 42]`. NonParen(Cow<'a, str>), /// An expression that does not fit in other variants. MaybeParen(Cow<'a, str>), @@ -283,7 +283,7 @@ pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> { } } - /// Adds parenthesis to any expression that might need them. Suitable to the + /// Adds parentheses to any expression that might need them. Suitable to the /// `self` argument of a method call /// (e.g., to build `bar.foo()` or `(1 + 2).foo()`). pub fn maybe_par(self) -> Self { diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 3717f962745..05d6c56f2ac 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -74,10 +74,10 @@ fn result_unwrap_or() { let a = Ok::(1); a.unwrap_or(42); - // int case, suggestion must surround Result expr with parenthesis + // int case, suggestion must surround Result expr with parentheses (Ok(1) as Result).unwrap_or(42); - // method call case, suggestion must not surround Result expr `s.method()` with parenthesis + // method call case, suggestion must not surround Result expr `s.method()` with parentheses struct S {} impl S { fn method(self) -> Option { diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index 989adde1f5b..09f62c69b71 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -95,13 +95,13 @@ fn result_unwrap_or() { Err(_) => 42, }; - // int case, suggestion must surround Result expr with parenthesis + // int case, suggestion must surround Result expr with parentheses match Ok(1) as Result { Ok(i) => i, Err(_) => 42, }; - // method call case, suggestion must not surround Result expr `s.method()` with parenthesis + // method call case, suggestion must not surround Result expr `s.method()` with parentheses struct S {} impl S { fn method(self) -> Option { diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 76aa82068d6..70ff08f3655 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -66,7 +66,7 @@ fn main() { let _ = vec![1, 2, 3].into_iter(); let _: String = format!("Hello {}", "world"); - // keep parenthesis around `a + b` for suggestion (see #4750) + // keep parentheses around `a + b` for suggestion (see #4750) let a: i32 = 1; let b: i32 = 1; let _ = (a + b) * 3; diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index ccee7abb404..f2444a8f436 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -66,7 +66,7 @@ fn main() { let _ = vec![1, 2, 3].into_iter().into_iter(); let _: String = format!("Hello {}", "world").into(); - // keep parenthesis around `a + b` for suggestion (see #4750) + // keep parentheses around `a + b` for suggestion (see #4750) let a: i32 = 1; let b: i32 = 1; let _ = i32::from(a + b) * 3; From a550133b8fa9e3bae23c26eadae1a75f86b240a6 Mon Sep 17 00:00:00 2001 From: Paul Gey Date: Sun, 17 Oct 2021 15:56:59 +0200 Subject: [PATCH 048/100] Fix false positive of `implicit_saturating_sub` with `else` clause Fixes #7831 --- clippy_lints/src/implicit_saturating_sub.rs | 2 +- tests/ui/implicit_saturating_sub.fixed | 8 ++++++++ tests/ui/implicit_saturating_sub.rs | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 79d4d7ddcbc..a4f60ded3a6 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -43,7 +43,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { return; } if_chain! { - if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr); + if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr); // Check if the conditional expression is a binary operation if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind; diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 859765d08a7..e6f57e9267e 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -157,4 +157,12 @@ fn main() { if i_64 != 0 { i_64 -= 1; } + + // issue #7831 + // No Lint + if u_32 > 0 { + u_32 -= 1; + } else { + println!("side effect"); + } } diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 2f32a7b1578..8bb28d149c6 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -203,4 +203,12 @@ fn main() { if i_64 != 0 { i_64 -= 1; } + + // issue #7831 + // No Lint + if u_32 > 0 { + u_32 -= 1; + } else { + println!("side effect"); + } } From bdc16242594e2ad9dea5ad8591417765b6bcc41c Mon Sep 17 00:00:00 2001 From: Dmitry Borodin <11879032+Dmitry-Borodin@users.noreply.github.com> Date: Sun, 17 Oct 2021 18:59:36 +0200 Subject: [PATCH 049/100] Add reference to another doc with explanation Add reference to another doc that explains which repository should be passed in this command since this is not covered in the command help itself. --- doc/basics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/basics.md b/doc/basics.md index ff2e0417435..6da90ebf5f5 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -93,7 +93,7 @@ cargo dev update_lints cargo dev new_lint # automatically formatting all code before each commit cargo dev setup git-hook -# (experimental) Setup Clippy to work with IntelliJ-Rust +# (experimental) Setup Clippy to work with IntelliJ-Rust. Details here: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust cargo dev setup intellij ``` From 5f2ecc37f895f2eeea84651c9246ffea97e5b0fe Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Oct 2021 23:20:30 +0300 Subject: [PATCH 050/100] rustc_span: `Ident::invalid` -> `Ident::empty` The equivalent for `Symbol`s was renamed some time ago (`kw::Invalid` -> `kw::Empty`), and it makes sense to do the same thing for `Ident`s. --- tests/ui-internal/unnecessary_symbol_str.fixed | 4 ++-- tests/ui-internal/unnecessary_symbol_str.rs | 4 ++-- tests/ui-internal/unnecessary_symbol_str.stderr | 9 ++++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed index 2ec0efe4c10..95b8c6dfe89 100644 --- a/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/tests/ui-internal/unnecessary_symbol_str.fixed @@ -11,6 +11,6 @@ fn main() { Symbol::intern("foo") == rustc_span::sym::clippy; Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower; Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper; - Ident::invalid().name == rustc_span::sym::clippy; - rustc_span::sym::clippy == Ident::invalid().name; + Ident::empty().name == rustc_span::sym::clippy; + rustc_span::sym::clippy == Ident::empty().name; } diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs index 87e1b3a2ee7..ad6937cf60a 100644 --- a/tests/ui-internal/unnecessary_symbol_str.rs +++ b/tests/ui-internal/unnecessary_symbol_str.rs @@ -11,6 +11,6 @@ fn main() { Symbol::intern("foo").as_str() == "clippy"; Symbol::intern("foo").to_string() == "self"; Symbol::intern("foo").to_ident_string() != "Self"; - &*Ident::invalid().as_str() == "clippy"; - "clippy" == Ident::invalid().to_string(); + &*Ident::empty().as_str() == "clippy"; + "clippy" == Ident::empty().to_string(); } diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr index b1284b7c8ff..8e04d447fbc 100644 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ b/tests/ui-internal/unnecessary_symbol_str.stderr @@ -26,14 +26,13 @@ LL | Symbol::intern("foo").to_ident_string() != "Self"; error: unnecessary `Symbol` to string conversion --> $DIR/unnecessary_symbol_str.rs:14:5 | -LL | &*Ident::invalid().as_str() == "clippy"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::invalid().name == rustc_span::sym::clippy` +LL | &*Ident::empty().as_str() == "clippy"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy` error: unnecessary `Symbol` to string conversion --> $DIR/unnecessary_symbol_str.rs:15:5 | -LL | "clippy" == Ident::invalid().to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::invalid().name` +LL | "clippy" == Ident::empty().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name` error: aborting due to 5 previous errors - From 63d715209eaf241114f87db247b435df5272e8e4 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Mon, 18 Oct 2021 08:46:11 +0200 Subject: [PATCH 051/100] Remove unneeded allow --- clippy_lints/src/identity_op.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 73bdd67ff5d..414f465c494 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -66,7 +66,6 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_ && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)) } -#[allow(clippy::cast_possible_wrap)] fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) { let check = match *cx.typeck_results().expr_ty(e).kind() { From 797507c58390662098f0d20a9ee89d200f93f11c Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Thu, 14 Oct 2021 20:08:38 -0700 Subject: [PATCH 052/100] Add boilerplate and basic tests --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.rs | 1 + ...railing_zero_sized_array_without_repr_c.rs | 58 +++++++++++++++++++ ...railing_zero_sized_array_without_repr_c.rs | 23 ++++++++ 6 files changed, 85 insertions(+) create mode 100644 clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs create mode 100644 tests/ui/trailing_zero_sized_array_without_repr_c.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f6a883311c9..a124bebe924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3021,6 +3021,7 @@ Released 2018-09-13 [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg +[`trailing_zero_sized_array_without_repr_c`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_zero_sized_array_without_repr_c [`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds [`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str [`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index f334f723f6b..34b87002fa3 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -443,6 +443,7 @@ temporary_assignment::TEMPORARY_ASSIGNMENT, to_digit_is_some::TO_DIGIT_IS_SOME, to_string_in_display::TO_STRING_IN_DISPLAY, + trailing_zero_sized_array_without_repr_c::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 96e0b421094..325706746db 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -25,6 +25,7 @@ LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), + LintId::of(trailing_zero_sized_array_without_repr_c::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(use_self::USE_SELF), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9794d74e198..17bffc08309 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -355,6 +355,7 @@ macro_rules! declare_clippy_lint { mod temporary_assignment; mod to_digit_is_some; mod to_string_in_display; +mod trailing_zero_sized_array_without_repr_c; mod trait_bounds; mod transmute; mod transmuting_null; diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs new file mode 100644 index 00000000000..9aea22af274 --- /dev/null +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -0,0 +1,58 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Displays a warning when a struct with a trailing zero-sized array is declared without the `repr(C)` attribute. + /// + /// ### Why is this bad? + /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code (or in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` is needed. + /// + /// ### Example + /// ```rust + /// struct RarelyUseful { + /// some_field: usize, + /// last: [SomeType; 0], + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// #[repr(C)] + /// struct MakesSense { + /// some_field: usize, + /// last: [SomeType; 0], + /// } + /// ``` + pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, + nursery, + "struct with a trailing zero-sized array but without `repr(C)`" +} +declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C]); + +impl LateLintPass<'_> for TrailingZeroSizedArrayWithoutReprC { + fn check_struct_def(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::VariantData<'tcx>) {} + + fn check_struct_def_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::VariantData<'tcx>) {} + // https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/enum.TyKind.html#variant.Array in latepass + // or https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Array in early pass + + fn check_field_def(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::FieldDef<'tcx>) {} + + fn check_attribute(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_ast::Attribute) {} + + fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} + + fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} +} +// +// TODO: Register the lint pass in `clippy_lints/src/lib.rs`, +// e.g. store.register_late_pass(|| +// Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); + + +fn temp_alert() { + span_lint_and_sugg(cx, lint, sp, msg, help, sugg, applicability) +} \ No newline at end of file diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs new file mode 100644 index 00000000000..2a0f432bc2d --- /dev/null +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -0,0 +1,23 @@ +#![warn(clippy::trailing_zero_sized_array_without_repr_c)] + +struct RarelyUseful { + field: i32, + last: [SomeType; 0], +} + +#[repr(C)] +struct GoodReason { + field: i32, + last: [SomeType; 0], +} + +struct OnlyFieldIsZeroSizeArray { + first_and_last: [SomeType; 0], +} + +struct GenericArrayType { + field: i32, + last: [T; 0], +} + +fn main() {} From c69387a0d530dccb56ef11d4cd148f9c38904893 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Fri, 15 Oct 2021 00:13:42 -0700 Subject: [PATCH 053/100] Well it builds --- ...railing_zero_sized_array_without_repr_c.rs | 47 +++++++++++++++---- ...railing_zero_sized_array_without_repr_c.rs | 6 +-- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 9aea22af274..507d9b40412 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_hir::*; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -33,26 +34,54 @@ declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C]); impl LateLintPass<'_> for TrailingZeroSizedArrayWithoutReprC { - fn check_struct_def(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::VariantData<'tcx>) {} + fn check_struct_def(&mut self, cx: &LateContext<'tcx>, data: &'tcx rustc_hir::VariantData<'tcx>) { + dbg!("in check_struct_def"); + if_chain! { + if let Some(def) = data.fields().last(); + if let rustc_hir::TyKind::Array(ty, acost) = def.ty.kind; + then { + // is the AnonConst `0` + } + } - fn check_struct_def_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::VariantData<'tcx>) {} + // span_lint_and_sugg( + // cx, + // todo!(), + // todo!(), + // todo!(), + // todo!(), + // todo!(), + // rustc_errors::Applicability::MaybeIncorrect, + // ) + } // https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/enum.TyKind.html#variant.Array in latepass // or https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Array in early pass - fn check_field_def(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::FieldDef<'tcx>) {} + // fn check_struct_def_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::VariantData<'tcx>) + // {} - fn check_attribute(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_ast::Attribute) {} + // fn check_field_def(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::FieldDef<'tcx>) {} - fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} + // fn check_attribute(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_ast::Attribute) {} - fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} + // fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} + + // fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} } // // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, // e.g. store.register_late_pass(|| // Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); +// fn temp_alert() {} -fn temp_alert() { - span_lint_and_sugg(cx, lint, sp, msg, help, sugg, applicability) -} \ No newline at end of file +impl EarlyLintPass for TrailingZeroSizedArrayWithoutReprC { + fn check_struct_def(&mut self, cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) { + if_chain! { + if let rustc_ast::ast::VariantData::Struct(field_defs, some_bool_huh) = data; + if let Some(last_field) = field_defs.last(); + if let rustc_ast::ast::TyKind::Array(_, aconst) = &last_field.ty.kind; + then {dbg!(aconst); return ();} + } + } +} diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 2a0f432bc2d..771622178e7 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -2,17 +2,17 @@ struct RarelyUseful { field: i32, - last: [SomeType; 0], + last: [usize; 0], } #[repr(C)] struct GoodReason { field: i32, - last: [SomeType; 0], + last: [usize; 0], } struct OnlyFieldIsZeroSizeArray { - first_and_last: [SomeType; 0], + first_and_last: [usize; 0], } struct GenericArrayType { From 92d3b775bd05c363b69b91ed66c20904c7fbfbe7 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Fri, 15 Oct 2021 01:31:26 -0700 Subject: [PATCH 054/100] =?UTF-8?q?ayy=20it=20compiles!=20ship=20it,=20rig?= =?UTF-8?q?ht=3F=20=F0=9F=98=8E=20/s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit why was `rustc_lint_defs` not already externed in `lib.rs`? and how was r-a able to find it but cargo wasn't? 🤔 --- clippy_lints/src/lib.rs | 2 + ...railing_zero_sized_array_without_repr_c.rs | 76 ++++++++----------- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 17bffc08309..6624ee93101 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -30,6 +30,7 @@ extern crate rustc_infer; extern crate rustc_lexer; extern crate rustc_lint; +extern crate rustc_lint_defs; extern crate rustc_middle; extern crate rustc_mir_dataflow; extern crate rustc_parse; @@ -487,6 +488,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass)); } + store.register_early_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); store.register_late_pass(|| Box::new(utils::author::Author)); store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding)); store.register_late_pass(|| Box::new(serde_api::SerdeApi)); diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 507d9b40412..a96b8792295 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_hir::*; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint_defs::Applicability; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -33,55 +32,42 @@ } declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C]); -impl LateLintPass<'_> for TrailingZeroSizedArrayWithoutReprC { - fn check_struct_def(&mut self, cx: &LateContext<'tcx>, data: &'tcx rustc_hir::VariantData<'tcx>) { - dbg!("in check_struct_def"); - if_chain! { - if let Some(def) = data.fields().last(); - if let rustc_hir::TyKind::Array(ty, acost) = def.ty.kind; - then { - // is the AnonConst `0` - } - } - - // span_lint_and_sugg( - // cx, - // todo!(), - // todo!(), - // todo!(), - // todo!(), - // todo!(), - // rustc_errors::Applicability::MaybeIncorrect, - // ) - } - // https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/enum.TyKind.html#variant.Array in latepass - // or https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/enum.TyKind.html#variant.Array in early pass - - // fn check_struct_def_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::VariantData<'tcx>) - // {} - - // fn check_field_def(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::FieldDef<'tcx>) {} - - // fn check_attribute(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_ast::Attribute) {} - - // fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} - - // fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [rustc_ast::Attribute]) {} -} // // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, -// e.g. store.register_late_pass(|| +// e.g. store.register_early_pass(|| // Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); -// fn temp_alert() {} - impl EarlyLintPass for TrailingZeroSizedArrayWithoutReprC { fn check_struct_def(&mut self, cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) { - if_chain! { - if let rustc_ast::ast::VariantData::Struct(field_defs, some_bool_huh) = data; - if let Some(last_field) = field_defs.last(); - if let rustc_ast::ast::TyKind::Array(_, aconst) = &last_field.ty.kind; - then {dbg!(aconst); return ();} + if is_struct_with_trailing_zero_sized_array(cx, data) && !has_repr_c(cx, data) { + span_lint_and_sugg( + cx, + todo!(), + todo!(), + todo!(), + "try", + "`#[repr(C)]`".to_string(), + Applicability::MachineApplicable, + ) } } } + +fn is_struct_with_trailing_zero_sized_array(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool { + if_chain! { + if let rustc_ast::ast::VariantData::Struct(field_defs, some_bool_huh) = data; + if let Some(last_field) = field_defs.last(); + if let rustc_ast::ast::TyKind::Array(_, aconst) = &last_field.ty.kind; + // TODO: if array is zero-sized; + then { + dbg!(aconst); + true + } else { + false + } + } +} + +fn has_repr_c(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool { + todo!() +} From 7ee8e7a9b846686148b8797ecc5ae724a6c5a1a9 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Fri, 15 Oct 2021 16:16:27 -0700 Subject: [PATCH 055/100] Implement detecting trailing zero-sized array --- clippy_lints/src/lib.rs | 4 +- ...railing_zero_sized_array_without_repr_c.rs | 62 ++++++++++++------- ...railing_zero_sized_array_without_repr_c.rs | 26 ++++++++ 3 files changed, 69 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6624ee93101..d494892c3b4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -30,7 +30,6 @@ extern crate rustc_infer; extern crate rustc_lexer; extern crate rustc_lint; -extern crate rustc_lint_defs; extern crate rustc_middle; extern crate rustc_mir_dataflow; extern crate rustc_parse; @@ -488,7 +487,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass)); } - store.register_early_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); store.register_late_pass(|| Box::new(utils::author::Author)); store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding)); store.register_late_pass(|| Box::new(serde_api::SerdeApi)); @@ -780,6 +778,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); store.register_late_pass(move || Box::new(format_args::FormatArgs)); + store.register_late_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); + } #[rustfmt::skip] diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index a96b8792295..6ca382d1679 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,6 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_lint_defs::Applicability; +// use clippy_utils::is_integer_const; +use clippy_utils::consts::{miri_to_const, Constant}; +use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind, TyKind, VariantData}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -36,38 +39,55 @@ // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, // e.g. store.register_early_pass(|| // Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); +// DONE! -impl EarlyLintPass for TrailingZeroSizedArrayWithoutReprC { - fn check_struct_def(&mut self, cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) { - if is_struct_with_trailing_zero_sized_array(cx, data) && !has_repr_c(cx, data) { - span_lint_and_sugg( - cx, - todo!(), - todo!(), - todo!(), - "try", - "`#[repr(C)]`".to_string(), - Applicability::MachineApplicable, - ) +impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if is_struct_with_trailing_zero_sized_array(cx, item) + /* && !has_repr_c(cx, item) */ + { + // span_lint_and_sugg( + // cx, + // todo!(), + // todo!(), + // todo!(), + // "try", + // "`#[repr(C)]`".to_string(), + // Applicability::MachineApplicable, + // ); + // println!("consider yourself linted 😎"); } } } -fn is_struct_with_trailing_zero_sized_array(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool { +fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { + dbg!(item.ident); if_chain! { - if let rustc_ast::ast::VariantData::Struct(field_defs, some_bool_huh) = data; + if let ItemKind::Struct(data, _generics) = &item.kind; + if let VariantData::Struct(field_defs, _) = data; if let Some(last_field) = field_defs.last(); - if let rustc_ast::ast::TyKind::Array(_, aconst) = &last_field.ty.kind; - // TODO: if array is zero-sized; + if let TyKind::Array(_, aconst) = last_field.ty.kind; + let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); + let ty = cx.tcx.type_of(aconst_def_id); + let constant = cx + .tcx + .const_eval_poly(aconst_def_id) // NOTE: maybe const_eval_resolve? seems especially cursed to be using a const expr which resolves to 0 to create a zero-sized array, tho + .ok() + .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); + if let Some(Constant::Int(val)) = constant.and_then(miri_to_const); + if val == 0; then { - dbg!(aconst); + eprintln!("true"); true } else { + // dbg!(aconst); + eprintln!("false"); false } } } -fn has_repr_c(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool { - todo!() +fn has_repr_c(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { + // todo!() + true } diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 771622178e7..5f844f16ba1 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -20,4 +20,30 @@ struct GenericArrayType { last: [T; 0], } +struct SizedArray { + field: i32, + last: [usize; 1], +} + +const ZERO: usize = 0; +struct ZeroSizedFromExternalConst { + field: i32, + last: [usize; ZERO], +} + +const ONE: usize = 1; +struct NonZeroSizedFromExternalConst { + field: i32, + last: [usize; ONE], +} + +#[allow(clippy::eq_op)] // lmao im impressed +const fn compute_zero() -> usize { + (4 + 6) - (2 * 5) +} +struct UsingFunction { + field: i32, + last: [usize; compute_zero()], +} + fn main() {} From 523b0131618d8e4437a788eb1e3ddca743b3789f Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Fri, 15 Oct 2021 23:44:39 -0700 Subject: [PATCH 056/100] Implement getting an array of attributes! --- ...railing_zero_sized_array_without_repr_c.rs | 73 ++++++++++++------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 6ca382d1679..063dfb874cf 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -5,6 +5,7 @@ use rustc_hir::{Item, ItemKind, TyKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -43,9 +44,8 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if is_struct_with_trailing_zero_sized_array(cx, item) - /* && !has_repr_c(cx, item) */ - { + dbg!(item.ident); + if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_c(cx, item) { // span_lint_and_sugg( // cx, // todo!(), @@ -61,33 +61,52 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { - dbg!(item.ident); - if_chain! { - if let ItemKind::Struct(data, _generics) = &item.kind; - if let VariantData::Struct(field_defs, _) = data; - if let Some(last_field) = field_defs.last(); - if let TyKind::Array(_, aconst) = last_field.ty.kind; - let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); - let ty = cx.tcx.type_of(aconst_def_id); - let constant = cx - .tcx - .const_eval_poly(aconst_def_id) // NOTE: maybe const_eval_resolve? seems especially cursed to be using a const expr which resolves to 0 to create a zero-sized array, tho - .ok() - .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(miri_to_const); - if val == 0; - then { - eprintln!("true"); - true - } else { - // dbg!(aconst); - eprintln!("false"); - false + if let ItemKind::Struct(data, _generics) = &item.kind { + if let VariantData::Struct(field_defs, _) = data { + if let Some(last_field) = field_defs.last() { + if let TyKind::Array(_, aconst) = last_field.ty.kind { + let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); + let ty = cx.tcx.type_of(aconst_def_id); + let constant = cx + .tcx + // NOTE: maybe const_eval_resolve? seems especially cursed to be using a const expr which + // resolves to 0 to create a zero-sized array, tho + .const_eval_poly(aconst_def_id) + .ok() + .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); + if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) { + if val == 0 { + eprintln!("trailing: true"); + return true; + } + } + } + } } } + // dbg!(aconst); + eprintln!("trailing: false"); + false } fn has_repr_c(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { - // todo!() - true + // let hir_id2 = if let Some(body) = cx.enclosing_body { + // body.hir_id + // } else { + // todo!(); + // }; + + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id); + let attrs = cx.tcx.hir().attrs(hir_id); + // NOTE: Can there ever be more than one `repr` attribute? + // other `repr` syms: repr, repr128, repr_align, repr_align_enum, repr_no_niche, repr_packed, + // repr_simd, repr_transparent + + if let Some(repr_attr) = attrs.iter().find(|attr| attr.has_name(sym::repr)) { + eprintln!("repr: true"); + true + } else { + eprintln!("repr: false"); + false + } } From e53a4da4a142d3e90f8eb658a19466eca54901ea Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sat, 16 Oct 2021 00:51:09 -0700 Subject: [PATCH 057/100] it works i think (incl some `dbg`s) --- ...railing_zero_sized_array_without_repr_c.rs | 53 +++++++------ ...railing_zero_sized_array_without_repr_c.rs | 79 +++++++++++++------ 2 files changed, 82 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 063dfb874cf..62f8ecdc216 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -2,7 +2,7 @@ // use clippy_utils::is_integer_const; use clippy_utils::consts::{miri_to_const, Constant}; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind, TyKind, VariantData}; +use rustc_hir::{HirId, Item, ItemKind, TyKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -45,17 +45,29 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { dbg!(item.ident); - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_c(cx, item) { - // span_lint_and_sugg( - // cx, - // todo!(), - // todo!(), - // todo!(), - // "try", - // "`#[repr(C)]`".to_string(), - // Applicability::MachineApplicable, - // ); - // println!("consider yourself linted 😎"); + + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id); + let hir_id2 = item.hir_id(); + dbg!(hir_id); + dbg!(hir_id2); + dbg!(hir_id == hir_id2); + + let span1 = cx.tcx.hir().span(hir_id); + let span2 = item.span; + dbg!(span1); + dbg!(span2); + dbg!(span1 == span2); + + if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_c(cx, hir_id) { + span_lint_and_sugg( + cx, + TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, + span2, + "trailing zero-sized array in a struct which isn't marked `#[repr(C)]`", + "try", + "#[repr(C)]".to_string(), + Applicability::MaybeIncorrect, + ); } } } @@ -76,7 +88,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) { if val == 0 { - eprintln!("trailing: true"); + // eprintln!("trailing: true"); return true; } } @@ -85,28 +97,21 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } } // dbg!(aconst); - eprintln!("trailing: false"); + // eprintln!("trailing: false"); false } -fn has_repr_c(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { - // let hir_id2 = if let Some(body) = cx.enclosing_body { - // body.hir_id - // } else { - // todo!(); - // }; - - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id); +fn has_repr_c(cx: &LateContext<'tcx>, hir_id: HirId) -> bool { let attrs = cx.tcx.hir().attrs(hir_id); // NOTE: Can there ever be more than one `repr` attribute? // other `repr` syms: repr, repr128, repr_align, repr_align_enum, repr_no_niche, repr_packed, // repr_simd, repr_transparent if let Some(repr_attr) = attrs.iter().find(|attr| attr.has_name(sym::repr)) { - eprintln!("repr: true"); + // eprintln!("repr: true"); true } else { - eprintln!("repr: false"); + // eprintln!("repr: false"); false } } diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 5f844f16ba1..1e3683b2c25 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -15,35 +15,62 @@ struct OnlyFieldIsZeroSizeArray { first_and_last: [usize; 0], } -struct GenericArrayType { - field: i32, - last: [T; 0], -} +// struct GenericArrayType { +// field: i32, +// last: [T; 0], +// } -struct SizedArray { - field: i32, - last: [usize; 1], -} +// struct SizedArray { +// field: i32, +// last: [usize; 1], +// } -const ZERO: usize = 0; -struct ZeroSizedFromExternalConst { - field: i32, - last: [usize; ZERO], -} +// const ZERO: usize = 0; +// struct ZeroSizedFromExternalConst { +// field: i32, +// last: [usize; ZERO], +// } -const ONE: usize = 1; -struct NonZeroSizedFromExternalConst { - field: i32, - last: [usize; ONE], -} +// const ONE: usize = 1; +// struct NonZeroSizedFromExternalConst { +// field: i32, +// last: [usize; ONE], +// } -#[allow(clippy::eq_op)] // lmao im impressed -const fn compute_zero() -> usize { - (4 + 6) - (2 * 5) -} -struct UsingFunction { - field: i32, - last: [usize; compute_zero()], -} +// #[allow(clippy::eq_op)] // lmao im impressed +// const fn compute_zero() -> usize { +// (4 + 6) - (2 * 5) +// } +// struct UsingFunction { +// field: i32, +// last: [usize; compute_zero()], +// } + +// // TODO: same +// #[repr(packed)] +// struct ReprPacked { +// small: u8, +// medium: i32, +// weird: [u64; 0], +// } + +// // TODO: actually, uh,, +// #[repr(align(64))] +// struct ReprAlign { +// field: i32, +// last: [usize; 0], +// } +// #[repr(C, align(64))] +// struct ReprCAlign { +// field: i32, +// last: [usize; 0], +// } + +// #[repr(C)] +// enum DontLintAnonymousStructsFromDesuraging { +// A(u32), +// B(f32, [u64; 0]), +// C { x: u32, y: [u64; 0] }, +// } fn main() {} From 4b4db597722ff561515812e2e0cab255a678a41c Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sat, 16 Oct 2021 02:01:17 -0700 Subject: [PATCH 058/100] output looks fantastic --- ...railing_zero_sized_array_without_repr_c.rs | 34 ++--- ...railing_zero_sized_array_without_repr_c.rs | 139 +++++++++++------- 2 files changed, 100 insertions(+), 73 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 62f8ecdc216..7eeb2914c40 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,8 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -// use clippy_utils::is_integer_const; use clippy_utils::consts::{miri_to_const, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; use rustc_errors::Applicability; -use rustc_hir::{HirId, Item, ItemKind, TyKind, VariantData}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{Item, ItemKind, TyKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -46,26 +47,14 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { dbg!(item.ident); - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id); - let hir_id2 = item.hir_id(); - dbg!(hir_id); - dbg!(hir_id2); - dbg!(hir_id == hir_id2); - - let span1 = cx.tcx.hir().span(hir_id); - let span2 = item.span; - dbg!(span1); - dbg!(span2); - dbg!(span1 == span2); - - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_c(cx, hir_id) { + if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_c(cx, item.def_id) { span_lint_and_sugg( cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, - span2, - "trailing zero-sized array in a struct which isn't marked `#[repr(C)]`", + item.span, + "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", "try", - "#[repr(C)]".to_string(), + format!("#[repr(C)]\n{}", snippet(cx, item.span, "..")), Applicability::MaybeIncorrect, ); } @@ -101,13 +90,14 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx false } -fn has_repr_c(cx: &LateContext<'tcx>, hir_id: HirId) -> bool { +fn has_repr_c(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); let attrs = cx.tcx.hir().attrs(hir_id); + // NOTE: Can there ever be more than one `repr` attribute? // other `repr` syms: repr, repr128, repr_align, repr_align_enum, repr_no_niche, repr_packed, // repr_simd, repr_transparent - - if let Some(repr_attr) = attrs.iter().find(|attr| attr.has_name(sym::repr)) { + if let Some(_repr_attr) = attrs.iter().find(|attr| attr.has_name(sym::repr)) { // eprintln!("repr: true"); true } else { diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 1e3683b2c25..311193fb4a1 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -1,5 +1,7 @@ #![warn(clippy::trailing_zero_sized_array_without_repr_c)] +// #![feature(const_generics_defaults)] + struct RarelyUseful { field: i32, last: [usize; 0], @@ -15,62 +17,97 @@ struct OnlyFieldIsZeroSizeArray { first_and_last: [usize; 0], } -// struct GenericArrayType { -// field: i32, -// last: [T; 0], -// } +struct GenericArrayType { + field: i32, + last: [T; 0], +} -// struct SizedArray { -// field: i32, -// last: [usize; 1], -// } +struct SizedArray { + field: i32, + last: [usize; 1], +} -// const ZERO: usize = 0; -// struct ZeroSizedFromExternalConst { -// field: i32, -// last: [usize; ZERO], -// } +const ZERO: usize = 0; +struct ZeroSizedFromExternalConst { + field: i32, + last: [usize; ZERO], +} -// const ONE: usize = 1; -// struct NonZeroSizedFromExternalConst { -// field: i32, -// last: [usize; ONE], -// } +const ONE: usize = 1; +struct NonZeroSizedFromExternalConst { + field: i32, + last: [usize; ONE], +} -// #[allow(clippy::eq_op)] // lmao im impressed -// const fn compute_zero() -> usize { -// (4 + 6) - (2 * 5) -// } -// struct UsingFunction { -// field: i32, -// last: [usize; compute_zero()], -// } - -// // TODO: same -// #[repr(packed)] -// struct ReprPacked { -// small: u8, -// medium: i32, -// weird: [u64; 0], -// } - -// // TODO: actually, uh,, -// #[repr(align(64))] -// struct ReprAlign { -// field: i32, -// last: [usize; 0], -// } -// #[repr(C, align(64))] -// struct ReprCAlign { -// field: i32, -// last: [usize; 0], -// } +#[allow(clippy::eq_op)] // lmao im impressed +const fn compute_zero() -> usize { + (4 + 6) - (2 * 5) +} +struct UsingFunction { + field: i32, + last: [usize; compute_zero()], +} // #[repr(C)] -// enum DontLintAnonymousStructsFromDesuraging { -// A(u32), -// B(f32, [u64; 0]), -// C { x: u32, y: [u64; 0] }, +// struct ConstParamOk { +// field: i32, +// last: [usize; N] // } -fn main() {} +// struct ConstParamLint { +// field: i32, +// last: [usize; N] +// } + + +// TODO: actually, uh,, +#[repr(packed)] +struct ReprPacked { + small: u8, + medium: i32, + weird: [u64; 0], +} + +// same +#[repr(align(64))] +struct ReprAlign { + field: i32, + last: [usize; 0], +} + +// same +#[repr(C, align(64))] +struct ReprCAlign { + field: i32, + last: [usize; 0], +} + +#[repr(C)] +enum DontLintAnonymousStructsFromDesuraging { + A(u32), + B(f32, [u64; 0]), + C { x: u32, y: [u64; 0] }, +} + +struct LotsOfFields { + f1: u32, + f2: u32, + f3: u32, + f4: u32, + f5: u32, + f6: u32, + f7: u32, + f8: u32, + f9: u32, + f10: u32, + f11: u32, + f12: u32, + f13: u32, + f14: u32, + f15: u32, + f16: u32, + last: [usize; 0], +} + +fn main() { +} From b9948c4be6741ae916b838df29e9777467d4c84c Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sat, 16 Oct 2021 02:26:08 -0700 Subject: [PATCH 059/100] Ran `dev bless`! --- ...railing_zero_sized_array_without_repr_c.rs | 58 ++++----- ...railing_zero_sized_array_without_repr_c.rs | 17 +-- ...ing_zero_sized_array_without_repr_c.stderr | 113 ++++++++++++++++++ 3 files changed, 147 insertions(+), 41 deletions(-) create mode 100644 tests/ui/trailing_zero_sized_array_without_repr_c.stderr diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 7eeb2914c40..7f579835512 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -26,7 +26,7 @@ /// Use instead: /// ```rust /// #[repr(C)] - /// struct MakesSense { + /// struct MoreOftenUseful { /// some_field: usize, /// last: [SomeType; 0], /// } @@ -45,15 +45,13 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - dbg!(item.ident); - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_c(cx, item.def_id) { span_lint_and_sugg( cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, item.span, "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", - "try", + "try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute):", format!("#[repr(C)]\n{}", snippet(cx, item.span, "..")), Applicability::MaybeIncorrect, ); @@ -62,46 +60,40 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { - if let ItemKind::Struct(data, _generics) = &item.kind { - if let VariantData::Struct(field_defs, _) = data { - if let Some(last_field) = field_defs.last() { - if let TyKind::Array(_, aconst) = last_field.ty.kind { - let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); - let ty = cx.tcx.type_of(aconst_def_id); - let constant = cx - .tcx - // NOTE: maybe const_eval_resolve? seems especially cursed to be using a const expr which - // resolves to 0 to create a zero-sized array, tho - .const_eval_poly(aconst_def_id) - .ok() - .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) { - if val == 0 { - // eprintln!("trailing: true"); - return true; - } - } - } - } + if_chain! { + if let ItemKind::Struct(data, _generics) = &item.kind; + if let VariantData::Struct(field_defs, _) = data; + if let Some(last_field) = field_defs.last(); + if let TyKind::Array(_, aconst) = last_field.ty.kind; + let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); + let ty = cx.tcx.type_of(aconst_def_id); + let constant = cx + .tcx + // NOTE: maybe const_eval_resolve? + .const_eval_poly(aconst_def_id) + .ok() + .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); + if let Some(Constant::Int(val)) = constant.and_then(miri_to_const); + if val == 0; + then { + true + } else { + false } } - // dbg!(aconst); - // eprintln!("trailing: false"); - false } fn has_repr_c(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - let attrs = cx.tcx.hir().attrs(hir_id); + let hir_map = cx.tcx.hir(); + let hir_id = hir_map.local_def_id_to_hir_id(def_id); + let attrs = hir_map.attrs(hir_id); // NOTE: Can there ever be more than one `repr` attribute? // other `repr` syms: repr, repr128, repr_align, repr_align_enum, repr_no_niche, repr_packed, // repr_simd, repr_transparent - if let Some(_repr_attr) = attrs.iter().find(|attr| attr.has_name(sym::repr)) { - // eprintln!("repr: true"); + if let Some(_attr) = attrs.iter().find(|attr| attr.has_name(sym::repr)) { true } else { - // eprintln!("repr: false"); false } } diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 311193fb4a1..62fe94d7abf 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -1,6 +1,5 @@ #![warn(clippy::trailing_zero_sized_array_without_repr_c)] - -// #![feature(const_generics_defaults)] +// #![feature(const_generics_defaults)] // see below struct RarelyUseful { field: i32, @@ -48,6 +47,9 @@ struct UsingFunction { last: [usize; compute_zero()], } +// NOTE: including these (along with the required feature) triggers an ICE. Should make sure the +// const generics people are aware of that if they weren't already. + // #[repr(C)] // struct ConstParamOk { // field: i32, @@ -59,8 +61,7 @@ struct UsingFunction { // last: [usize; N] // } - -// TODO: actually, uh,, +// TODO: actually, uh,, no idea what behavior here would be #[repr(packed)] struct ReprPacked { small: u8, @@ -68,20 +69,21 @@ struct ReprPacked { weird: [u64; 0], } -// same +// TODO: clarify expected behavior #[repr(align(64))] struct ReprAlign { field: i32, last: [usize; 0], } -// same +// TODO: clarify expected behavior #[repr(C, align(64))] struct ReprCAlign { field: i32, last: [usize; 0], } +// NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen #[repr(C)] enum DontLintAnonymousStructsFromDesuraging { A(u32), @@ -109,5 +111,4 @@ struct LotsOfFields { last: [usize; 0], } -fn main() { -} +fn main() {} diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.stderr b/tests/ui/trailing_zero_sized_array_without_repr_c.stderr new file mode 100644 index 00000000000..84606ed6185 --- /dev/null +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.stderr @@ -0,0 +1,113 @@ +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:4:1 + | +LL | / struct RarelyUseful { +LL | | field: i32, +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = note: `-D clippy::trailing-zero-sized-array-without-repr-c` implied by `-D warnings` +help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): + | +LL + #[repr(C)] +LL + struct RarelyUseful { +LL + field: i32, +LL + last: [usize; 0], +LL + } + | + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:15:1 + | +LL | / struct OnlyFieldIsZeroSizeArray { +LL | | first_and_last: [usize; 0], +LL | | } + | |_^ + | +help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): + | +LL + #[repr(C)] +LL + struct OnlyFieldIsZeroSizeArray { +LL + first_and_last: [usize; 0], +LL + } + | + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:19:1 + | +LL | / struct GenericArrayType { +LL | | field: i32, +LL | | last: [T; 0], +LL | | } + | |_^ + | +help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): + | +LL + #[repr(C)] +LL + struct GenericArrayType { +LL + field: i32, +LL + last: [T; 0], +LL + } + | + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:30:1 + | +LL | / struct ZeroSizedFromExternalConst { +LL | | field: i32, +LL | | last: [usize; ZERO], +LL | | } + | |_^ + | +help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): + | +LL + #[repr(C)] +LL + struct ZeroSizedFromExternalConst { +LL + field: i32, +LL + last: [usize; ZERO], +LL + } + | + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:45:1 + | +LL | / struct UsingFunction { +LL | | field: i32, +LL | | last: [usize; compute_zero()], +LL | | } + | |_^ + | +help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): + | +LL + #[repr(C)] +LL + struct UsingFunction { +LL + field: i32, +LL + last: [usize; compute_zero()], +LL + } + | + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:94:1 + | +LL | / struct LotsOfFields { +LL | | f1: u32, +LL | | f2: u32, +LL | | f3: u32, +... | +LL | | last: [usize; 0], +LL | | } + | |_^ + | +help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): + | +LL + #[repr(C)] +LL + struct LotsOfFields { +LL + f1: u32, +LL + f2: u32, +LL + f3: u32, +LL + f4: u32, + ... + +error: aborting due to 6 previous errors + From 003972f4281ab83fb56ce9a898efd93b6ca3740e Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sat, 16 Oct 2021 15:26:10 -0700 Subject: [PATCH 060/100] add multiple `get_attrs` and `includes_repr` and they all work! --- clippy_lints/src/lib.rs | 1 + ...railing_zero_sized_array_without_repr_c.rs | 66 +++++++-- ...railing_zero_sized_array_without_repr_c.rs | 139 ++++++++++-------- 3 files changed, 130 insertions(+), 76 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d494892c3b4..72636146d7c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -21,6 +21,7 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 7f579835512..4c3c5191d28 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,10 +1,14 @@ use clippy_utils::consts::{miri_to_const, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use rustc_ast::Attribute; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Item, ItemKind, TyKind, VariantData}; +use rustc_hir::{Item, ItemKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::dep_graph::DepContext; +use rustc_middle::ty as ty_mod; +use rustc_middle::ty::ReprFlags; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -33,19 +37,16 @@ /// ``` pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, nursery, - "struct with a trailing zero-sized array but without `repr(C)`" + "struct with a trailing zero-sized array but without `repr(C)` or another `repr` attribute" } declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C]); -// -// TODO: Register the lint pass in `clippy_lints/src/lib.rs`, -// e.g. store.register_early_pass(|| -// Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); -// DONE! +// TESTNAME=trailing_zero_sized_array_without_repr_c cargo uitest impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_c(cx, item.def_id) { + dbg!(item.ident); + if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.def_id) { span_lint_and_sugg( cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, @@ -64,7 +65,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx if let ItemKind::Struct(data, _generics) = &item.kind; if let VariantData::Struct(field_defs, _) = data; if let Some(last_field) = field_defs.last(); - if let TyKind::Array(_, aconst) = last_field.ty.kind; + if let rustc_hir::TyKind::Array(_, aconst) = last_field.ty.kind; let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); let ty = cx.tcx.type_of(aconst_def_id); let constant = cx @@ -83,17 +84,50 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } } -fn has_repr_c(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { +fn has_repr_attr(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { + let attrs_get_attrs = get_attrs_get_attrs(cx, def_id); + let attrs_hir_map = get_attrs_hir_map(cx, def_id); + let b11 = dbg!(includes_repr_attr_using_sym(attrs_get_attrs)); + let b12 = dbg!(includes_repr_attr_using_sym(attrs_hir_map)); + let b21 = dbg!(includes_repr_attr_using_helper(cx, attrs_get_attrs)); + let b22 = dbg!(includes_repr_attr_using_helper(cx, attrs_hir_map)); + let b3 = dbg!(has_repr_attr_using_adt(cx, def_id)); + let all_same = b11 && b12 && b21 && b22 && b3; + dbg!(all_same); + + b11 +} + +fn get_attrs_get_attrs(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attribute] { + cx.tcx.get_attrs(def_id.to_def_id()) +} + +fn get_attrs_hir_map(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attribute] { let hir_map = cx.tcx.hir(); let hir_id = hir_map.local_def_id_to_hir_id(def_id); - let attrs = hir_map.attrs(hir_id); + hir_map.attrs(hir_id) +} - // NOTE: Can there ever be more than one `repr` attribute? - // other `repr` syms: repr, repr128, repr_align, repr_align_enum, repr_no_niche, repr_packed, - // repr_simd, repr_transparent - if let Some(_attr) = attrs.iter().find(|attr| attr.has_name(sym::repr)) { - true +// Don't like this because it's so dependent on the current list of `repr` flags and it would have to be manually updated if that ever expanded. idk if there's any mechanism in `bitflag!` or elsewhere for requiring that sort of exhaustiveness +fn has_repr_attr_using_adt(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { + let ty = cx.tcx.type_of(def_id.to_def_id()); + if let ty_mod::Adt(adt, _) = ty.kind() { + if adt.is_struct() { + let repr = adt.repr; + let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR; + repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr) + } else { + false + } } else { false } } + +fn includes_repr_attr_using_sym(attrs: &'tcx [Attribute]) -> bool { + attrs.iter().any(|attr| attr.has_name(sym::repr)) +} + +fn includes_repr_attr_using_helper(cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) -> bool { + attrs.iter().any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty()) +} diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 62fe94d7abf..8e8c84fe9c5 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -1,13 +1,9 @@ #![warn(clippy::trailing_zero_sized_array_without_repr_c)] // #![feature(const_generics_defaults)] // see below -struct RarelyUseful { - field: i32, - last: [usize; 0], -} +// Do lint: -#[repr(C)] -struct GoodReason { +struct RarelyUseful { field: i32, last: [usize; 0], } @@ -21,9 +17,16 @@ struct GenericArrayType { last: [T; 0], } -struct SizedArray { +#[derive(Debug)] +struct PlayNiceWithOtherAttributesDerive { field: i32, - last: [usize; 1], + last: [usize; 0] +} + +#[must_use] +struct PlayNiceWithOtherAttributesMustUse { + field: i32, + last: [usize; 0] } const ZERO: usize = 0; @@ -32,13 +35,7 @@ struct ZeroSizedFromExternalConst { last: [usize; ZERO], } -const ONE: usize = 1; -struct NonZeroSizedFromExternalConst { - field: i32, - last: [usize; ONE], -} - -#[allow(clippy::eq_op)] // lmao im impressed +#[allow(clippy::eq_op)] const fn compute_zero() -> usize { (4 + 6) - (2 * 5) } @@ -47,50 +44,6 @@ struct UsingFunction { last: [usize; compute_zero()], } -// NOTE: including these (along with the required feature) triggers an ICE. Should make sure the -// const generics people are aware of that if they weren't already. - -// #[repr(C)] -// struct ConstParamOk { -// field: i32, -// last: [usize; N] -// } - -// struct ConstParamLint { -// field: i32, -// last: [usize; N] -// } - -// TODO: actually, uh,, no idea what behavior here would be -#[repr(packed)] -struct ReprPacked { - small: u8, - medium: i32, - weird: [u64; 0], -} - -// TODO: clarify expected behavior -#[repr(align(64))] -struct ReprAlign { - field: i32, - last: [usize; 0], -} - -// TODO: clarify expected behavior -#[repr(C, align(64))] -struct ReprCAlign { - field: i32, - last: [usize; 0], -} - -// NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen -#[repr(C)] -enum DontLintAnonymousStructsFromDesuraging { - A(u32), - B(f32, [u64; 0]), - C { x: u32, y: [u64; 0] }, -} - struct LotsOfFields { f1: u32, f2: u32, @@ -111,4 +64,70 @@ struct LotsOfFields { last: [usize; 0], } -fn main() {} +// Don't lint + +#[repr(C)] +struct GoodReason { + field: i32, + last: [usize; 0], +} + +struct SizedArray { + field: i32, + last: [usize; 1], +} + +const ONE: usize = 1; +struct NonZeroSizedFromExternalConst { + field: i32, + last: [usize; ONE], +} + +#[repr(packed)] +struct ReprPacked { + field: i32, + last: [usize; 0], +} + +#[repr(C, packed)] +struct ReprCPacked { + field: i32, + last: [usize; 0], +} + +#[repr(align(64))] +struct ReprAlign { + field: i32, + last: [usize; 0], +} +#[repr(C, align(64))] +struct ReprCAlign { + field: i32, + last: [usize; 0], +} + +// NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen +#[repr(C)] +enum DontLintAnonymousStructsFromDesuraging { + A(u32), + B(f32, [u64; 0]), + C { x: u32, y: [u64; 0] }, +} + +// NOTE: including these (along with the required feature) triggers an ICE. Should make sure the +// const generics people are aware of that if they weren't already. + +// #[repr(C)] +// struct ConstParamOk { +// field: i32, +// last: [usize; N] +// } + +// struct ConstParamLint { +// field: i32, +// last: [usize; N] +// } + +fn main() { + let _ = PlayNiceWithOtherAttributesMustUse {field: 0, last: []}; +} From 5fdf93415bfd59a7cd61ebec20f0a4e4fec78164 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sat, 16 Oct 2021 16:13:14 -0700 Subject: [PATCH 061/100] intermediate step --- ...railing_zero_sized_array_without_repr_c.rs | 45 ++++++++++--------- ...railing_zero_sized_array_without_repr_c.rs | 14 +++--- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 4c3c5191d28..a9c6e24918e 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,8 +1,6 @@ use clippy_utils::consts::{miri_to_const, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::Attribute; -use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Item, ItemKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; @@ -47,15 +45,15 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { dbg!(item.ident); if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.def_id) { - span_lint_and_sugg( - cx, - TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, - item.span, - "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", - "try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute):", - format!("#[repr(C)]\n{}", snippet(cx, item.span, "..")), - Applicability::MaybeIncorrect, - ); + // span_lint_and_help( + // cx, + // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, + // item.span, + // "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", + // None, + // "consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute)", + // ); + eprintln!("— consider yourself linted — 🦀") } } } @@ -87,15 +85,16 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx fn has_repr_attr(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { let attrs_get_attrs = get_attrs_get_attrs(cx, def_id); let attrs_hir_map = get_attrs_hir_map(cx, def_id); - let b11 = dbg!(includes_repr_attr_using_sym(attrs_get_attrs)); - let b12 = dbg!(includes_repr_attr_using_sym(attrs_hir_map)); - let b21 = dbg!(includes_repr_attr_using_helper(cx, attrs_get_attrs)); - let b22 = dbg!(includes_repr_attr_using_helper(cx, attrs_hir_map)); - let b3 = dbg!(has_repr_attr_using_adt(cx, def_id)); - let all_same = b11 && b12 && b21 && b22 && b3; + + let b11 = includes_repr_attr_using_sym(attrs_get_attrs); + let b12 = includes_repr_attr_using_sym(attrs_hir_map); + let b21 = includes_repr_attr_using_helper(cx, attrs_get_attrs); + let b22 = includes_repr_attr_using_helper(cx, attrs_hir_map); + let b3 = has_repr_attr_using_adt(cx, def_id); + let all_same = (b11 && b12 && b21 && b22 && b3) || (!b11 && !b12 && !b21 && !b22 && !b3); dbg!(all_same); - b11 + b21 } fn get_attrs_get_attrs(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attribute] { @@ -108,7 +107,9 @@ fn get_attrs_hir_map(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attri hir_map.attrs(hir_id) } -// Don't like this because it's so dependent on the current list of `repr` flags and it would have to be manually updated if that ever expanded. idk if there's any mechanism in `bitflag!` or elsewhere for requiring that sort of exhaustiveness +// Don't like this because it's so dependent on the current list of `repr` flags and it would have +// to be manually updated if that ever expanded. idk if there's any mechanism in `bitflag!` or +// elsewhere for requiring that sort of exhaustiveness fn has_repr_attr_using_adt(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { let ty = cx.tcx.type_of(def_id.to_def_id()); if let ty_mod::Adt(adt, _) = ty.kind() { @@ -129,5 +130,7 @@ fn includes_repr_attr_using_sym(attrs: &'tcx [Attribute]) -> bool { } fn includes_repr_attr_using_helper(cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) -> bool { - attrs.iter().any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty()) + attrs + .iter() + .any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty()) } diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 8e8c84fe9c5..07cba5774a5 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -1,5 +1,5 @@ #![warn(clippy::trailing_zero_sized_array_without_repr_c)] -// #![feature(const_generics_defaults)] // see below +#![feature(const_generics_defaults)] // see below // Do lint: @@ -20,13 +20,13 @@ struct GenericArrayType { #[derive(Debug)] struct PlayNiceWithOtherAttributesDerive { field: i32, - last: [usize; 0] + last: [usize; 0], } #[must_use] struct PlayNiceWithOtherAttributesMustUse { field: i32, - last: [usize; 0] + last: [usize; 0], } const ZERO: usize = 0; @@ -72,7 +72,7 @@ struct GoodReason { last: [usize; 0], } -struct SizedArray { +struct NonZeroSizedArray { field: i32, last: [usize; 1], } @@ -114,8 +114,8 @@ enum DontLintAnonymousStructsFromDesuraging { C { x: u32, y: [u64; 0] }, } -// NOTE: including these (along with the required feature) triggers an ICE. Should make sure the -// const generics people are aware of that if they weren't already. +// NOTE: including these (along with the required feature) triggers an ICE. Not sure why. Should +// make sure the const generics people are aware of that if they weren't already. // #[repr(C)] // struct ConstParamOk { @@ -129,5 +129,5 @@ enum DontLintAnonymousStructsFromDesuraging { // } fn main() { - let _ = PlayNiceWithOtherAttributesMustUse {field: 0, last: []}; + let _ = PlayNiceWithOtherAttributesMustUse { field: 0, last: [] }; } From 9b3f55ee61e781ef3360ddfaa436746bb7e40df5 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sat, 16 Oct 2021 17:49:13 -0700 Subject: [PATCH 062/100] tried to simplify but it doesn't work :/ --- ...railing_zero_sized_array_without_repr_c.rs | 109 ++++++------------ ...railing_zero_sized_array_without_repr_c.rs | 34 ++++-- 2 files changed, 61 insertions(+), 82 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index a9c6e24918e..913812126a9 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,14 +1,11 @@ use clippy_utils::consts::{miri_to_const, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::Attribute; -use rustc_hir::def_id::LocalDefId; use rustc_hir::{Item, ItemKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty as ty_mod; -use rustc_middle::ty::ReprFlags; +use rustc_middle::ty::Const; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -43,37 +40,44 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - dbg!(item.ident); - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.def_id) { - // span_lint_and_help( - // cx, - // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, - // item.span, - // "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", - // None, - // "consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute)", - // ); - eprintln!("— consider yourself linted — 🦀") + if is_struct_with_trailing_zero_sized_array(cx, item) { + let attrs = cx.tcx.get_attrs(item.def_id.to_def_id()); + let first_attr = attrs.first(); // Actually, I've no idea if this is guaranteed to be the first one in the source code. + + let lint_span = if let Some(first_attr) = first_attr { + first_attr.span.until(item.span) + } else { + item.span + }; + + if !has_repr_attr(cx, attrs) { + span_lint_and_help( + cx, + TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, + lint_span, + "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", + None, + "consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute)", + ); + } } } } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { if_chain! { - if let ItemKind::Struct(data, _generics) = &item.kind; + // Check if last field is an array + if let ItemKind::Struct(data, _) = &item.kind; if let VariantData::Struct(field_defs, _) = data; if let Some(last_field) = field_defs.last(); - if let rustc_hir::TyKind::Array(_, aconst) = last_field.ty.kind; - let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); - let ty = cx.tcx.type_of(aconst_def_id); - let constant = cx - .tcx - // NOTE: maybe const_eval_resolve? - .const_eval_poly(aconst_def_id) - .ok() - .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(miri_to_const); - if val == 0; + if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind; + + // Check if that that array zero-sized. + let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); + let length = Const::from_anon_const(cx.tcx, length_ldid); + if let Some(Constant::Int(length)) = miri_to_const(length); + if length == 0; + then { true } else { @@ -82,54 +86,9 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } } -fn has_repr_attr(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { - let attrs_get_attrs = get_attrs_get_attrs(cx, def_id); - let attrs_hir_map = get_attrs_hir_map(cx, def_id); - - let b11 = includes_repr_attr_using_sym(attrs_get_attrs); - let b12 = includes_repr_attr_using_sym(attrs_hir_map); - let b21 = includes_repr_attr_using_helper(cx, attrs_get_attrs); - let b22 = includes_repr_attr_using_helper(cx, attrs_hir_map); - let b3 = has_repr_attr_using_adt(cx, def_id); - let all_same = (b11 && b12 && b21 && b22 && b3) || (!b11 && !b12 && !b21 && !b22 && !b3); - dbg!(all_same); - - b21 -} - -fn get_attrs_get_attrs(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attribute] { - cx.tcx.get_attrs(def_id.to_def_id()) -} - -fn get_attrs_hir_map(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attribute] { - let hir_map = cx.tcx.hir(); - let hir_id = hir_map.local_def_id_to_hir_id(def_id); - hir_map.attrs(hir_id) -} - -// Don't like this because it's so dependent on the current list of `repr` flags and it would have -// to be manually updated if that ever expanded. idk if there's any mechanism in `bitflag!` or -// elsewhere for requiring that sort of exhaustiveness -fn has_repr_attr_using_adt(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool { - let ty = cx.tcx.type_of(def_id.to_def_id()); - if let ty_mod::Adt(adt, _) = ty.kind() { - if adt.is_struct() { - let repr = adt.repr; - let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR; - repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr) - } else { - false - } - } else { - false - } -} - -fn includes_repr_attr_using_sym(attrs: &'tcx [Attribute]) -> bool { - attrs.iter().any(|attr| attr.has_name(sym::repr)) -} - -fn includes_repr_attr_using_helper(cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) -> bool { +fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool { + // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed + // on all testcases.) Happy to use another; they're in the commit history. attrs .iter() .any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty()) diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 07cba5774a5..6ab96c2ebf6 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -8,7 +8,7 @@ struct RarelyUseful { last: [usize; 0], } -struct OnlyFieldIsZeroSizeArray { +struct OnlyField { first_and_last: [usize; 0], } @@ -18,19 +18,19 @@ struct GenericArrayType { } #[derive(Debug)] -struct PlayNiceWithOtherAttributesDerive { +struct OnlyAnotherAttributeDerive { field: i32, last: [usize; 0], } #[must_use] -struct PlayNiceWithOtherAttributesMustUse { +struct OnlyAnotherAttributeMustUse { field: i32, last: [usize; 0], } const ZERO: usize = 0; -struct ZeroSizedFromExternalConst { +struct ZeroSizedWithConst { field: i32, last: [usize; ZERO], } @@ -39,7 +39,7 @@ struct ZeroSizedFromExternalConst { const fn compute_zero() -> usize { (4 + 6) - (2 * 5) } -struct UsingFunction { +struct ZeroSizedWithConstFunction { field: i32, last: [usize; compute_zero()], } @@ -72,17 +72,36 @@ struct GoodReason { last: [usize; 0], } +#[repr(C)] +struct OnlyFieldWithReprC { + first_and_last: [usize; 0], +} + struct NonZeroSizedArray { field: i32, last: [usize; 1], } const ONE: usize = 1; -struct NonZeroSizedFromExternalConst { +struct NonZeroSizedWithConst { field: i32, last: [usize; ONE], } +#[derive(Debug)] +#[repr(C)] +struct OtherAttributesDerive { + field: i32, + last: [usize; 0], +} + +#[must_use] +#[repr(C)] +struct OtherAttributesMustUse { + field: i32, + last: [usize; 0], +} + #[repr(packed)] struct ReprPacked { field: i32, @@ -129,5 +148,6 @@ enum DontLintAnonymousStructsFromDesuraging { // } fn main() { - let _ = PlayNiceWithOtherAttributesMustUse { field: 0, last: [] }; + let _ = OnlyAnotherAttributeMustUse { field: 0, last: [] }; + let _ = OtherAttributesMustUse { field: 0, last: [] }; } From a3420f70043c19165a4e44639ef4e6f3c156a174 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sat, 16 Oct 2021 22:03:08 -0700 Subject: [PATCH 063/100] Tidy comments + tests; revert 'size-is-zero' detection --- ...railing_zero_sized_array_without_repr_c.rs | 35 ++++--- ...railing_zero_sized_array_without_repr_c.rs | 36 +++---- ...ing_zero_sized_array_without_repr_c.stderr | 97 ++++++++----------- 3 files changed, 75 insertions(+), 93 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 913812126a9..bc055307d5e 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -36,16 +36,15 @@ } declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C]); -// TESTNAME=trailing_zero_sized_array_without_repr_c cargo uitest - impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if is_struct_with_trailing_zero_sized_array(cx, item) { + // NOTE: This is to include attributes on the definition when we print the lint. If the convention + // is to not do that with struct definitions (I'm not sure), then this isn't necessary. let attrs = cx.tcx.get_attrs(item.def_id.to_def_id()); - let first_attr = attrs.first(); // Actually, I've no idea if this is guaranteed to be the first one in the source code. - + let first_attr = attrs.iter().min_by_key(|attr| attr.span.lo()); let lint_span = if let Some(first_attr) = first_attr { - first_attr.span.until(item.span) + first_attr.span.to(item.span) } else { item.span }; @@ -66,18 +65,29 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { if_chain! { - // Check if last field is an array + // First check if last field is an array if let ItemKind::Struct(data, _) = &item.kind; if let VariantData::Struct(field_defs, _) = data; if let Some(last_field) = field_defs.last(); if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind; - // Check if that that array zero-sized. - let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); - let length = Const::from_anon_const(cx.tcx, length_ldid); - if let Some(Constant::Int(length)) = miri_to_const(length); - if length == 0; + // Then check if that that array zero-sized + // This is pretty much copied from `enum_clike.rs` and I don't fully understand it, so let me know + // if there's a better way. I tried `Const::from_anon_const` but it didn't fold in the values + // on the `ZeroSizedWithConst` and `ZeroSizedWithConstFunction` tests. + + // This line in particular seems convoluted. + let length_did = cx.tcx.hir().body_owner_def_id(length.body).to_def_id(); + let length_ty = cx.tcx.type_of(length_did); + let length = cx + .tcx + .const_eval_poly(length_did) + .ok() + .map(|val| Const::from_value(cx.tcx, val, length_ty)) + .and_then(miri_to_const); + if let Some(Constant::Int(length)) = length; + if length == 0; then { true } else { @@ -88,7 +98,8 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool { // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed - // on all testcases.) Happy to use another; they're in the commit history. + // on all testcases.) Happy to use another; they're in the commit history if you want to look (or I + // can go find them). attrs .iter() .any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty()) diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 6ab96c2ebf6..77b2c29b275 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -1,5 +1,4 @@ #![warn(clippy::trailing_zero_sized_array_without_repr_c)] -#![feature(const_generics_defaults)] // see below // Do lint: @@ -17,14 +16,16 @@ struct GenericArrayType { last: [T; 0], } -#[derive(Debug)] -struct OnlyAnotherAttributeDerive { +#[must_use] +struct OnlyAnotherAttributeMustUse { field: i32, last: [usize; 0], } -#[must_use] -struct OnlyAnotherAttributeMustUse { +// NOTE: Unfortunately the attribute isn't included in the lint output. I'm not sure how to make it +// show up. +#[derive(Debug)] +struct OnlyAnotherAttributeDerive { field: i32, last: [usize; 0], } @@ -82,6 +83,12 @@ struct NonZeroSizedArray { last: [usize; 1], } +struct NotLastField { + f1: u32, + zero_sized: [usize; 0], + last: i32, +} + const ONE: usize = 1; struct NonZeroSizedWithConst { field: i32, @@ -133,21 +140,4 @@ enum DontLintAnonymousStructsFromDesuraging { C { x: u32, y: [u64; 0] }, } -// NOTE: including these (along with the required feature) triggers an ICE. Not sure why. Should -// make sure the const generics people are aware of that if they weren't already. - -// #[repr(C)] -// struct ConstParamOk { -// field: i32, -// last: [usize; N] -// } - -// struct ConstParamLint { -// field: i32, -// last: [usize; N] -// } - -fn main() { - let _ = OnlyAnotherAttributeMustUse { field: 0, last: [] }; - let _ = OtherAttributesMustUse { field: 0, last: [] }; -} +fn main() {} diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.stderr b/tests/ui/trailing_zero_sized_array_without_repr_c.stderr index 84606ed6185..ee8182cdc38 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.stderr +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.stderr @@ -1,5 +1,5 @@ error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:4:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:5:1 | LL | / struct RarelyUseful { LL | | field: i32, @@ -8,33 +8,20 @@ LL | | } | |_^ | = note: `-D clippy::trailing-zero-sized-array-without-repr-c` implied by `-D warnings` -help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): - | -LL + #[repr(C)] -LL + struct RarelyUseful { -LL + field: i32, -LL + last: [usize; 0], -LL + } - | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:15:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:10:1 | -LL | / struct OnlyFieldIsZeroSizeArray { +LL | / struct OnlyField { LL | | first_and_last: [usize; 0], LL | | } | |_^ | -help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): - | -LL + #[repr(C)] -LL + struct OnlyFieldIsZeroSizeArray { -LL + first_and_last: [usize; 0], -LL + } - | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:19:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:14:1 | LL | / struct GenericArrayType { LL | | field: i32, @@ -42,53 +29,55 @@ LL | | last: [T; 0], LL | | } | |_^ | -help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): - | -LL + #[repr(C)] -LL + struct GenericArrayType { -LL + field: i32, -LL + last: [T; 0], -LL + } - | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:30:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:19:1 | -LL | / struct ZeroSizedFromExternalConst { +LL | / #[must_use] +LL | | struct OnlyAnotherAttributeMustUse { +LL | | field: i32, +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:28:1 + | +LL | / struct OnlyAnotherAttributeDerive { +LL | | field: i32, +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:34:1 + | +LL | / struct ZeroSizedWithConst { LL | | field: i32, LL | | last: [usize; ZERO], LL | | } | |_^ | -help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): - | -LL + #[repr(C)] -LL + struct ZeroSizedFromExternalConst { -LL + field: i32, -LL + last: [usize; ZERO], -LL + } - | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:45:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:43:1 | -LL | / struct UsingFunction { +LL | / struct ZeroSizedWithConstFunction { LL | | field: i32, LL | | last: [usize; compute_zero()], LL | | } | |_^ | -help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): - | -LL + #[repr(C)] -LL + struct UsingFunction { -LL + field: i32, -LL + last: [usize; compute_zero()], -LL + } - | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:94:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:48:1 | LL | / struct LotsOfFields { LL | | f1: u32, @@ -99,15 +88,7 @@ LL | | last: [usize; 0], LL | | } | |_^ | -help: try annotating the struct definition with `#[repr(C)]` (or another `repr` attribute): - | -LL + #[repr(C)] -LL + struct LotsOfFields { -LL + f1: u32, -LL + f2: u32, -LL + f3: u32, -LL + f4: u32, - ... + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors From c5d3167a23e7f1f6515a28ff15a6698b6712ae54 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Sun, 17 Oct 2021 17:28:45 -0700 Subject: [PATCH 064/100] update testsuite and expand `if_chain` --- ...railing_zero_sized_array_without_repr_c.rs | 55 +++++++++++-------- ...railing_zero_sized_array_without_repr_c.rs | 32 +++++++++++ 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index bc055307d5e..de2513244da 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -64,35 +64,42 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { - if_chain! { - // First check if last field is an array - if let ItemKind::Struct(data, _) = &item.kind; - if let VariantData::Struct(field_defs, _) = data; - if let Some(last_field) = field_defs.last(); - if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind; + // First check if last field is an array + if let ItemKind::Struct(data, _) = &item.kind { + if let VariantData::Struct(field_defs, _) = data { + if let Some(last_field) = field_defs.last() { + if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { + // Then check if that that array zero-sized - // Then check if that that array zero-sized + // This is pretty much copied from `enum_clike.rs` and I don't fully understand it, so let me know + // if there's a better way. I tried `Const::from_anon_const` but it didn't fold in the values + // on the `ZeroSizedWithConst` and `ZeroSizedWithConstFunction` tests. - // This is pretty much copied from `enum_clike.rs` and I don't fully understand it, so let me know - // if there's a better way. I tried `Const::from_anon_const` but it didn't fold in the values - // on the `ZeroSizedWithConst` and `ZeroSizedWithConstFunction` tests. - - // This line in particular seems convoluted. - let length_did = cx.tcx.hir().body_owner_def_id(length.body).to_def_id(); - let length_ty = cx.tcx.type_of(length_did); - let length = cx - .tcx - .const_eval_poly(length_did) - .ok() - .map(|val| Const::from_value(cx.tcx, val, length_ty)) - .and_then(miri_to_const); - if let Some(Constant::Int(length)) = length; - if length == 0; - then { - true + // This line in particular seems convoluted. + let length_did = cx.tcx.hir().body_owner_def_id(length.body).to_def_id(); + let length_ty = cx.tcx.type_of(length_did); + let length = cx + .tcx + .const_eval_poly(length_did) + .ok() + .map(|val| Const::from_value(cx.tcx, val, length_ty)) + .and_then(miri_to_const); + if let Some(Constant::Int(length)) = length { + length == 0 + } else { + false + } + } else { + false + } + } else { + false + } } else { false } + } else { + false } } diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 77b2c29b275..c6ee36e9685 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -1,4 +1,5 @@ #![warn(clippy::trailing_zero_sized_array_without_repr_c)] +#![feature(const_generics_defaults)] // Do lint: @@ -45,6 +46,10 @@ struct ZeroSizedWithConstFunction { last: [usize; compute_zero()], } +struct ZeroSizedArrayWrapper([usize; 0]); + +struct TupleStruct(i32, [usize; 0]); + struct LotsOfFields { f1: u32, f2: u32, @@ -140,4 +145,31 @@ enum DontLintAnonymousStructsFromDesuraging { C { x: u32, y: [u64; 0] }, } +#[repr(C)] +struct TupleStructReprC(i32, [usize; 0]); + +type NamedTuple = (i32, [usize; 0]); + +#[rustfmt::skip] // [rustfmt#4995](https://github.com/rust-lang/rustfmt/issues/4995) +struct ConstParamZeroDefault { + field: i32, + last: [usize; N], +} + +struct ConstParamNoDefault { + field: i32, + last: [usize; N], +} + +#[rustfmt::skip] +struct ConstParamNonZeroDefault { + field: i32, + last: [usize; N], +} + +type A = ConstParamZeroDefault; +type B = ConstParamZeroDefault<0>; +type C = ConstParamNoDefault<0>; +type D = ConstParamNonZeroDefault<0>; + fn main() {} From 2a5a4f07cf34895cf6d3c6f8843169e3d6d9c46d Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 00:51:30 -0700 Subject: [PATCH 065/100] =?UTF-8?q?Refactor=20ZS=20array=20detection=20aga?= =?UTF-8?q?in=20and=20this=20one=20seems=20great=20=F0=9F=91=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...railing_zero_sized_array_without_repr_c.rs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index de2513244da..d68ad901704 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{miri_to_const, Constant}; +use clippy_utils::consts::{constant, miri_to_const, ConstEvalLateContext, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::Attribute; use rustc_hir::{Item, ItemKind, VariantData}; @@ -38,9 +38,11 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + dbg!(item.ident); if is_struct_with_trailing_zero_sized_array(cx, item) { // NOTE: This is to include attributes on the definition when we print the lint. If the convention - // is to not do that with struct definitions (I'm not sure), then this isn't necessary. + // is to not do that with struct definitions (I'm not sure), then this isn't necessary. (note: if + // you don't get rid of this, change `has_repr_attr` to `includes_repr_attr`). let attrs = cx.tcx.get_attrs(item.def_id.to_def_id()); let first_attr = attrs.iter().min_by_key(|attr| attr.span.lo()); let lint_span = if let Some(first_attr) = first_attr { @@ -70,21 +72,11 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx if let Some(last_field) = field_defs.last() { if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { // Then check if that that array zero-sized - - // This is pretty much copied from `enum_clike.rs` and I don't fully understand it, so let me know - // if there's a better way. I tried `Const::from_anon_const` but it didn't fold in the values - // on the `ZeroSizedWithConst` and `ZeroSizedWithConstFunction` tests. - - // This line in particular seems convoluted. - let length_did = cx.tcx.hir().body_owner_def_id(length.body).to_def_id(); - let length_ty = cx.tcx.type_of(length_did); - let length = cx - .tcx - .const_eval_poly(length_did) - .ok() - .map(|val| Const::from_value(cx.tcx, val, length_ty)) - .and_then(miri_to_const); - if let Some(Constant::Int(length)) = length { + let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); + let length = Const::from_anon_const(cx.tcx, length_ldid); + let length = length.try_eval_usize(cx.tcx, cx.param_env); + // if let Some((Constant::Int(length), _)) = length { + if let Some(length) = length { length == 0 } else { false From 9f402b370c43f8cbad15d477d29aa96ff9746de5 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:03:48 -0700 Subject: [PATCH 066/100] Check for tuple structs --- ...railing_zero_sized_array_without_repr_c.rs | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index d68ad901704..9373551db15 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -38,7 +38,6 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - dbg!(item.ident); if is_struct_with_trailing_zero_sized_array(cx, item) { // NOTE: This is to include attributes on the definition when we print the lint. If the convention // is to not do that with struct definitions (I'm not sure), then this isn't necessary. (note: if @@ -66,24 +65,18 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { + // TODO: when finalized, replace with an `if_chain`. I have it like this because my rust-analyzer doesn't work when it's an `if_chain` // First check if last field is an array if let ItemKind::Struct(data, _) = &item.kind { - if let VariantData::Struct(field_defs, _) = data { - if let Some(last_field) = field_defs.last() { - if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { - // Then check if that that array zero-sized - let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); - let length = Const::from_anon_const(cx.tcx, length_ldid); - let length = length.try_eval_usize(cx.tcx, cx.param_env); - // if let Some((Constant::Int(length), _)) = length { - if let Some(length) = length { - length == 0 - } else { - false - } - } else { - false - } + let field_defs = data.fields(); + if let Some(last_field) = field_defs.last() { + if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { + // Then check if that that array zero-sized + let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); + let length = Const::from_anon_const(cx.tcx, length_ldid); + let length = length.try_eval_usize(cx.tcx, cx.param_env); + // if let Some((Constant::Int(length), _)) = length { + if let Some(length) = length { length == 0 } else { false } } else { false } From cd6862283ee603432f509510c53f35bda12e3a5a Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:04:50 -0700 Subject: [PATCH 067/100] Tidy imports --- .../src/trailing_zero_sized_array_without_repr_c.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index 9373551db15..a759fff9cfc 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,7 +1,7 @@ -use clippy_utils::consts::{constant, miri_to_const, ConstEvalLateContext, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::Attribute; -use rustc_hir::{Item, ItemKind, VariantData}; +use rustc_hir::VariantData; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::Const; @@ -65,8 +65,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { - // TODO: when finalized, replace with an `if_chain`. I have it like this because my rust-analyzer doesn't work when it's an `if_chain` - // First check if last field is an array + // TODO: when finalized, replace with an `if_chain`. I have it like this because my rust-analyzer + // doesn't work when it's an `if_chain` First check if last field is an array if let ItemKind::Struct(data, _) = &item.kind { let field_defs = data.fields(); if let Some(last_field) = field_defs.last() { From 6377fb2fe71a8bde91a20fbadc93242e19fd0dee Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:13:48 -0700 Subject: [PATCH 068/100] Tidy import + update expected stderr --- ...railing_zero_sized_array_without_repr_c.rs | 3 +- ...ing_zero_sized_array_without_repr_c.stderr | 34 ++++++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index a759fff9cfc..aea2fb208df 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,6 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::Attribute; -use rustc_hir::VariantData; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::dep_graph::DepContext; @@ -90,7 +89,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool { // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed - // on all testcases.) Happy to use another; they're in the commit history if you want to look (or I + // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another; they're in the commit history if you want to look (or I // can go find them). attrs .iter() diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.stderr b/tests/ui/trailing_zero_sized_array_without_repr_c.stderr index ee8182cdc38..5ed91e937d5 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.stderr +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.stderr @@ -1,5 +1,5 @@ error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:5:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:6:1 | LL | / struct RarelyUseful { LL | | field: i32, @@ -11,7 +11,7 @@ LL | | } = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:10:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:11:1 | LL | / struct OnlyField { LL | | first_and_last: [usize; 0], @@ -21,7 +21,7 @@ LL | | } = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:14:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:15:1 | LL | / struct GenericArrayType { LL | | field: i32, @@ -32,7 +32,7 @@ LL | | } = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:19:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:20:1 | LL | / #[must_use] LL | | struct OnlyAnotherAttributeMustUse { @@ -44,7 +44,7 @@ LL | | } = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:28:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:29:1 | LL | / struct OnlyAnotherAttributeDerive { LL | | field: i32, @@ -55,7 +55,7 @@ LL | | } = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:34:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:35:1 | LL | / struct ZeroSizedWithConst { LL | | field: i32, @@ -66,7 +66,7 @@ LL | | } = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:43:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:44:1 | LL | / struct ZeroSizedWithConstFunction { LL | | field: i32, @@ -77,7 +77,23 @@ LL | | } = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:48:1 + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:49:1 + | +LL | struct ZeroSizedArrayWrapper([usize; 0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:51:1 + | +LL | struct TupleStruct(i32, [usize; 0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) + +error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` + --> $DIR/trailing_zero_sized_array_without_repr_c.rs:53:1 | LL | / struct LotsOfFields { LL | | f1: u32, @@ -90,5 +106,5 @@ LL | | } | = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors From 149b3728732169cbd6684dfb5e17242924a506a7 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:16:10 -0700 Subject: [PATCH 069/100] run rustfmt --- clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index aea2fb208df..6cba18146b1 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -89,8 +89,8 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool { // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed - // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another; they're in the commit history if you want to look (or I - // can go find them). + // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another; + // they're in the commit history if you want to look (or I can go find them). attrs .iter() .any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty()) From 7f84e3d791846fb462eb39d05bbec029b68d97af Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:45:08 -0700 Subject: [PATCH 070/100] Rename lint --- CHANGELOG.md | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_nursery.rs | 2 +- clippy_lints/src/lib.rs | 4 ++-- ...trailing_zero_sized_array_without_repr.rs} | 22 +++++++++---------- ...trailing_zero_sized_array_without_repr.rs} | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) rename clippy_lints/src/{trailing_zero_sized_array_without_repr_c.rs => trailing_zero_sized_array_without_repr.rs} (81%) rename tests/ui/{trailing_zero_sized_array_without_repr_c.rs => trailing_zero_sized_array_without_repr.rs} (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index a124bebe924..0cf19a6f0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3021,7 +3021,7 @@ Released 2018-09-13 [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg -[`trailing_zero_sized_array_without_repr_c`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_zero_sized_array_without_repr_c +[`trailing_zero_sized_array_without_repr`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_zero_sized_array_without_repr [`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds [`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str [`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 34b87002fa3..af0629beb36 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -443,7 +443,7 @@ temporary_assignment::TEMPORARY_ASSIGNMENT, to_digit_is_some::TO_DIGIT_IS_SOME, to_string_in_display::TO_STRING_IN_DISPLAY, - trailing_zero_sized_array_without_repr_c::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, + trailing_zero_sized_array_without_repr::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 325706746db..eab0e5b90f1 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -25,7 +25,7 @@ LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), - LintId::of(trailing_zero_sized_array_without_repr_c::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C), + LintId::of(trailing_zero_sized_array_without_repr::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(use_self::USE_SELF), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 72636146d7c..1473a2f3095 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -356,7 +356,7 @@ macro_rules! declare_clippy_lint { mod temporary_assignment; mod to_digit_is_some; mod to_string_in_display; -mod trailing_zero_sized_array_without_repr_c; +mod trailing_zero_sized_array_without_repr; mod trait_bounds; mod transmute; mod transmuting_null; @@ -779,7 +779,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); store.register_late_pass(move || Box::new(format_args::FormatArgs)); - store.register_late_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); + store.register_late_pass(|| Box::new(trailing_zero_sized_array_without_repr::TrailingZeroSizedArrayWithoutRepr)); } diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs similarity index 81% rename from clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs rename to clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 6cba18146b1..0267f7bdf0e 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -8,10 +8,10 @@ declare_clippy_lint! { /// ### What it does - /// Displays a warning when a struct with a trailing zero-sized array is declared without the `repr(C)` attribute. + /// Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute. /// /// ### Why is this bad? - /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code (or in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` is needed. + /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed. /// /// ### Example /// ```rust @@ -29,13 +29,13 @@ /// last: [SomeType; 0], /// } /// ``` - pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, + pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, nursery, "struct with a trailing zero-sized array but without `repr(C)` or another `repr` attribute" } -declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C]); +declare_lint_pass!(TrailingZeroSizedArrayWithoutRepr => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR]); -impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { +impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if is_struct_with_trailing_zero_sized_array(cx, item) { // NOTE: This is to include attributes on the definition when we print the lint. If the convention @@ -52,7 +52,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if !has_repr_attr(cx, attrs) { span_lint_and_help( cx, - TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C, + TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, lint_span, "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", None, @@ -65,17 +65,17 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { // TODO: when finalized, replace with an `if_chain`. I have it like this because my rust-analyzer - // doesn't work when it's an `if_chain` First check if last field is an array + // doesn't work when it's an `if_chain`. + + // First check if last field is an array if let ItemKind::Struct(data, _) = &item.kind { - let field_defs = data.fields(); - if let Some(last_field) = field_defs.last() { + if let Some(last_field) = data.fields().last() { if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { // Then check if that that array zero-sized let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); let length = Const::from_anon_const(cx.tcx, length_ldid); let length = length.try_eval_usize(cx.tcx, cx.param_env); - // if let Some((Constant::Int(length), _)) = length { - if let Some(length) = length { length == 0 } else { false } + length == Some(0) } else { false } diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr.rs similarity index 98% rename from tests/ui/trailing_zero_sized_array_without_repr_c.rs rename to tests/ui/trailing_zero_sized_array_without_repr.rs index c6ee36e9685..6ac124c8b34 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr.rs @@ -1,4 +1,4 @@ -#![warn(clippy::trailing_zero_sized_array_without_repr_c)] +#![warn(clippy::trailing_zero_sized_array_without_repr)] #![feature(const_generics_defaults)] // Do lint: From a6aa9864a339783e2e8400053408a197b607301d Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:52:37 -0700 Subject: [PATCH 071/100] Rename stderr --- ...iling_zero_sized_array_without_repr.stderr | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/ui/trailing_zero_sized_array_without_repr.stderr diff --git a/tests/ui/trailing_zero_sized_array_without_repr.stderr b/tests/ui/trailing_zero_sized_array_without_repr.stderr new file mode 100644 index 00000000000..54b36ec6cec --- /dev/null +++ b/tests/ui/trailing_zero_sized_array_without_repr.stderr @@ -0,0 +1,110 @@ +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:6:1 + | +LL | / struct RarelyUseful { +LL | | field: i32, +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = note: `-D clippy::trailing-zero-sized-array-without-repr` implied by `-D warnings` + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:11:1 + | +LL | / struct OnlyField { +LL | | first_and_last: [usize; 0], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:15:1 + | +LL | / struct GenericArrayType { +LL | | field: i32, +LL | | last: [T; 0], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:20:1 + | +LL | / #[must_use] +LL | | struct OnlyAnotherAttributeMustUse { +LL | | field: i32, +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:29:1 + | +LL | / struct OnlyAnotherAttributeDerive { +LL | | field: i32, +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:35:1 + | +LL | / struct ZeroSizedWithConst { +LL | | field: i32, +LL | | last: [usize; ZERO], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:44:1 + | +LL | / struct ZeroSizedWithConstFunction { +LL | | field: i32, +LL | | last: [usize; compute_zero()], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:49:1 + | +LL | struct ZeroSizedArrayWrapper([usize; 0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:51:1 + | +LL | struct TupleStruct(i32, [usize; 0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:53:1 + | +LL | / struct LotsOfFields { +LL | | f1: u32, +LL | | f2: u32, +LL | | f3: u32, +... | +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + +error: aborting due to 10 previous errors + From a54dbf6445f923b6b315a4c9b08f3e45eaac0081 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:52:57 -0700 Subject: [PATCH 072/100] Improve doc and span messages --- clippy_lints/src/trailing_zero_sized_array_without_repr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 0267f7bdf0e..98f5073681d 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -31,7 +31,7 @@ /// ``` pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, nursery, - "struct with a trailing zero-sized array but without `repr(C)` or another `repr` attribute" + "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute" } declare_lint_pass!(TrailingZeroSizedArrayWithoutRepr => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR]); @@ -54,9 +54,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, lint_span, - "trailing zero-sized array in a struct which is not marked `#[repr(C)]`", + "trailing zero-sized array in a struct which is not marked with a `repr` attribute", None, - "consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute)", + "consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute", ); } } From 5b78907be7b67cfb598301e20a9ebd500a494c41 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 03:56:49 -0700 Subject: [PATCH 073/100] Still renaming lmao --- ...ing_zero_sized_array_without_repr_c.stderr | 110 ------------------ 1 file changed, 110 deletions(-) delete mode 100644 tests/ui/trailing_zero_sized_array_without_repr_c.stderr diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.stderr b/tests/ui/trailing_zero_sized_array_without_repr_c.stderr deleted file mode 100644 index 5ed91e937d5..00000000000 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.stderr +++ /dev/null @@ -1,110 +0,0 @@ -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:6:1 - | -LL | / struct RarelyUseful { -LL | | field: i32, -LL | | last: [usize; 0], -LL | | } - | |_^ - | - = note: `-D clippy::trailing-zero-sized-array-without-repr-c` implied by `-D warnings` - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:11:1 - | -LL | / struct OnlyField { -LL | | first_and_last: [usize; 0], -LL | | } - | |_^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:15:1 - | -LL | / struct GenericArrayType { -LL | | field: i32, -LL | | last: [T; 0], -LL | | } - | |_^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:20:1 - | -LL | / #[must_use] -LL | | struct OnlyAnotherAttributeMustUse { -LL | | field: i32, -LL | | last: [usize; 0], -LL | | } - | |_^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:29:1 - | -LL | / struct OnlyAnotherAttributeDerive { -LL | | field: i32, -LL | | last: [usize; 0], -LL | | } - | |_^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:35:1 - | -LL | / struct ZeroSizedWithConst { -LL | | field: i32, -LL | | last: [usize; ZERO], -LL | | } - | |_^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:44:1 - | -LL | / struct ZeroSizedWithConstFunction { -LL | | field: i32, -LL | | last: [usize; compute_zero()], -LL | | } - | |_^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:49:1 - | -LL | struct ZeroSizedArrayWrapper([usize; 0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:51:1 - | -LL | struct TupleStruct(i32, [usize; 0]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: trailing zero-sized array in a struct which is not marked `#[repr(C)]` - --> $DIR/trailing_zero_sized_array_without_repr_c.rs:53:1 - | -LL | / struct LotsOfFields { -LL | | f1: u32, -LL | | f2: u32, -LL | | f3: u32, -... | -LL | | last: [usize; 0], -LL | | } - | |_^ - | - = help: consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute) - -error: aborting due to 10 previous errors - From d25b4eeefbcb6e2755b0843b0a66de0f5a744460 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 04:22:43 -0700 Subject: [PATCH 074/100] One more test --- tests/ui/trailing_zero_sized_array_without_repr.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ui/trailing_zero_sized_array_without_repr.rs b/tests/ui/trailing_zero_sized_array_without_repr.rs index 6ac124c8b34..5b12a882aa7 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr.rs @@ -167,6 +167,11 @@ struct ConstParamNonZeroDefault { last: [usize; N], } +struct TwoGenericParams { + field: i32, + last: [T; N], +} + type A = ConstParamZeroDefault; type B = ConstParamZeroDefault<0>; type C = ConstParamNoDefault<0>; From ab9fa25e82b3af4691df275f53c73bc439e84d78 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 04:59:03 -0700 Subject: [PATCH 075/100] Better testcase names --- tests/ui/trailing_zero_sized_array_without_repr.rs | 8 ++++---- tests/ui/trailing_zero_sized_array_without_repr.stderr | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui/trailing_zero_sized_array_without_repr.rs b/tests/ui/trailing_zero_sized_array_without_repr.rs index 5b12a882aa7..52966c64db7 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr.rs @@ -18,7 +18,7 @@ struct GenericArrayType { } #[must_use] -struct OnlyAnotherAttributeMustUse { +struct OnlyAnotherAttribute { field: i32, last: [usize; 0], } @@ -26,7 +26,7 @@ struct OnlyAnotherAttributeMustUse { // NOTE: Unfortunately the attribute isn't included in the lint output. I'm not sure how to make it // show up. #[derive(Debug)] -struct OnlyAnotherAttributeDerive { +struct OnlyADeriveAttribute { field: i32, last: [usize; 0], } @@ -102,14 +102,14 @@ struct NonZeroSizedWithConst { #[derive(Debug)] #[repr(C)] -struct OtherAttributesDerive { +struct AlsoADeriveAttribute { field: i32, last: [usize; 0], } #[must_use] #[repr(C)] -struct OtherAttributesMustUse { +struct AlsoAnotherAttribute { field: i32, last: [usize; 0], } diff --git a/tests/ui/trailing_zero_sized_array_without_repr.stderr b/tests/ui/trailing_zero_sized_array_without_repr.stderr index 54b36ec6cec..e5714386c8b 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.stderr +++ b/tests/ui/trailing_zero_sized_array_without_repr.stderr @@ -35,7 +35,7 @@ error: trailing zero-sized array in a struct which is not marked with a `repr` a --> $DIR/trailing_zero_sized_array_without_repr.rs:20:1 | LL | / #[must_use] -LL | | struct OnlyAnotherAttributeMustUse { +LL | | struct OnlyAnotherAttribute { LL | | field: i32, LL | | last: [usize; 0], LL | | } @@ -46,7 +46,7 @@ LL | | } error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_zero_sized_array_without_repr.rs:29:1 | -LL | / struct OnlyAnotherAttributeDerive { +LL | / struct OnlyADeriveAttribute { LL | | field: i32, LL | | last: [usize; 0], LL | | } From 3a41f226c5c89806f23ef67502ea29bedf7d9ce8 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 07:02:00 -0700 Subject: [PATCH 076/100] Exploring emitting other sorts of `span`s --- .../trailing_zero_sized_array_without_repr.rs | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 98f5073681d..48feb365ed8 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -1,5 +1,6 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{diagnostics::{span_lint_and_help, span_lint_and_then, span_lint_and_sugg}, source::{indent_of, snippet}}; use rustc_ast::Attribute; +use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::dep_graph::DepContext; @@ -50,14 +51,34 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { }; if !has_repr_attr(cx, attrs) { - span_lint_and_help( - cx, - TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, - lint_span, - "trailing zero-sized array in a struct which is not marked with a `repr` attribute", - None, - "consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute", - ); + let suggestion_span = item.span.shrink_to_lo(); + let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0)); + + span_lint_and_sugg(cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", "consider adding `#[repr(C)]` or another `repr` attribute", format!("#[repr(C)]\n{}", snippet(cx, item.span.shrink_to_lo().to(item.ident.span), "..")), Applicability::MaybeIncorrect); + + // span_lint_and_then( + // cx, + // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + // item.span, + // "trailing zero-sized array in a struct which is not marked with a `repr` attribute", + // |diag| { + // let sugg = format!("#[repr(C)]\n{}", indent); + // let sugg2 = format!("#[repr(C)]\n{}", item.ident.span); + // diag.span_suggestion(item.span, + // "consider adding `#[repr(C)]` or another `repr` attribute", + // sugg2, + // Applicability::MaybeIncorrect); + // } + // ); + + // span_lint_and_help( + // cx, + // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + // lint_span, + // "trailing zero-sized array in a struct which is not marked with a `repr` attribute", + // None, + // "consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute", + // ); } } } @@ -91,7 +112,8 @@ fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool { // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another; // they're in the commit history if you want to look (or I can go find them). + let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? attrs .iter() - .any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty()) + .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) } From d8bacf078a0c0d1dd3f15e6554338805f2d7256b Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 15:33:11 -0700 Subject: [PATCH 077/100] All five `has_repr_attr` agree + are correct --- .../trailing_zero_sized_array_without_repr.rs | 115 ++++++++++-------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 48feb365ed8..10088ea55a9 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -1,11 +1,15 @@ -use clippy_utils::{diagnostics::{span_lint_and_help, span_lint_and_then, span_lint_and_sugg}, source::{indent_of, snippet}}; +use clippy_utils::{ + diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, + source::{indent_of, snippet}, +}; use rustc_ast::Attribute; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind}; +use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty::Const; +use rustc_middle::ty::{self as ty_mod, Const, ReprFlags}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -38,48 +42,19 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if is_struct_with_trailing_zero_sized_array(cx, item) { - // NOTE: This is to include attributes on the definition when we print the lint. If the convention - // is to not do that with struct definitions (I'm not sure), then this isn't necessary. (note: if - // you don't get rid of this, change `has_repr_attr` to `includes_repr_attr`). - let attrs = cx.tcx.get_attrs(item.def_id.to_def_id()); - let first_attr = attrs.iter().min_by_key(|attr| attr.span.lo()); - let lint_span = if let Some(first_attr) = first_attr { - first_attr.span.to(item.span) - } else { - item.span - }; - - if !has_repr_attr(cx, attrs) { - let suggestion_span = item.span.shrink_to_lo(); - let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0)); - - span_lint_and_sugg(cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", "consider adding `#[repr(C)]` or another `repr` attribute", format!("#[repr(C)]\n{}", snippet(cx, item.span.shrink_to_lo().to(item.ident.span), "..")), Applicability::MaybeIncorrect); - - // span_lint_and_then( - // cx, - // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, - // item.span, - // "trailing zero-sized array in a struct which is not marked with a `repr` attribute", - // |diag| { - // let sugg = format!("#[repr(C)]\n{}", indent); - // let sugg2 = format!("#[repr(C)]\n{}", item.ident.span); - // diag.span_suggestion(item.span, - // "consider adding `#[repr(C)]` or another `repr` attribute", - // sugg2, - // Applicability::MaybeIncorrect); - // } - // ); - - // span_lint_and_help( - // cx, - // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, - // lint_span, - // "trailing zero-sized array in a struct which is not marked with a `repr` attribute", - // None, - // "consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute", - // ); - } + dbg!(item.ident); + if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item) { + eprintln!("consider yourself linted 😎"); + // span_lint_and_help( + // cx, + // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + // item.span, + // "trailing zero-sized array in a struct which is not marked with a `repr` + // attribute", + // None, + // "consider annotating the struct definition with `#[repr(C)]` or another + // `repr` attribute", + // ); } } } @@ -108,12 +83,52 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } } -fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool { +fn has_repr_attr(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another; // they're in the commit history if you want to look (or I can go find them). - let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? - attrs - .iter() - .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) + + let attrs1 = cx.tcx.hir().attrs(item.hir_id()); + let attrs2 = cx.tcx.get_attrs(item.def_id.to_def_id()); + + let res11 = { + let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? + attrs1 + .iter() + .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) + }; + let res12 = { attrs1.iter().any(|attr| attr.has_name(sym::repr)) }; + + let res21 = { + let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? + attrs2 + .iter() + .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) + }; + let res22 = { attrs2.iter().any(|attr| attr.has_name(sym::repr)) }; + + let res_adt = { + let ty = cx.tcx.type_of(item.def_id.to_def_id()); + if let ty_mod::Adt(adt, _) = ty.kind() { + if adt.is_struct() { + let repr = adt.repr; + let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR; + repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr) + } else { + false + } + } else { + false + } + }; + + let all_same = (res11 && res12 && res21 && res22 && res_adt) || (!res11 && !res12 && !res21 && !res22 && !res_adt); + + + dbg!(( + (res11, res12, res21, res22, res_adt), + all_same, + )); + + res12 } From 18c863dd0ef490d8f069dba6263d7d5d6f8b3e13 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 16:53:05 -0700 Subject: [PATCH 078/100] Improve help message --- .../trailing_zero_sized_array_without_repr.rs | 87 ++++++------------- 1 file changed, 26 insertions(+), 61 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 10088ea55a9..0c9066fda82 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -2,12 +2,10 @@ diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, source::{indent_of, snippet}, }; -use rustc_ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty::{self as ty_mod, Const, ReprFlags}; +use rustc_middle::ty::{Const, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -43,18 +41,28 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { dbg!(item.ident); - if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item) { - eprintln!("consider yourself linted 😎"); - // span_lint_and_help( - // cx, - // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, - // item.span, - // "trailing zero-sized array in a struct which is not marked with a `repr` - // attribute", - // None, - // "consider annotating the struct definition with `#[repr(C)]` or another - // `repr` attribute", - // ); + if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) { + let help_msg = format!( + "consider annotating {} with `#[repr(C)]` or another `repr` attribute", + cx.tcx + .type_of(item.def_id) + .ty_adt_def() + .map(|adt_def| cx.tcx.def_path_str(adt_def.did)) + .unwrap_or_else( + // I don't think this will ever be the case, since we made it through + // `is_struct_with_trailing_zero_sized_array`, but I don't feel comfortable putting an `unwrap` + || "the struct definition".to_string() + ) + ); + + span_lint_and_help( + cx, + TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + item.span, + "trailing zero-sized array in a struct which is not marked with a `repr` attribute", + None, + &help_msg, + ); } } } @@ -83,52 +91,9 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } } -fn has_repr_attr(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { +fn has_repr_attr(cx: &LateContext<'tcx>, hir_id: HirId) -> bool { // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed - // on all testcases (when i wrote this comment. I added a few since then).) Happy to use another; + // on all testcases.) Happy to use another; // they're in the commit history if you want to look (or I can go find them). - - let attrs1 = cx.tcx.hir().attrs(item.hir_id()); - let attrs2 = cx.tcx.get_attrs(item.def_id.to_def_id()); - - let res11 = { - let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? - attrs1 - .iter() - .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) - }; - let res12 = { attrs1.iter().any(|attr| attr.has_name(sym::repr)) }; - - let res21 = { - let sess = cx.tcx.sess(); // are captured values in closures evaluated once or every time? - attrs2 - .iter() - .any(|attr| !rustc_attr::find_repr_attrs(sess, attr).is_empty()) - }; - let res22 = { attrs2.iter().any(|attr| attr.has_name(sym::repr)) }; - - let res_adt = { - let ty = cx.tcx.type_of(item.def_id.to_def_id()); - if let ty_mod::Adt(adt, _) = ty.kind() { - if adt.is_struct() { - let repr = adt.repr; - let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR; - repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr) - } else { - false - } - } else { - false - } - }; - - let all_same = (res11 && res12 && res21 && res22 && res_adt) || (!res11 && !res12 && !res21 && !res22 && !res_adt); - - - dbg!(( - (res11, res12, res21, res22, res_adt), - all_same, - )); - - res12 + cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr)) } From 48cf9c284ac858545cdd22ef2efec9096e6c6b06 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 16:53:17 -0700 Subject: [PATCH 079/100] Don't need `rustc_attr` anymore --- clippy_lints/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1473a2f3095..de2ebcab667 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -21,7 +21,6 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_ast; extern crate rustc_ast_pretty; -extern crate rustc_attr; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; From d85f903c91d909534003ee2ff0e16316b20687dc Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 17:07:51 -0700 Subject: [PATCH 080/100] !: this is the commit that demonstrates the ICE --- .../trailing_zero_sized_array_without_repr.rs | 55 ++++++++----------- .../trailing_zero_sized_array_without_repr.rs | 8 ++- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 0c9066fda82..ac4bbded127 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -1,11 +1,6 @@ -use clippy_utils::{ - diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, - source::{indent_of, snippet}, -}; -use rustc_errors::Applicability; +use clippy_utils::{consts::miri_to_const, consts::Constant, diagnostics::span_lint_and_help}; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Const, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -42,27 +37,15 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { dbg!(item.ident); if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) { - let help_msg = format!( - "consider annotating {} with `#[repr(C)]` or another `repr` attribute", - cx.tcx - .type_of(item.def_id) - .ty_adt_def() - .map(|adt_def| cx.tcx.def_path_str(adt_def.did)) - .unwrap_or_else( - // I don't think this will ever be the case, since we made it through - // `is_struct_with_trailing_zero_sized_array`, but I don't feel comfortable putting an `unwrap` - || "the struct definition".to_string() - ) - ); - - span_lint_and_help( - cx, - TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, - item.span, - "trailing zero-sized array in a struct which is not marked with a `repr` attribute", - None, - &help_msg, - ); + // span_lint_and_help( + // cx, + // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + // item.span, + // "trailing zero-sized array in a struct which is not marked with a `repr` attribute", + // None, + // "", + // ); + eprintln!("consider yourself linted 😎"); } } } @@ -75,11 +58,19 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx if let ItemKind::Struct(data, _) = &item.kind { if let Some(last_field) = data.fields().last() { if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { - // Then check if that that array zero-sized - let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); - let length = Const::from_anon_const(cx.tcx, length_ldid); - let length = length.try_eval_usize(cx.tcx, cx.param_env); - length == Some(0) + let length_did = cx.tcx.hir().body_owner_def_id(length.body).to_def_id(); + let ty = cx.tcx.type_of(length_did); + let length = cx + .tcx + // ICE happens in `const_eval_poly` according to my backtrace + .const_eval_poly(length_did) + .ok() + .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); + if let Some(Constant::Int(length)) = length.and_then(miri_to_const){ + length == 0 + } else { + false + } } else { false } diff --git a/tests/ui/trailing_zero_sized_array_without_repr.rs b/tests/ui/trailing_zero_sized_array_without_repr.rs index 52966c64db7..c00a772d2fe 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr.rs @@ -1,6 +1,8 @@ #![warn(clippy::trailing_zero_sized_array_without_repr)] #![feature(const_generics_defaults)] +// ICE note: All of these are fine + // Do lint: struct RarelyUseful { @@ -23,8 +25,6 @@ struct OnlyAnotherAttribute { last: [usize; 0], } -// NOTE: Unfortunately the attribute isn't included in the lint output. I'm not sure how to make it -// show up. #[derive(Debug)] struct OnlyADeriveAttribute { field: i32, @@ -150,12 +150,16 @@ enum DontLintAnonymousStructsFromDesuraging { type NamedTuple = (i32, [usize; 0]); +// ICE note: and then this one crashes + #[rustfmt::skip] // [rustfmt#4995](https://github.com/rust-lang/rustfmt/issues/4995) struct ConstParamZeroDefault { field: i32, last: [usize; N], } +// ICE notes: presumably these as well but I'm not sure + struct ConstParamNoDefault { field: i32, last: [usize; N], From 6303d2d075131641ef325344124c71052d2bd3eb Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 17:18:07 -0700 Subject: [PATCH 081/100] Revert "!: this is the commit that demonstrates the ICE" This reverts commit d85f903c91d909534003ee2ff0e16316b20687dc. --- .../trailing_zero_sized_array_without_repr.rs | 55 +++++++++++-------- .../trailing_zero_sized_array_without_repr.rs | 8 +-- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index ac4bbded127..0c9066fda82 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -1,6 +1,11 @@ -use clippy_utils::{consts::miri_to_const, consts::Constant, diagnostics::span_lint_and_help}; +use clippy_utils::{ + diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, + source::{indent_of, snippet}, +}; +use rustc_errors::Applicability; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Const, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -37,15 +42,27 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { dbg!(item.ident); if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) { - // span_lint_and_help( - // cx, - // TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, - // item.span, - // "trailing zero-sized array in a struct which is not marked with a `repr` attribute", - // None, - // "", - // ); - eprintln!("consider yourself linted 😎"); + let help_msg = format!( + "consider annotating {} with `#[repr(C)]` or another `repr` attribute", + cx.tcx + .type_of(item.def_id) + .ty_adt_def() + .map(|adt_def| cx.tcx.def_path_str(adt_def.did)) + .unwrap_or_else( + // I don't think this will ever be the case, since we made it through + // `is_struct_with_trailing_zero_sized_array`, but I don't feel comfortable putting an `unwrap` + || "the struct definition".to_string() + ) + ); + + span_lint_and_help( + cx, + TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + item.span, + "trailing zero-sized array in a struct which is not marked with a `repr` attribute", + None, + &help_msg, + ); } } } @@ -58,19 +75,11 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx if let ItemKind::Struct(data, _) = &item.kind { if let Some(last_field) = data.fields().last() { if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { - let length_did = cx.tcx.hir().body_owner_def_id(length.body).to_def_id(); - let ty = cx.tcx.type_of(length_did); - let length = cx - .tcx - // ICE happens in `const_eval_poly` according to my backtrace - .const_eval_poly(length_did) - .ok() - .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); - if let Some(Constant::Int(length)) = length.and_then(miri_to_const){ - length == 0 - } else { - false - } + // Then check if that that array zero-sized + let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); + let length = Const::from_anon_const(cx.tcx, length_ldid); + let length = length.try_eval_usize(cx.tcx, cx.param_env); + length == Some(0) } else { false } diff --git a/tests/ui/trailing_zero_sized_array_without_repr.rs b/tests/ui/trailing_zero_sized_array_without_repr.rs index c00a772d2fe..52966c64db7 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr.rs @@ -1,8 +1,6 @@ #![warn(clippy::trailing_zero_sized_array_without_repr)] #![feature(const_generics_defaults)] -// ICE note: All of these are fine - // Do lint: struct RarelyUseful { @@ -25,6 +23,8 @@ struct OnlyAnotherAttribute { last: [usize; 0], } +// NOTE: Unfortunately the attribute isn't included in the lint output. I'm not sure how to make it +// show up. #[derive(Debug)] struct OnlyADeriveAttribute { field: i32, @@ -150,16 +150,12 @@ enum DontLintAnonymousStructsFromDesuraging { type NamedTuple = (i32, [usize; 0]); -// ICE note: and then this one crashes - #[rustfmt::skip] // [rustfmt#4995](https://github.com/rust-lang/rustfmt/issues/4995) struct ConstParamZeroDefault { field: i32, last: [usize; N], } -// ICE notes: presumably these as well but I'm not sure - struct ConstParamNoDefault { field: i32, last: [usize; N], From c654cc56da81e9bebc37dd6c476b40c07d297cbe Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 17:41:27 -0700 Subject: [PATCH 082/100] One more test + final tidying --- .../trailing_zero_sized_array_without_repr.rs | 55 ++++++------------- .../trailing_zero_sized_array_without_repr.rs | 8 +++ ...iling_zero_sized_array_without_repr.stderr | 44 +++++++++------ 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 0c9066fda82..88ec471184c 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -1,11 +1,7 @@ -use clippy_utils::{ - diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, - source::{indent_of, snippet}, -}; -use rustc_errors::Applicability; +use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Const, TyS}; +use rustc_middle::ty::Const; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -40,54 +36,39 @@ impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - dbg!(item.ident); if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) { - let help_msg = format!( - "consider annotating {} with `#[repr(C)]` or another `repr` attribute", - cx.tcx - .type_of(item.def_id) - .ty_adt_def() - .map(|adt_def| cx.tcx.def_path_str(adt_def.did)) - .unwrap_or_else( - // I don't think this will ever be the case, since we made it through - // `is_struct_with_trailing_zero_sized_array`, but I don't feel comfortable putting an `unwrap` - || "the struct definition".to_string() - ) - ); - span_lint_and_help( cx, TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", None, - &help_msg, + &format!( + "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute", + cx.tcx.def_path_str(item.def_id.to_def_id()) + ), ); } } } fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { - // TODO: when finalized, replace with an `if_chain`. I have it like this because my rust-analyzer - // doesn't work when it's an `if_chain`. + if_chain! { + // First check if last field is an array + if let ItemKind::Struct(data, _) = &item.kind; + if let Some(last_field) = data.fields().last(); + if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind; - // First check if last field is an array - if let ItemKind::Struct(data, _) = &item.kind { - if let Some(last_field) = data.fields().last() { - if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind { - // Then check if that that array zero-sized - let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); - let length = Const::from_anon_const(cx.tcx, length_ldid); - let length = length.try_eval_usize(cx.tcx, cx.param_env); - length == Some(0) - } else { - false - } + // Then check if that that array zero-sized + let length_ldid = cx.tcx.hir().local_def_id(length.hir_id); + let length = Const::from_anon_const(cx.tcx, length_ldid); + let length = length.try_eval_usize(cx.tcx, cx.param_env); + if let Some(length) = length; + then { + length == 0 } else { false } - } else { - false } } diff --git a/tests/ui/trailing_zero_sized_array_without_repr.rs b/tests/ui/trailing_zero_sized_array_without_repr.rs index 52966c64db7..dee7f811540 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr.rs @@ -46,6 +46,14 @@ struct ZeroSizedWithConstFunction { last: [usize; compute_zero()], } +const fn compute_zero_from_arg(x: usize) -> usize { + x - 1 +} +struct ZeroSizedWithConstFunction2 { + field: i32, + last: [usize; compute_zero_from_arg(1)], +} + struct ZeroSizedArrayWrapper([usize; 0]); struct TupleStruct(i32, [usize; 0]); diff --git a/tests/ui/trailing_zero_sized_array_without_repr.stderr b/tests/ui/trailing_zero_sized_array_without_repr.stderr index e5714386c8b..93c607bbf38 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.stderr +++ b/tests/ui/trailing_zero_sized_array_without_repr.stderr @@ -8,7 +8,7 @@ LL | | } | |_^ | = note: `-D clippy::trailing-zero-sized-array-without-repr` implied by `-D warnings` - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_zero_sized_array_without_repr.rs:11:1 @@ -18,7 +18,7 @@ LL | | first_and_last: [usize; 0], LL | | } | |_^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `OnlyField` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_zero_sized_array_without_repr.rs:15:1 @@ -29,19 +29,18 @@ LL | | last: [T; 0], LL | | } | |_^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `GenericArrayType` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:20:1 + --> $DIR/trailing_zero_sized_array_without_repr.rs:21:1 | -LL | / #[must_use] -LL | | struct OnlyAnotherAttribute { +LL | / struct OnlyAnotherAttribute { LL | | field: i32, LL | | last: [usize; 0], LL | | } | |_^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `OnlyAnotherAttribute` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_zero_sized_array_without_repr.rs:29:1 @@ -52,7 +51,7 @@ LL | | last: [usize; 0], LL | | } | |_^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `OnlyADeriveAttribute` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_zero_sized_array_without_repr.rs:35:1 @@ -63,7 +62,7 @@ LL | | last: [usize; ZERO], LL | | } | |_^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `ZeroSizedWithConst` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute --> $DIR/trailing_zero_sized_array_without_repr.rs:44:1 @@ -74,26 +73,37 @@ LL | | last: [usize; compute_zero()], LL | | } | |_^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `ZeroSizedWithConstFunction` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:49:1 + --> $DIR/trailing_zero_sized_array_without_repr.rs:52:1 + | +LL | / struct ZeroSizedWithConstFunction2 { +LL | | field: i32, +LL | | last: [usize; compute_zero_from_arg(1)], +LL | | } + | |_^ + | + = help: consider annotating `ZeroSizedWithConstFunction2` with `#[repr(C)]` or another `repr` attribute + +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_zero_sized_array_without_repr.rs:57:1 | LL | struct ZeroSizedArrayWrapper([usize; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `ZeroSizedArrayWrapper` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:51:1 + --> $DIR/trailing_zero_sized_array_without_repr.rs:59:1 | LL | struct TupleStruct(i32, [usize; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `TupleStruct` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:53:1 + --> $DIR/trailing_zero_sized_array_without_repr.rs:61:1 | LL | / struct LotsOfFields { LL | | f1: u32, @@ -104,7 +114,7 @@ LL | | last: [usize; 0], LL | | } | |_^ | - = help: consider annotating the struct definition with `#[repr(C)]` or another `repr` attribute + = help: consider annotating `LotsOfFields` with `#[repr(C)]` or another `repr` attribute -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors From bc32be0fecd9a99c981323699bbd5a8e485220f0 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 18:03:00 -0700 Subject: [PATCH 083/100] Remove comment --- clippy_lints/src/trailing_zero_sized_array_without_repr.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 88ec471184c..cc1671af82d 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -73,8 +73,5 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } fn has_repr_attr(cx: &LateContext<'tcx>, hir_id: HirId) -> bool { - // NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed - // on all testcases.) Happy to use another; - // they're in the commit history if you want to look (or I can go find them). cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr)) } From 02b1f266d6a98cd9dc430554b80971705c5de09b Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 18:20:35 -0700 Subject: [PATCH 084/100] Remove explicit lifetime --- clippy_lints/src/trailing_zero_sized_array_without_repr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index cc1671af82d..5fa13605ae3 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -72,6 +72,6 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx } } -fn has_repr_attr(cx: &LateContext<'tcx>, hir_id: HirId) -> bool { +fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr)) } From 4c8e8169720d54db905142a18502ab2a2dad63a0 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 18:32:00 -0700 Subject: [PATCH 085/100] Use real type in doc examples --- .../src/trailing_zero_sized_array_without_repr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index 5fa13605ae3..bfe0049dfae 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -15,17 +15,17 @@ /// ### Example /// ```rust /// struct RarelyUseful { - /// some_field: usize, - /// last: [SomeType; 0], + /// some_field: u32, + /// last: [u32; 0], /// } /// ``` /// - /// Use instead: + /// Use instead: /// ```rust /// #[repr(C)] /// struct MoreOftenUseful { /// some_field: usize, - /// last: [SomeType; 0], + /// last: [u32; 0], /// } /// ``` pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, From 5283d24b38631941790082b41ae3c99c698fc346 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Mon, 18 Oct 2021 18:42:01 -0700 Subject: [PATCH 086/100] =?UTF-8?q?formatting=20=F0=9F=99=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clippy_lints/src/trailing_zero_sized_array_without_repr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs index bfe0049dfae..2e579aecab0 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr.rs @@ -20,7 +20,7 @@ /// } /// ``` /// - /// Use instead: + /// Use instead: /// ```rust /// #[repr(C)] /// struct MoreOftenUseful { From 687f3925da6481d938be0d787808328f8a93fdee Mon Sep 17 00:00:00 2001 From: dswij Date: Tue, 19 Oct 2021 18:26:50 +0800 Subject: [PATCH 087/100] Cover `Result` for `question_mark` --- clippy_lints/src/question_mark.rs | 76 ++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index aa6d254e7a5..c1ee20c370a 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -4,10 +4,10 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{eq_expr_value, path_to_local_id}; +use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -48,16 +48,25 @@ impl QuestionMark { /// } /// ``` /// + /// ```ignore + /// if result.is_err() { + /// return result; + /// } + /// ``` + /// /// If it matches, it will suggest to use the question mark operator instead - fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_is_none_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); if let ExprKind::MethodCall(segment, _, args, _) = &cond.kind; - if segment.ident.name == sym!(is_none); - if Self::expression_returns_none(cx, then); if let Some(subject) = args.get(0); - if Self::is_option(cx, subject); - + if (Self::is_option(cx, subject) + && Self::expression_returns_none(cx, then) + && segment.ident.name == sym!(is_none)) + || + (Self::is_result(cx, subject) + && Self::expression_returns_unmodified_err(cx, then, subject) + && segment.ident.name == sym!(is_err)); then { let mut applicability = Applicability::MachineApplicable; let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability); @@ -95,31 +104,29 @@ fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) { } } - fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_if_let_some_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(cx, expr); - if Self::is_option(cx, let_expr); - if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind; - if is_lang_ctor(cx, path1, OptionSome); + if (Self::is_option(cx, let_expr) + && Self::expression_returns_none(cx, if_else) + && is_lang_ctor(cx, path1, OptionSome)) + || + (Self::is_result(cx, let_expr) + && Self::expression_returns_unmodified_err(cx, if_else, let_expr) + && is_lang_ctor(cx, path1, ResultOk)); + if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind; let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); - if let ExprKind::Block(block, None) = if_then.kind; if block.stmts.is_empty(); if let Some(trailing_expr) = &block.expr; if path_to_local_id(trailing_expr, bind_id); - - if Self::expression_returns_none(cx, if_else); then { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); - let replacement = format!( - "{}{}?", - receiver_str, - if by_ref { ".as_ref()" } else { "" }, - ); + let replacement = format!("{}{}?", receiver_str, if by_ref { ".as_ref()" } else { "" },); span_lint_and_sugg( cx, @@ -146,6 +153,12 @@ fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { is_type_diagnostic_item(cx, expr_ty, sym::Option) } + fn is_result(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { + let expr_ty = cx.typeck_results().expr_ty(expression); + + is_type_diagnostic_item(cx, expr_ty, sym::Result) + } + fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { match expression.kind { ExprKind::Block(block, _) => { @@ -161,6 +174,27 @@ fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool } } + fn expression_returns_unmodified_err( + cx: &LateContext<'_>, + expression: &Expr<'_>, + origin_hir_id: &Expr<'_>, + ) -> bool { + match expression.kind { + ExprKind::Block(block, _) => { + if let Some(return_expression) = Self::return_expression(block) { + return Self::expression_returns_unmodified_err(cx, return_expression, origin_hir_id); + } + + false + }, + ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => { + Self::expression_returns_unmodified_err(cx, expr, origin_hir_id) + }, + ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id), + _ => false, + } + } + fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { // Check if last expression is a return statement. Then, return the expression if_chain! { @@ -189,7 +223,7 @@ fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { impl<'tcx> LateLintPass<'tcx> for QuestionMark { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - Self::check_is_none_and_early_return_none(cx, expr); - Self::check_if_let_some_and_early_return_none(cx, expr); + Self::check_is_none_or_err_and_early_return(cx, expr); + Self::check_if_let_some_or_err_and_early_return(cx, expr); } } From 3fc99b6a3376a568adc2030e93b82ad3f99eb189 Mon Sep 17 00:00:00 2001 From: dswij Date: Tue, 19 Oct 2021 18:27:37 +0800 Subject: [PATCH 088/100] Update test for `question_mark` to cover `Result` --- tests/ui/question_mark.fixed | 17 +++++++++++++++++ tests/ui/question_mark.rs | 19 +++++++++++++++++++ tests/ui/question_mark.stderr | 16 +++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 0b5746cb522..ccb2e5a302e 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -104,6 +104,21 @@ fn func() -> Option { Some(0) } +fn result_func(x: Result) -> Result { + let _ = x?; + + x?; + + // No warning + let y = if let Ok(x) = x { + x + } else { + return Err("some error"); + }; + + Ok(y) +} + fn main() { some_func(Some(42)); some_func(None); @@ -123,4 +138,6 @@ fn main() { returns_something_similar_to_option(so); func(); + + let _ = result_func(Ok(42)); } diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 0f0825c9334..ca3722371f5 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -134,6 +134,23 @@ fn f() -> Option { Some(0) } +fn result_func(x: Result) -> Result { + let _ = if let Ok(x) = x { x } else { return x }; + + if x.is_err() { + return x; + } + + // No warning + let y = if let Ok(x) = x { + x + } else { + return Err("some error"); + }; + + Ok(y) +} + fn main() { some_func(Some(42)); some_func(None); @@ -153,4 +170,6 @@ fn main() { returns_something_similar_to_option(so); func(); + + let _ = result_func(Ok(42)); } diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 6f330cfa385..161588cb73c 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -100,5 +100,19 @@ LL | | return None; LL | | } | |_____^ help: replace it with: `f()?;` -error: aborting due to 11 previous errors +error: this if-let-else may be rewritten with the `?` operator + --> $DIR/question_mark.rs:138:13 + | +LL | let _ = if let Ok(x) = x { x } else { return x }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?` + +error: this block may be rewritten with the `?` operator + --> $DIR/question_mark.rs:140:5 + | +LL | / if x.is_err() { +LL | | return x; +LL | | } + | |_____^ help: replace it with: `x?;` + +error: aborting due to 13 previous errors From ebf4f03f7d4c1fa53ab7da166d6bf0becabb584c Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 19 Oct 2021 13:58:58 +0100 Subject: [PATCH 089/100] Remove begin_panic_fmt from clippy --- clippy_utils/src/higher.rs | 1 - clippy_utils/src/lib.rs | 1 - clippy_utils/src/paths.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index ba4d50bf744..74cf323720c 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -619,7 +619,6 @@ pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { if let Some(init) = block.expr; if let ExprKind::Call(_, [format_args]) = init.kind; let expn_data = expr.span.ctxt().outer_expn_data(); - if let ExprKind::AddrOf(_, _, format_args) = format_args.kind; if let Some(format_args) = FormatArgsExpn::parse(format_args); then { Some(PanicExpn { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index c47aa9170e5..8e94d16a33a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1646,7 +1646,6 @@ pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool { did, &[ &paths::BEGIN_PANIC, - &paths::BEGIN_PANIC_FMT, &paths::PANIC_ANY, &paths::PANICKING_PANIC, &paths::PANICKING_PANIC_FMT, diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e43c5756021..81aff585ded 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -20,7 +20,6 @@ pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; -pub(super) const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"]; /// Preferably use the diagnostic item `sym::Borrow` where possible pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"]; From 7246731ad87b78b02a7074154e41a7ef1ea84296 Mon Sep 17 00:00:00 2001 From: Dmitry Borodin Date: Tue, 19 Oct 2021 20:33:39 +0200 Subject: [PATCH 090/100] made description of intellij a link by moving outside of code block. --- doc/basics.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/basics.md b/doc/basics.md index 6da90ebf5f5..57a90a924ec 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -93,9 +93,10 @@ cargo dev update_lints cargo dev new_lint # automatically formatting all code before each commit cargo dev setup git-hook -# (experimental) Setup Clippy to work with IntelliJ-Rust. Details here: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust +# (experimental) Setup Clippy to work with IntelliJ-Rust cargo dev setup intellij ``` +More about intellij command usage and reasons [here](../CONTRIBUTING.md#intellij-rust) ## lintcheck `cargo lintcheck` will build and run clippy on a fixed set of crates and generate a log of the results. From e88c956e1e18a99af55af00c8917f8e975d534c5 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 12 Oct 2021 19:18:22 +0200 Subject: [PATCH 091/100] avoid `eq_op` in test code --- clippy_lints/src/eq_op.rs | 11 ++++-- clippy_utils/src/lib.rs | 78 ++++++++++++++++++++++++++++++++++----- tests/compile-test.rs | 14 +++++++ tests/ui_test/eq_op.rs | 15 ++++++++ 4 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 tests/ui_test/eq_op.rs diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 51d5094e8c9..655560afd42 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::{implements_trait, is_copy}; -use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of}; +use clippy_utils::{ + ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, is_in_test_function, +}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind}; @@ -81,7 +83,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if macro_args.len() == 2; let (lhs, rhs) = (macro_args[0], macro_args[1]); if eq_expr_value(cx, lhs, rhs); - + if !is_in_test_function(cx.tcx, e.hir_id); then { span_lint( cx, @@ -108,7 +110,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) { return; } - if is_useless_with_eq_exprs(op.node.into()) && eq_expr_value(cx, left, right) { + if is_useless_with_eq_exprs(op.node.into()) + && eq_expr_value(cx, left, right) + && !is_in_test_function(cx.tcx, e.hir_id) + { span_lint( cx, EQ_OP, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 09eee78f0d1..c540e1ebc9c 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -69,11 +69,13 @@ use rustc_hir::def_id::DefId; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ - def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl, - ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat, - PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, + def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs, + HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, + Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, + UnOp, }; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::exports::Export; @@ -2064,16 +2066,72 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { false } -/// Checks whether item either has `test` attribute applied, or -/// is a module with `test` in its name. -pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { - if let Some(def_id) = tcx.hir().opt_local_def_id(item.hir_id()) { - if tcx.has_attr(def_id.to_def_id(), sym::test) { - return true; +struct VisitConstTestStruct<'tcx> { + tcx: TyCtxt<'tcx>, + names: Vec, + found: bool, +} +impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> { + fn visit_item(&mut self, item: &Item<'_>) { + if let ItemKind::Const(ty, _body) = item.kind { + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + // We could also check for the type name `test::TestDescAndFn` + // and the `#[rustc_test_marker]` attribute? + if let Res::Def(DefKind::Struct, _) = path.res { + let has_test_marker = self + .tcx + .hir() + .attrs(item.hir_id()) + .iter() + .any(|a| a.has_name(sym::rustc_test_marker)); + if has_test_marker && self.names.contains(&item.ident.name) { + self.found = true; + } + } + } } } + fn visit_trait_item(&mut self, _: &TraitItem<'_>) {} + fn visit_impl_item(&mut self, _: &ImplItem<'_>) {} + fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {} +} - matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") +/// Checks if the function containing the given `HirId` is a `#[test]` function +/// +/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`. +pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { + let names: Vec<_> = tcx + .hir() + .parent_iter(id) + // Since you can nest functions we need to collect all until we leave + // function scope + .filter_map(|(_id, node)| { + if let Node::Item(item) = node { + if let ItemKind::Fn(_, _, _) = item.kind { + return Some(item.ident.name); + } + } + None + }) + .collect(); + let parent_mod = tcx.parent_module(id); + let mut vis = VisitConstTestStruct { + tcx, + names, + found: false, + }; + tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis); + vis.found +} + +/// Checks whether item either has `test` attribute appelied, or +/// is a module with `test` in its name. +/// +/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`. +pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { + is_in_test_function(tcx, item.hir_id()) + || matches!(item.kind, ItemKind::Mod(..)) + && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests") } macro_rules! op_utils { diff --git a/tests/compile-test.rs b/tests/compile-test.rs index e8b1640c869..c15835ef299 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -149,6 +149,19 @@ fn run_ui(cfg: &mut compiletest::Config) { compiletest::run_tests(cfg); } +fn run_ui_test(cfg: &mut compiletest::Config) { + cfg.mode = TestMode::Ui; + cfg.src_base = Path::new("tests").join("ui_test"); + let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap()); + let rustcflags = cfg.target_rustcflags.get_or_insert_with(Default::default); + let len = rustcflags.len(); + rustcflags.push_str(" --test"); + compiletest::run_tests(cfg); + if let Some(ref mut flags) = &mut cfg.target_rustcflags { + flags.truncate(len); + } +} + fn run_internal_tests(cfg: &mut compiletest::Config) { // only run internal tests with the internal-tests feature if !RUN_INTERNAL_TESTS { @@ -312,6 +325,7 @@ fn compile_test() { prepare_env(); let mut config = default_config(); run_ui(&mut config); + run_ui_test(&mut config); run_ui_toml(&mut config); run_ui_cargo(&mut config); run_internal_tests(&mut config); diff --git a/tests/ui_test/eq_op.rs b/tests/ui_test/eq_op.rs new file mode 100644 index 00000000000..f2f5f1e588e --- /dev/null +++ b/tests/ui_test/eq_op.rs @@ -0,0 +1,15 @@ +#[warn(clippy::eq_op)] +#[test] +fn eq_op_shouldnt_trigger_in_tests() { + let a = 1; + let result = a + 1 == 1 + a; + assert!(result); +} + +#[test] +fn eq_op_macros_shouldnt_trigger_in_tests() { + let a = 1; + let b = 2; + assert_eq!(a, a); + assert_eq!(a + b, b + a); +} From 60da4c9cb683a41eca4707ab7a533c5759b52485 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Tue, 19 Oct 2021 14:23:55 -0700 Subject: [PATCH 092/100] remove resolved note --- tests/ui/trailing_zero_sized_array_without_repr.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/ui/trailing_zero_sized_array_without_repr.rs b/tests/ui/trailing_zero_sized_array_without_repr.rs index dee7f811540..bfa3af0bbc3 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr.rs @@ -23,8 +23,6 @@ struct OnlyAnotherAttribute { last: [usize; 0], } -// NOTE: Unfortunately the attribute isn't included in the lint output. I'm not sure how to make it -// show up. #[derive(Debug)] struct OnlyADeriveAttribute { field: i32, From 0f9f591e30074bf5e31e4ca279280425685f33ff Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Tue, 19 Oct 2021 14:33:43 -0700 Subject: [PATCH 093/100] Rename lint --- CHANGELOG.md | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_nursery.rs | 2 +- clippy_lints/src/lib.rs | 4 ++-- ...ithout_repr.rs => trailing_empty_array.rs} | 8 +++---- ...ithout_repr.rs => trailing_empty_array.rs} | 2 +- ...epr.stderr => trailing_empty_array.stderr} | 24 +++++++++---------- 7 files changed, 22 insertions(+), 22 deletions(-) rename clippy_lints/src/{trailing_zero_sized_array_without_repr.rs => trailing_empty_array.rs} (90%) rename tests/ui/{trailing_zero_sized_array_without_repr.rs => trailing_empty_array.rs} (98%) rename tests/ui/{trailing_zero_sized_array_without_repr.stderr => trailing_empty_array.stderr} (82%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cf19a6f0f1..49499324ea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3021,7 +3021,7 @@ Released 2018-09-13 [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg -[`trailing_zero_sized_array_without_repr`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_zero_sized_array_without_repr +[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array [`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds [`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str [`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index af0629beb36..37d8d7f422f 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -443,7 +443,7 @@ temporary_assignment::TEMPORARY_ASSIGNMENT, to_digit_is_some::TO_DIGIT_IS_SOME, to_string_in_display::TO_STRING_IN_DISPLAY, - trailing_zero_sized_array_without_repr::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + trailing_empty_array::TRAILING_EMPTY_ARRAY, trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index eab0e5b90f1..1e54482a8da 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -25,7 +25,7 @@ LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), - LintId::of(trailing_zero_sized_array_without_repr::TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR), + LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(use_self::USE_SELF), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index de2ebcab667..58e4c061892 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -355,7 +355,7 @@ macro_rules! declare_clippy_lint { mod temporary_assignment; mod to_digit_is_some; mod to_string_in_display; -mod trailing_zero_sized_array_without_repr; +mod trailing_empty_array; mod trait_bounds; mod transmute; mod transmuting_null; @@ -778,7 +778,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); store.register_late_pass(move || Box::new(format_args::FormatArgs)); - store.register_late_pass(|| Box::new(trailing_zero_sized_array_without_repr::TrailingZeroSizedArrayWithoutRepr)); + store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray)); } diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs b/clippy_lints/src/trailing_empty_array.rs similarity index 90% rename from clippy_lints/src/trailing_zero_sized_array_without_repr.rs rename to clippy_lints/src/trailing_empty_array.rs index 2e579aecab0..c216a1f81ea 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -28,18 +28,18 @@ /// last: [u32; 0], /// } /// ``` - pub TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + pub TRAILING_EMPTY_ARRAY, nursery, "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute" } -declare_lint_pass!(TrailingZeroSizedArrayWithoutRepr => [TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR]); +declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]); -impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutRepr { +impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) { span_lint_and_help( cx, - TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR, + TRAILING_EMPTY_ARRAY, item.span, "trailing zero-sized array in a struct which is not marked with a `repr` attribute", None, diff --git a/tests/ui/trailing_zero_sized_array_without_repr.rs b/tests/ui/trailing_empty_array.rs similarity index 98% rename from tests/ui/trailing_zero_sized_array_without_repr.rs rename to tests/ui/trailing_empty_array.rs index bfa3af0bbc3..501c9eb7651 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.rs +++ b/tests/ui/trailing_empty_array.rs @@ -1,4 +1,4 @@ -#![warn(clippy::trailing_zero_sized_array_without_repr)] +#![warn(clippy::trailing_empty_array)] #![feature(const_generics_defaults)] // Do lint: diff --git a/tests/ui/trailing_zero_sized_array_without_repr.stderr b/tests/ui/trailing_empty_array.stderr similarity index 82% rename from tests/ui/trailing_zero_sized_array_without_repr.stderr rename to tests/ui/trailing_empty_array.stderr index 93c607bbf38..d88aa0504b5 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr.stderr +++ b/tests/ui/trailing_empty_array.stderr @@ -1,5 +1,5 @@ error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:6:1 + --> $DIR/trailing_empty_array.rs:6:1 | LL | / struct RarelyUseful { LL | | field: i32, @@ -7,11 +7,11 @@ LL | | last: [usize; 0], LL | | } | |_^ | - = note: `-D clippy::trailing-zero-sized-array-without-repr` implied by `-D warnings` + = note: `-D clippy::trailing-empty-array` implied by `-D warnings` = help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:11:1 + --> $DIR/trailing_empty_array.rs:11:1 | LL | / struct OnlyField { LL | | first_and_last: [usize; 0], @@ -21,7 +21,7 @@ LL | | } = help: consider annotating `OnlyField` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:15:1 + --> $DIR/trailing_empty_array.rs:15:1 | LL | / struct GenericArrayType { LL | | field: i32, @@ -32,7 +32,7 @@ LL | | } = help: consider annotating `GenericArrayType` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:21:1 + --> $DIR/trailing_empty_array.rs:21:1 | LL | / struct OnlyAnotherAttribute { LL | | field: i32, @@ -43,7 +43,7 @@ LL | | } = help: consider annotating `OnlyAnotherAttribute` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:29:1 + --> $DIR/trailing_empty_array.rs:27:1 | LL | / struct OnlyADeriveAttribute { LL | | field: i32, @@ -54,7 +54,7 @@ LL | | } = help: consider annotating `OnlyADeriveAttribute` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:35:1 + --> $DIR/trailing_empty_array.rs:33:1 | LL | / struct ZeroSizedWithConst { LL | | field: i32, @@ -65,7 +65,7 @@ LL | | } = help: consider annotating `ZeroSizedWithConst` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:44:1 + --> $DIR/trailing_empty_array.rs:42:1 | LL | / struct ZeroSizedWithConstFunction { LL | | field: i32, @@ -76,7 +76,7 @@ LL | | } = help: consider annotating `ZeroSizedWithConstFunction` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:52:1 + --> $DIR/trailing_empty_array.rs:50:1 | LL | / struct ZeroSizedWithConstFunction2 { LL | | field: i32, @@ -87,7 +87,7 @@ LL | | } = help: consider annotating `ZeroSizedWithConstFunction2` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:57:1 + --> $DIR/trailing_empty_array.rs:55:1 | LL | struct ZeroSizedArrayWrapper([usize; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | struct ZeroSizedArrayWrapper([usize; 0]); = help: consider annotating `ZeroSizedArrayWrapper` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:59:1 + --> $DIR/trailing_empty_array.rs:57:1 | LL | struct TupleStruct(i32, [usize; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | struct TupleStruct(i32, [usize; 0]); = help: consider annotating `TupleStruct` with `#[repr(C)]` or another `repr` attribute error: trailing zero-sized array in a struct which is not marked with a `repr` attribute - --> $DIR/trailing_zero_sized_array_without_repr.rs:61:1 + --> $DIR/trailing_empty_array.rs:59:1 | LL | / struct LotsOfFields { LL | | f1: u32, From 6b22bba902e873a9cceb3f5649d10a195699267d Mon Sep 17 00:00:00 2001 From: F3real Date: Mon, 4 Oct 2021 23:49:53 +0200 Subject: [PATCH 094/100] Lint on underscore variable assignment Fix tests after no_effect update Add a drop testcase Don't lint _ variables in macro expansion Address review comments and update tests Don't shadow unnecessary operation lint if no_effect is allowed Revert shadowing change and remove no_effect allows Update clippy_lints/src/no_effect.rs Co-authored-by: Takayuki Nakata Update clippy_lints/src/no_effect.rs Co-authored-by: Takayuki Nakata Address review comments --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/no_effect.rs | 179 ++++++++++++++-------- tests/ui/cfg_attr_rustfmt.fixed | 2 +- tests/ui/cfg_attr_rustfmt.rs | 2 +- tests/ui/no_effect.rs | 8 +- tests/ui/no_effect.stderr | 28 +++- tests/ui/option_if_let_else.fixed | 3 +- tests/ui/option_if_let_else.rs | 3 +- tests/ui/option_if_let_else.stderr | 28 ++-- 11 files changed, 170 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e837d363a..b7a7a421532 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2899,6 +2899,7 @@ Released 2018-09-13 [`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect +[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 7d81fafe4c9..e5fe22ad394 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -362,6 +362,7 @@ neg_multiply::NEG_MULTIPLY, new_without_default::NEW_WITHOUT_DEFAULT, no_effect::NO_EFFECT, + no_effect::NO_EFFECT_UNDERSCORE_BINDING, no_effect::UNNECESSARY_OPERATION, non_copy_const::BORROW_INTERIOR_MUTABLE_CONST, non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 6533b94e82b..268349d2848 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -72,6 +72,7 @@ LintId::of(needless_continue::NEEDLESS_CONTINUE), LintId::of(needless_for_each::NEEDLESS_FOR_EACH), LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), + LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING), LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES), LintId::of(non_expressive_names::SIMILAR_NAMES), LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE), diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index c5a5cde4b11..6dae8f32043 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,9 +1,10 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; +use clippy_utils::is_lint_allowed; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; +use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::ops::Deref; @@ -13,7 +14,7 @@ /// Checks for statements which have no effect. /// /// ### Why is this bad? - /// Similar to dead code, these statements are actually + /// Unlike dead code, these statements are actually /// executed. However, as they have no effect, all they do is make the code less /// readable. /// @@ -26,6 +27,28 @@ "statements with no effect" } +declare_clippy_lint! { + /// ### What it does + /// Checks for binding to underscore prefixed variable without side-effects. + /// + /// ### Why is this bad? + /// Unlike dead code, these bindings are actually + /// executed. However, as they have no effect and shouldn't be used further on, all they + /// do is make the code less readable. + /// + /// ### Known problems + /// Further usage of this variable is not checked, which can lead to false positives if it is + /// used later in the code. + /// + /// ### Example + /// ```rust,ignore + /// let _i_serve_no_purpose = 1; + /// ``` + pub NO_EFFECT_UNDERSCORE_BINDING, + pedantic, + "binding to `_` prefixed variable with no side-effect" +} + declare_clippy_lint! { /// ### What it does /// Checks for expression statements that can be reduced to a @@ -44,6 +67,46 @@ "outer expressions with no effect" } +declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]); + +impl<'tcx> LateLintPass<'tcx> for NoEffect { + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { + if check_no_effect(cx, stmt) { + return; + } + check_unnecessary_operation(cx, stmt); + } +} + +fn check_no_effect(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> bool { + if let StmtKind::Semi(expr) = stmt.kind { + if has_no_effect(cx, expr) { + span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); + return true; + } + } else if let StmtKind::Local(local) = stmt.kind { + if_chain! { + if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id); + if let Some(init) = local.init; + if !local.pat.span.from_expansion(); + if has_no_effect(cx, init); + if let PatKind::Binding(_, _, ident, _) = local.pat.kind; + if ident.name.to_ident_string().starts_with('_'); + then { + span_lint_hir( + cx, + NO_EFFECT_UNDERSCORE_BINDING, + init.hir_id, + stmt.span, + "binding to `_` prefixed variable with no side-effect" + ); + return true; + } + } + } + false +} + fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if expr.span.from_expansion() { return false; @@ -88,71 +151,59 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } } -declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION]); - -impl<'tcx> LateLintPass<'tcx> for NoEffect { - fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Semi(expr) = stmt.kind { - if has_no_effect(cx, expr) { - span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); - } else if let Some(reduced) = reduce_expression(cx, expr) { - for e in &reduced { - if e.span.from_expansion() { +fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { + if_chain! { + if let StmtKind::Semi(expr) = stmt.kind; + if let Some(reduced) = reduce_expression(cx, expr); + if !&reduced.iter().any(|e| e.span.from_expansion()); + then { + if let ExprKind::Index(..) = &expr.kind { + let snippet; + if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { + snippet = format!("assert!({}.len() > {});", &arr, &func); + } else { + return; + } + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be written as", + snippet, + Applicability::MaybeIncorrect, + ); + }, + ); + } else { + let mut snippet = String::new(); + for e in reduced { + if let Some(snip) = snippet_opt(cx, e.span) { + snippet.push_str(&snip); + snippet.push(';'); + } else { return; } } - if let ExprKind::Index(..) = &expr.kind { - let snippet; - if_chain! { - if let Some(arr) = snippet_opt(cx, reduced[0].span); - if let Some(func) = snippet_opt(cx, reduced[1].span); - then { - snippet = format!("assert!({}.len() > {});", &arr, &func); - } else { - return; - } - } - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "unnecessary operation", - |diag| { - diag.span_suggestion( - stmt.span, - "statement can be written as", - snippet, - Applicability::MaybeIncorrect, - ); - }, - ); - } else { - let mut snippet = String::new(); - for e in reduced { - if let Some(snip) = snippet_opt(cx, e.span) { - snippet.push_str(&snip); - snippet.push(';'); - } else { - return; - } - } - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "unnecessary operation", - |diag| { - diag.span_suggestion( - stmt.span, - "statement can be reduced to", - snippet, - Applicability::MachineApplicable, - ); - }, - ); - } + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be reduced to", + snippet, + Applicability::MachineApplicable, + ); + }, + ); } } } diff --git a/tests/ui/cfg_attr_rustfmt.fixed b/tests/ui/cfg_attr_rustfmt.fixed index 4e583a25b94..061a4ab9b2e 100644 --- a/tests/ui/cfg_attr_rustfmt.fixed +++ b/tests/ui/cfg_attr_rustfmt.fixed @@ -1,7 +1,7 @@ // run-rustfix #![feature(stmt_expr_attributes)] -#![allow(unused, clippy::no_effect)] +#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] #![warn(clippy::deprecated_cfg_attr)] // This doesn't get linted, see known problems diff --git a/tests/ui/cfg_attr_rustfmt.rs b/tests/ui/cfg_attr_rustfmt.rs index 9c0fcf6fb45..035169fab85 100644 --- a/tests/ui/cfg_attr_rustfmt.rs +++ b/tests/ui/cfg_attr_rustfmt.rs @@ -1,7 +1,7 @@ // run-rustfix #![feature(stmt_expr_attributes)] -#![allow(unused, clippy::no_effect)] +#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] #![warn(clippy::deprecated_cfg_attr)] // This doesn't get linted, see known problems diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 7ec845adfaa..7bcc4cad0d3 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,5 +1,5 @@ #![feature(box_syntax)] -#![warn(clippy::no_effect)] +#![warn(clippy::no_effect_underscore_binding)] #![allow(dead_code)] #![allow(path_statements)] #![allow(clippy::deref_addrof)] @@ -90,6 +90,10 @@ fn main() { || x += 5; let s: String = "foo".into(); FooString { s: s }; + let _unused = 1; + let _penguin = || println!("Some helpful closure"); + let _duck = Struct { field: 0 }; + let _cat = [2, 4, 6, 8][2]; #[allow(clippy::no_effect)] 0; @@ -97,6 +101,8 @@ fn main() { // Do not warn get_number(); unsafe { unsafe_fn() }; + let _used = get_struct(); + let _x = vec![1]; DropUnit; DropStruct { field: 0 }; DropTuple(0); diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index 6b24675ac2d..a5dbc9fef45 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -156,5 +156,31 @@ error: statement with no effect LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: binding to `_` prefixed variable with no side-effect + --> $DIR/no_effect.rs:93:5 + | +LL | let _unused = 1; + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` + +error: binding to `_` prefixed variable with no side-effect + --> $DIR/no_effect.rs:94:5 + | +LL | let _penguin = || println!("Some helpful closure"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: binding to `_` prefixed variable with no side-effect + --> $DIR/no_effect.rs:95:5 + | +LL | let _duck = Struct { field: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: binding to `_` prefixed variable with no side-effect + --> $DIR/no_effect.rs:96:5 + | +LL | let _cat = [2, 4, 6, 8][2]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 30 previous errors diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index a3ebe5d0703..4077f1920a3 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,8 +1,7 @@ // edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] +#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { string.map_or((false, "hello"), |x| (true, x)) diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index b11df3db60f..2f414e129d5 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,8 +1,7 @@ // edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] -#![allow(clippy::redundant_closure)] -#![allow(clippy::ref_option_ref, clippy::equatable_if_let)] +#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index ed748ee8b39..803d941c36d 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:8:5 + --> $DIR/option_if_let_else.rs:7:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -11,19 +11,19 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:26:13 + --> $DIR/option_if_let_else.rs:25:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:27:13 + --> $DIR/option_if_let_else.rs:26:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:28:13 + --> $DIR/option_if_let_else.rs:27:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -43,13 +43,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:34:13 + --> $DIR/option_if_let_else.rs:33:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:35:13 + --> $DIR/option_if_let_else.rs:34:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -69,7 +69,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:41:13 + --> $DIR/option_if_let_else.rs:40:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -89,7 +89,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:50:5 + --> $DIR/option_if_let_else.rs:49:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -108,7 +108,7 @@ LL + }) | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:63:13 + --> $DIR/option_if_let_else.rs:62:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -120,7 +120,7 @@ LL | | }; | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:72:13 + --> $DIR/option_if_let_else.rs:71:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -143,13 +143,13 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:101:13 + --> $DIR/option_if_let_else.rs:100:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:110:13 + --> $DIR/option_if_let_else.rs:109:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -171,13 +171,13 @@ LL ~ }); | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:138:13 + --> $DIR/option_if_let_else.rs:137:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:142:13 + --> $DIR/option_if_let_else.rs:141:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ From 083a4546f6a93be70da2538bf9bd73a0b88c8236 Mon Sep 17 00:00:00 2001 From: dswij Date: Wed, 20 Oct 2021 13:41:44 +0800 Subject: [PATCH 095/100] Small refactor on `question_mark` condition checks --- clippy_lints/src/question_mark.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index c1ee20c370a..4d616e26bfc 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -60,13 +60,8 @@ fn check_is_none_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); if let ExprKind::MethodCall(segment, _, args, _) = &cond.kind; if let Some(subject) = args.get(0); - if (Self::is_option(cx, subject) - && Self::expression_returns_none(cx, then) - && segment.ident.name == sym!(is_none)) - || - (Self::is_result(cx, subject) - && Self::expression_returns_unmodified_err(cx, then, subject) - && segment.ident.name == sym!(is_err)); + if (Self::option_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_none)) || + (Self::result_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_err)); then { let mut applicability = Applicability::MachineApplicable; let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability); @@ -109,13 +104,8 @@ fn check_if_let_some_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<' if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) = higher::IfLet::hir(cx, expr); if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind; - if (Self::is_option(cx, let_expr) - && Self::expression_returns_none(cx, if_else) - && is_lang_ctor(cx, path1, OptionSome)) - || - (Self::is_result(cx, let_expr) - && Self::expression_returns_unmodified_err(cx, if_else, let_expr) - && is_lang_ctor(cx, path1, ResultOk)); + if (Self::option_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, OptionSome)) || + (Self::result_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, ResultOk)); if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind; let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); @@ -141,6 +131,14 @@ fn check_if_let_some_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<' } } + fn result_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool { + Self::is_result(cx, expr) && Self::expression_returns_unmodified_err(cx, nested_expr, expr) + } + + fn option_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool { + Self::is_option(cx, expr) && Self::expression_returns_none(cx, nested_expr) + } + fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expression); From 9cf68e40fe37106e22859b67fb204145467162d5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 20 Oct 2021 13:46:12 +0200 Subject: [PATCH 096/100] Fix doc heading of TRANSMUTE_NUM_TO_BYTES --- clippy_lints/src/transmute/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 374999473a4..e6acf1a94c9 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -263,7 +263,7 @@ } declare_clippy_lint! { - /// # What it does + /// ### What it does /// Checks for transmutes from a number to an array of `u8` /// /// ### Why this is bad? From 3630afb57f5c98c83210adde07a92f6ebdce7fc7 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 14 Oct 2021 12:16:35 +0200 Subject: [PATCH 097/100] Do not lint if any parent has hidden attribute --- clippy_lints/src/doc.rs | 12 ++++++++++++ tests/ui/doc_unsafe.rs | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 9840affbf6f..5511c3ea9b6 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,3 +1,4 @@ +use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note}; use clippy_utils::source::first_line_of_span; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; @@ -297,6 +298,17 @@ fn lint_for_missing_headers<'tcx>( if !cx.access_levels.is_exported(def_id) { return; // Private functions do not require doc comments } + + // do not lint if any parent has `#[doc(hidden)]` attribute (#7347) + if cx + .tcx + .hir() + .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id)) + .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) + { + return; + } + if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe { span_lint( cx, diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index 8f823f1672b..03bb30f9083 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -115,3 +115,13 @@ fn main() { drive(); } } + +// do not lint if any parent has `#[doc(hidden)]` attribute +// see #7347 +#[doc(hidden)] +pub mod __macro { + pub struct T; + impl T { + pub unsafe fn f() {} + } +} From abb7ae9a79cdeeb6a892f19120a87ed4dba77b17 Mon Sep 17 00:00:00 2001 From: surechen Date: Thu, 21 Oct 2021 14:33:43 +0800 Subject: [PATCH 098/100] Fix typo for INVALID_NULL_PTR_USAGE and MISSING_INLINE_IN_PUBLIC_ITEMS. --- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/ptr.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 667cdd83025..b593c747498 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -8,7 +8,7 @@ declare_clippy_lint! { /// ### What it does - /// it lints if an exported function, method, trait method with default impl, + /// It lints if an exported function, method, trait method with default impl, /// or trait method impl is not `#[inline]`. /// /// ### Why is this bad? diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index d180d6f9227..92a4801a846 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -139,6 +139,7 @@ /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); } /// ``` /// + /// ```ignore /// // Good /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); } /// ``` From 122233091ad36e010796cb9a9b3b0836b0d16f8e Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 21 Oct 2021 12:19:32 +0200 Subject: [PATCH 099/100] Bump Clippy Version -> 0.1.58 --- Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_utils/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ba3ed3053ac..ed7fb144013 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.57" +version = "0.1.58" 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/Cargo.toml b/clippy_lints/Cargo.toml index 7900dc6d041..aaf9ac83d49 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.57" +version = "0.1.58" 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_utils/Cargo.toml b/clippy_utils/Cargo.toml index e7fca3ae5d4..d99a3d9359e 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.57" +version = "0.1.58" edition = "2021" publish = false From 8e48333bf19218fef59cf1e998ac3704033fc5dd Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 21 Oct 2021 12:19:46 +0200 Subject: [PATCH 100/100] Bump nightly version -> 2021-10-21 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index f98819303e6..67eaf286004 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-10-07" +channel = "nightly-2021-10-21" components = ["llvm-tools-preview", "rustc-dev", "rust-src"]