From e6e6e7d211d74e54dba121165bfb92116da85c33 Mon Sep 17 00:00:00 2001 From: dswij Date: Mon, 27 Sep 2021 14:26:29 +0800 Subject: [PATCH 01/65] Change `unseparated_literal_suffix` type to restriction --- clippy_lints/src/lib.register_pedantic.rs | 1 - clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/misc_early/mod.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 6533b94e82bd5..c249fb39938b9 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -65,7 +65,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ 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), diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 4463dea5fcb84..419a40b1bb8a6 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -35,6 +35,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::UNWRAP_USED), LintId::of(misc::FLOAT_CMP_CONST), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), + LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), 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), diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index b32feab4ee3e7..5aad08cdd46c0 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -128,7 +128,7 @@ declare_clippy_lint! { /// let y = 123832_i32; /// ``` pub UNSEPARATED_LITERAL_SUFFIX, - pedantic, + restriction, "literals whose suffix is not separated by an underscore" } From 449d68d47ced094d5b3ca2eb9d480c720d4e6395 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 14 Oct 2021 16:41:46 -0500 Subject: [PATCH 02/65] Fix clippy with for loop span change --- clippy_lints/src/vec.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index d124d948b5e69..d3234b5758a57 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -63,13 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg))); then { // report the error around the `vec!` not inside `:` - let span = arg.span - .ctxt() - .outer_expn_data() - .call_site - .ctxt() - .outer_expn_data() - .call_site; + let span = arg.span.ctxt().outer_expn_data().call_site; self.check_vec_macro(cx, &vec_args, Mutability::Not, span); } } From 4679eb3a0d09219b4bd815c636eb55e5b05c5a5e Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Wed, 20 Oct 2021 06:13:42 +0200 Subject: [PATCH 03/65] Move const int value code to utils --- .../src/invalid_upcast_comparisons.rs | 68 +------------------ clippy_utils/src/consts.rs | 68 +++++++++++++++++++ 2 files changed, 71 insertions(+), 65 deletions(-) diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index b1f70b30c12cf..82438d85c7a3a 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -1,5 +1,3 @@ -use std::cmp::Ordering; - use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; @@ -7,11 +5,11 @@ use rustc_middle::ty::{self, IntTy, UintTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; +use clippy_utils::comparisons; use clippy_utils::comparisons::Rel; -use clippy_utils::consts::{constant, Constant}; +use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; -use clippy_utils::{comparisons, sext}; declare_clippy_lint! { /// ### What it does @@ -39,53 +37,6 @@ declare_clippy_lint! { declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]); -#[derive(Copy, Clone, Debug, Eq)] -enum FullInt { - S(i128), - U(u128), -} - -impl FullInt { - #[allow(clippy::cast_sign_loss)] - #[must_use] - fn cmp_s_u(s: i128, u: u128) -> Ordering { - if s < 0 { - Ordering::Less - } else if u > (i128::MAX as u128) { - Ordering::Greater - } else { - (s as u128).cmp(&u) - } - } -} - -impl PartialEq for FullInt { - #[must_use] - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal - } -} - -impl PartialOrd for FullInt { - #[must_use] - fn partial_cmp(&self, other: &Self) -> Option { - Some(match (self, other) { - (&Self::S(s), &Self::S(o)) => s.cmp(&o), - (&Self::U(s), &Self::U(o)) => s.cmp(&o), - (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o), - (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(), - }) - } -} - -impl Ord for FullInt { - #[must_use] - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other) - .expect("`partial_cmp` for FullInt can never return `None`") - } -} - fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> { if let ExprKind::Cast(cast_exp, _) = expr.kind { let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp); @@ -118,19 +69,6 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> } } -fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { - let val = constant(cx, cx.typeck_results(), expr)?.0; - if let Constant::Int(const_int) = val { - match *cx.typeck_results().expr_ty(expr).kind() { - ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))), - ty::Uint(_) => Some(FullInt::U(const_int)), - _ => None, - } - } else { - None - } -} - fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) { if let ExprKind::Cast(cast_val, _) = expr.kind { span_lint( @@ -156,7 +94,7 @@ fn upcast_comparison_bounds_err<'tcx>( invert: bool, ) { if let Some((lb, ub)) = lhs_bounds { - if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) { + if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) { if rel == Rel::Eq || rel == Rel::Ne { if norm_rhs_val < lb || norm_rhs_val > ub { err_upcast_comparison(cx, span, lhs, rel == Rel::Ne); diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 8bf31807d55d1..3e5d74a66f4e8 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -155,6 +155,19 @@ impl Constant { _ => None, } } + + /// Returns the integer value or `None` if `self` or `val_type` is not integer type. + pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option { + if let Constant::Int(const_int) = *self { + match *val_type.kind() { + ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))), + ty::Uint(_) => Some(FullInt::U(const_int)), + _ => None, + } + } else { + None + } + } } /// Parses a `LitKind` to a `Constant`. @@ -202,6 +215,61 @@ pub fn constant_simple<'tcx>( constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) } +pub fn constant_full_int( + lcx: &LateContext<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + e: &Expr<'_>, +) -> Option { + constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e)) +} + +#[derive(Copy, Clone, Debug, Eq)] +pub enum FullInt { + S(i128), + U(u128), +} + +impl FullInt { + #[allow(clippy::cast_sign_loss)] + #[must_use] + fn cmp_s_u(s: i128, u: u128) -> Ordering { + if s < 0 { + Ordering::Less + } else if u > (i128::MAX as u128) { + Ordering::Greater + } else { + (s as u128).cmp(&u) + } + } +} + +impl PartialEq for FullInt { + #[must_use] + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal + } +} + +impl PartialOrd for FullInt { + #[must_use] + fn partial_cmp(&self, other: &Self) -> Option { + Some(match (self, other) { + (&Self::S(s), &Self::S(o)) => s.cmp(&o), + (&Self::U(s), &Self::U(o)) => s.cmp(&o), + (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o), + (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(), + }) + } +} + +impl Ord for FullInt { + #[must_use] + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other) + .expect("`partial_cmp` for FullInt can never return `None`") + } +} + /// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. pub fn constant_context<'a, 'tcx>( lcx: &'a LateContext<'tcx>, From c4d5471a45dbdddccb74bb505864cab284df21fd Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Wed, 20 Oct 2021 06:13:42 +0200 Subject: [PATCH 04/65] Add test for #7829 --- tests/ui/match_overlapping_arm.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index ff91c4498ec62..845986a4eadab 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -100,6 +100,13 @@ fn overlapping() { _ => (), } + // Issue #7829 + match 0 { + -1..=1 => (), + -2..=2 => (), + _ => (), + } + if let None = Some(42) { // nothing } else if let None = Some(42) { From 1ede540b2135ce56546cb5f28fbf5c000646363f Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Wed, 20 Oct 2021 06:13:42 +0200 Subject: [PATCH 05/65] Fix false positive in `match_overlapping_arm` The bug was dues to the constant bytes being compared instead of their values. This meant that negative values were being treated as larger than some positive values. Fixes #7829 --- clippy_lints/src/matches.rs | 51 ++++++++++--------------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index b643fba5d3288..f1289a36e7770 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, miri_to_const, Constant}; +use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt}; use clippy_utils::diagnostics::{ multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; @@ -930,9 +930,8 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() { let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex)); - let type_ranges = type_ranges(&ranges); - if !type_ranges.is_empty() { - if let Some((start, end)) = overlapping(&type_ranges) { + if !ranges.is_empty() { + if let Some((start, end)) = overlapping(&ranges) { span_lint_and_note( cx, MATCH_OVERLAPPING_ARM, @@ -1601,7 +1600,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<' } /// Gets all arms that are unbounded `PatRange`s. -fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec> { +fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec> { arms.iter() .filter_map(|arm| { if let Arm { pat, guard: None, .. } = *arm { @@ -1614,21 +1613,25 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?, }; - let rhs = match range_end { - RangeEnd::Included => Bound::Included(rhs), - RangeEnd::Excluded => Bound::Excluded(rhs), + + let lhs_val = lhs.int_value(cx, ty)?; + let rhs_val = rhs.int_value(cx, ty)?; + + let rhs_bound = match range_end { + RangeEnd::Included => Bound::Included(rhs_val), + RangeEnd::Excluded => Bound::Excluded(rhs_val), }; return Some(SpannedRange { span: pat.span, - node: (lhs, rhs), + node: (lhs_val, rhs_bound), }); } if let PatKind::Lit(value) = pat.kind { - let value = constant(cx, cx.typeck_results(), value)?.0; + let value = constant_full_int(cx, cx.typeck_results(), value)?; return Some(SpannedRange { span: pat.span, - node: (value.clone(), Bound::Included(value)), + node: (value, Bound::Included(value)), }); } } @@ -1643,32 +1646,6 @@ pub struct SpannedRange { pub node: (T, Bound), } -type TypedRanges = Vec>; - -/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway -/// and other types than -/// `Uint` and `Int` probably don't make sense. -fn type_ranges(ranges: &[SpannedRange]) -> TypedRanges { - ranges - .iter() - .filter_map(|range| match range.node { - (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange { - span: range.span, - node: (start, Bound::Included(end)), - }), - (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange { - span: range.span, - node: (start, Bound::Excluded(end)), - }), - (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange { - span: range.span, - node: (start, Bound::Unbounded), - }), - _ => None, - }) - .collect() -} - // Checks if arm has the form `None => None` fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone)) From 7631fc5d822afc69d82e738ddf365d8e97f72c22 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 21 Oct 2021 13:11:36 +0200 Subject: [PATCH 06/65] Merge commit '91496c2ac6abf6454c413bb23e8becf6b6dc20ea' into clippyup --- CHANGELOG.md | 9 + Cargo.toml | 2 +- clippy_dev/Cargo.toml | 1 + clippy_dev/src/main.rs | 6 + clippy_dev/src/new_lint.rs | 220 +++++++++----- clippy_dev/src/update_lints.rs | 4 +- clippy_lints/Cargo.toml | 2 +- .../src/casts/fn_to_numeric_cast_any.rs | 34 +++ clippy_lints/src/casts/mod.rs | 39 +++ clippy_lints/src/copies.rs | 10 +- clippy_lints/src/default.rs | 8 + clippy_lints/src/disallowed_type.rs | 69 +++-- clippy_lints/src/doc.rs | 12 + clippy_lints/src/eq_op.rs | 11 +- clippy_lints/src/equatable_if_let.rs | 8 +- clippy_lints/src/format.rs | 51 +--- clippy_lints/src/format_args.rs | 223 ++++++++++++++ clippy_lints/src/functions/mod.rs | 12 +- clippy_lints/src/identity_op.rs | 1 - clippy_lints/src/if_then_panic.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/inherent_to_string.rs | 8 +- clippy_lints/src/let_underscore.rs | 7 +- clippy_lints/src/lib.register_all.rs | 5 + clippy_lints/src/lib.register_complexity.rs | 1 + clippy_lints/src/lib.register_correctness.rs | 2 + clippy_lints/src/lib.register_lints.rs | 9 + clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/lib.register_perf.rs | 2 + clippy_lints/src/lib.register_restriction.rs | 2 + clippy_lints/src/lib.rs | 15 +- clippy_lints/src/match_result_ok.rs | 2 +- clippy_lints/src/match_str_case_mismatch.rs | 171 +++++++++++ clippy_lints/src/matches.rs | 10 +- clippy_lints/src/methods/mod.rs | 11 +- .../src/methods/uninit_assumed_init.rs | 14 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/mut_mut.rs | 4 + clippy_lints/src/no_effect.rs | 179 +++++++---- clippy_lints/src/ptr.rs | 1 + clippy_lints/src/question_mark.rs | 74 +++-- .../src/semicolon_if_nothing_returned.rs | 4 +- clippy_lints/src/shadow.rs | 6 +- .../src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/trailing_empty_array.rs | 77 +++++ clippy_lints/src/transmute/mod.rs | 25 ++ .../src/transmute/transmute_int_to_char.rs | 2 +- .../src/transmute/transmute_int_to_float.rs | 2 +- .../src/transmute/transmute_num_to_bytes.rs | 49 +++ .../src/undocumented_unsafe_blocks.rs | 225 ++++++++++++++ clippy_lints/src/uninit_vec.rs | 223 ++++++++++++++ clippy_lints/src/unnecessary_sort_by.rs | 11 +- clippy_lints/src/utils/conf.rs | 10 +- clippy_lints/src/utils/internal_lints.rs | 3 +- clippy_lints/src/vec_init_then_push.rs | 52 +--- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/higher.rs | 157 +++++++++- clippy_utils/src/lib.rs | 118 ++++--- clippy_utils/src/paths.rs | 20 ++ clippy_utils/src/ty.rs | 10 + doc/basics.md | 1 + rust-toolchain | 2 +- tests/compile-test.rs | 14 + .../ui-internal/unnecessary_symbol_str.stderr | 5 +- .../ui-toml/toml_disallowed_type/clippy.toml | 6 +- .../conf_disallowed_type.rs | 4 + .../conf_disallowed_type.stderr | 34 ++- tests/ui/auxiliary/macro_rules.rs | 7 + tests/ui/cfg_attr_rustfmt.fixed | 2 +- tests/ui/cfg_attr_rustfmt.rs | 2 +- tests/ui/doc_unsafe.rs | 10 + tests/ui/equatable_if_let.fixed | 9 + tests/ui/equatable_if_let.rs | 9 + tests/ui/equatable_if_let.stderr | 8 +- tests/ui/expect_fun_call.fixed | 1 + tests/ui/expect_fun_call.rs | 1 + tests/ui/expect_fun_call.stderr | 24 +- tests/ui/field_reassign_with_default.rs | 64 ++++ tests/ui/field_reassign_with_default.stderr | 26 +- tests/ui/fn_to_numeric_cast_any.rs | 76 +++++ tests/ui/fn_to_numeric_cast_any.stderr | 106 +++++++ tests/ui/format.fixed | 2 +- tests/ui/format.rs | 2 +- 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 +++++++++++ tests/ui/implicit_saturating_sub.fixed | 8 + tests/ui/implicit_saturating_sub.rs | 8 + tests/ui/match_expr_like_matches_macro.stderr | 35 +-- tests/ui/match_overlapping_arm.rs | 59 ++-- tests/ui/match_overlapping_arm.stderr | 34 ++- tests/ui/match_ref_pats.rs | 42 +++ tests/ui/match_ref_pats.stderr | 57 +--- tests/ui/match_str_case_mismatch.rs | 98 ++++++ tests/ui/match_str_case_mismatch.stderr | 36 +++ tests/ui/mut_mut.rs | 10 + tests/ui/mut_mut.stderr | 18 +- 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 +- tests/ui/question_mark.fixed | 17 ++ tests/ui/question_mark.rs | 19 ++ tests/ui/question_mark.stderr | 16 +- tests/ui/semicolon_if_nothing_returned.rs | 12 + tests/ui/shadow.rs | 5 + tests/ui/shadow.stderr | 60 ++-- tests/ui/to_string_in_display.rs | 2 +- tests/ui/trailing_empty_array.rs | 186 ++++++++++++ tests/ui/trailing_empty_array.stderr | 120 ++++++++ tests/ui/transmute.rs | 27 ++ tests/ui/transmute.stderr | 92 +++++- tests/ui/undocumented_unsafe_blocks.rs | 287 ++++++++++++++++++ tests/ui/undocumented_unsafe_blocks.stderr | 159 ++++++++++ tests/ui/uninit_vec.rs | 94 ++++++ tests/ui/uninit_vec.stderr | 105 +++++++ tests/ui/unnecessary_sort_by.fixed | 5 + tests/ui/unnecessary_sort_by.rs | 5 + tests/ui/unnecessary_sort_by.stderr | 24 +- tests/ui/wildcard_imports.fixed | 8 + tests/ui/wildcard_imports.rs | 8 + tests/ui/wildcard_imports.stderr | 8 +- tests/ui_test/eq_op.rs | 15 + 127 files changed, 4334 insertions(+), 628 deletions(-) create mode 100644 clippy_lints/src/casts/fn_to_numeric_cast_any.rs create mode 100644 clippy_lints/src/format_args.rs create mode 100644 clippy_lints/src/match_str_case_mismatch.rs create mode 100644 clippy_lints/src/trailing_empty_array.rs create mode 100644 clippy_lints/src/transmute/transmute_num_to_bytes.rs create mode 100644 clippy_lints/src/undocumented_unsafe_blocks.rs create mode 100644 clippy_lints/src/uninit_vec.rs create mode 100644 tests/ui/fn_to_numeric_cast_any.rs create mode 100644 tests/ui/fn_to_numeric_cast_any.stderr 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 create mode 100644 tests/ui/match_str_case_mismatch.rs create mode 100644 tests/ui/match_str_case_mismatch.stderr create mode 100644 tests/ui/trailing_empty_array.rs create mode 100644 tests/ui/trailing_empty_array.stderr create mode 100644 tests/ui/undocumented_unsafe_blocks.rs create mode 100644 tests/ui/undocumented_unsafe_blocks.stderr create mode 100644 tests/ui/uninit_vec.rs create mode 100644 tests/ui/uninit_vec.stderr create mode 100644 tests/ui_test/eq_op.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index e700e5f0d736e..3b4c687209e11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2730,11 +2730,13 @@ 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 [`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 @@ -2836,6 +2838,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 @@ -2896,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 @@ -3012,16 +3016,19 @@ 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 [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg +[`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 [`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 @@ -3031,10 +3038,12 @@ 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 [`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/Cargo.toml b/Cargo.toml index ba3ed3053ac74..ed7fb1440139f 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_dev/Cargo.toml b/clippy_dev/Cargo.toml index 4a13a45240976..affb283017c8c 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/main.rs b/clippy_dev/src/main.rs index 8fdeba9842af3..b5c04efce3bc9 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 3a81aaba6de04..25320907bb492 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}; @@ -32,7 +33,7 @@ impl Context for io::Result { /// # 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,29 +41,12 @@ 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<()> { - 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( - pass_type, - pass_lifetimes, - lint.name, - &camel_case_name, - lint.category, - pass_import, - context_import, - ); +fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { + 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()) @@ -122,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 ); @@ -140,64 +125,143 @@ 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 ) } -fn get_lint_file_contents( - pass_type: &str, - pass_lifetimes: &str, - lint_name: &str, - camel_case_name: &str, - category: &str, - pass_import: &str, - context_import: &str, -) -> String { - format!( - "use rustc_lint::{{{type}, {context_import}}}; -use rustc_session::{{declare_lint_pass, declare_tool_lint}}; -{pass_import} - -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\" -}} - -declare_lint_pass!({name_camel} => [{name_upper}]); - -impl {type}{lifetimes} for {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 - ) +fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { + let mut result = String::new(); + + 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 { + format!( + 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!( + 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 + ) + }); + + result.push_str(&format!( + 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!( + indoc! {" + 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!( + 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})); + "}, + 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] diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 10d859988f6f2..23f58bc4915f9 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -619,8 +619,8 @@ mod tests { 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/Cargo.toml b/clippy_lints/Cargo.toml index 7900dc6d04141..aaf9ac83d4900 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_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 0000000000000..03621887a34a6 --- /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 27e1bea799353..f0800c6a6f18f 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -7,6 +7,7 @@ mod cast_ref_to_mut; 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 @@ declare_clippy_lint! { "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 @@ impl_lint_pass!(Casts => [ 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 @@ impl<'tcx> LateLintPass<'tcx> for Casts { 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/copies.rs b/clippy_lints/src/copies.rs index b7385dcfbca19..8abf10c0d1c2d 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -459,12 +459,10 @@ fn emit_branches_sharing_code_lint( } else { sm.stmt_span(block.stmts[block.stmts.len() - end_stmts].span, block.span) }; - let moved_end = block - .expr - .map_or_else( - || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span), - |expr| expr.span.source_callsite(), - ); + let moved_end = block.expr.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/default.rs b/clippy_lints/src/default.rs index db8f2171348f7..cde27d3ad2a0c 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 @@ impl LateLintPass<'_> for Default { .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/clippy_lints/src/disallowed_type.rs b/clippy_lints/src/disallowed_type.rs index 87124f093a86d..48f781516f422 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 @@ -19,7 +21,15 @@ declare_clippy_lint! { /// 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 @@ -38,33 +48,30 @@ declare_clippy_lint! { } #[derive(Clone, Debug)] pub struct DisallowedType { - disallowed: FxHashSet>, - def_ids: FxHashSet, - prim_tys: FxHashSet, + conf_disallowed: Vec, + def_ids: FxHashMap>, + prim_tys: FxHashMap>, } impl DisallowedType { - pub fn new(disallowed: &FxHashSet) -> Self { + pub fn new(conf_disallowed: Vec) -> Self { Self { - disallowed: disallowed - .iter() - .map(|s| s.split("::").map(Symbol::intern).collect::>()) - .collect(), - def_ids: FxHashSet::default(), - prim_tys: FxHashSet::default(), + conf_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 +83,21 @@ impl_lint_pass!(DisallowedType => [DISALLOWED_TYPE]); 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.conf_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 +121,16 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedType { } } -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/doc.rs b/clippy_lints/src/doc.rs index 9840affbf6fd8..5511c3ea9b688 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/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 51d5094e8c998..655560afd4250 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 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { 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 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { 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_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 0c6ba91c9430b..e8b1d6f6edaaa 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 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { 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 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { "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/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 37d9ea3bdc117..c22f9d0e17032 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 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { 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, @@ -101,47 +100,3 @@ fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicabi 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 0000000000000..8b27442aa9465 --- /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/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 04fc5887e8e8b..d7c5ec9ba355b 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -91,11 +91,9 @@ declare_clippy_lint! { 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! { 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! { 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/identity_op.rs b/clippy_lints/src/identity_op.rs index 73bdd67ff5d25..414f465c49414 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() { diff --git a/clippy_lints/src/if_then_panic.rs b/clippy_lints/src/if_then_panic.rs index 10bca59e6d06a..e8cea5529e889 100644 --- a/clippy_lints/src/if_then_panic.rs +++ b/clippy_lints/src/if_then_panic.rs @@ -78,10 +78,10 @@ impl LateLintPass<'_> for IfThenPanic { 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/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 79d4d7ddcbced..a4f60ded3a6e0 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { 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/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 3c40ca50a0981..61dd0eb4af7ed 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/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 89146b4dd2c9b..9efd7aba7e83b 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -10,12 +10,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; 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 diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 6a3ee35b41a4b..c949ee23ecc7a 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -60,6 +60,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), @@ -118,6 +120,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), @@ -265,6 +268,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), @@ -277,6 +281,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 64b82fc0faac8..c51341bdf0c23 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -82,6 +82,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! 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_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index bbe47a0e772f7..ff56a6081fb57 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -36,6 +36,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve 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_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), @@ -62,6 +63,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve 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 b0be3b653664c..e8dd3708c8ed4 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -67,6 +67,7 @@ store.register_lints(&[ 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, @@ -138,6 +139,8 @@ store.register_lints(&[ 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, @@ -225,6 +228,7 @@ store.register_lints(&[ 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, @@ -359,6 +363,7 @@ store.register_lints(&[ 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, @@ -438,6 +443,7 @@ store.register_lints(&[ temporary_assignment::TEMPORARY_ASSIGNMENT, to_digit_is_some::TO_DIGIT_IS_SOME, to_string_in_display::TO_STRING_IN_DISPLAY, + trailing_empty_array::TRAILING_EMPTY_ARRAY, trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS, trait_bounds::TYPE_REPETITION_IN_BOUNDS, transmute::CROSSPOINTER_TRANSMUTE, @@ -447,6 +453,7 @@ store.register_lints(&[ 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, @@ -463,10 +470,12 @@ store.register_lints(&[ 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, 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.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 96e0b421094d6..1e54482a8dafd 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -25,6 +25,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), + 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.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 6533b94e82bd5..268349d284811 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -72,6 +72,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ 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/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index 5432345760bc3..a0d5cf9418e0b 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.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 4463dea5fcb84..3d68a6e900958 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -8,6 +8,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve 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), @@ -56,6 +57,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve 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 5534f9c94f367..ed7e827702395 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -218,6 +218,7 @@ mod float_equality_without_abs; mod float_literal; mod floating_point_arithmetic; mod format; +mod format_args; mod formatting; mod from_over_into; mod from_str_radix_10; @@ -265,6 +266,7 @@ mod map_err_ignore; mod map_unit_fn; mod match_on_vec_items; mod match_result_ok; +mod match_str_case_mismatch; mod matches; mod mem_forget; mod mem_replace; @@ -352,13 +354,16 @@ mod tabs_in_doc_comments; mod temporary_assignment; mod to_digit_is_some; mod to_string_in_display; +mod trailing_empty_array; mod trait_bounds; mod transmute; mod transmuting_null; mod try_err; mod types; +mod undocumented_unsafe_blocks; mod undropped_manually_drops; mod unicode; +mod uninit_vec; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -516,6 +521,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)); @@ -754,8 +760,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(); @@ -767,6 +773,11 @@ 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())); + 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_empty_array::TrailingEmptyArray)); + } #[rustfmt::skip] diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 3db1f0421ea70..ecf6ad316a461 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -35,7 +35,7 @@ declare_clippy_lint! { /// } /// /// if let Ok(value) = iter.next() { - /// vec.push_value) + /// vec.push(value) /// } /// ``` pub MATCH_RESULT_OK, 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 0000000000000..a83f38e3d516e --- /dev/null +++ b/clippy_lints/src/match_str_case_mismatch.rs @@ -0,0 +1,171 @@ +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}; +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::symbol::SymbolStr; +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 + /// # let text = "Foo"; + /// + /// match &*text.to_ascii_lowercase() { + /// "foo" => {}, + /// "Bar" => {}, + /// _ => {}, + /// } + /// ``` + /// Use instead: + /// ```rust + /// # let text = "Foo"; + /// + /// 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_span, bad_case_str)) = verify_case(&case_method, arms) { + lint(cx, &case_method, bad_case_span, &bad_case_str); + } + } + } + } + } +} + +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<'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')) }, + 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; + let input = symbol.as_str(); + if !case_check(&input); + then { + return Some((lit.span, input)); + } + } + } + + None +} + +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_sugg( + cx, + MATCH_STR_CASE_MISMATCH, + 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/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 56d4163a6b343..b643fba5d3288 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1187,7 +1187,7 @@ where '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 @@ where }) { 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/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b26d11c0d6b0d..26c29fbb289cb 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1777,14 +1777,13 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **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. + /// ### What it does + /// Checks for usages of `str::splitn(2, _)` /// - /// **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()?; diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 1a5894e48d14c..ce89189bce977 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, paths, ty::is_uninit_value_valid_for_ty}; 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_value_valid_for_ty(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/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 667cdd8302528..b593c747498e3 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -8,7 +8,7 @@ use rustc_span::sym; 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/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 610152a217f1e..7c4cac29ba8e8 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -82,6 +82,10 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { } 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/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index c5a5cde4b110f..6dae8f320436f 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 @@ declare_clippy_lint! { /// 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 @@ declare_clippy_lint! { "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 @@ declare_clippy_lint! { "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() { - 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, - ); - }, - ); +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 { - 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; - } + 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/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index d180d6f922710..92a4801a8468a 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -139,6 +139,7 @@ declare_clippy_lint! { /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); } /// ``` /// + /// ```ignore /// // Good /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); } /// ``` diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index aa6d254e7a544..4d616e26bfc1d 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -4,10 +4,10 @@ use clippy_utils::is_lang_ctor; 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,20 @@ 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::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); @@ -95,31 +99,24 @@ impl QuestionMark { } } - 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::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); - 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, @@ -134,6 +131,14 @@ impl QuestionMark { } } + 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); @@ -146,6 +151,12 @@ impl QuestionMark { 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 +172,27 @@ impl QuestionMark { } } + 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 +221,7 @@ impl QuestionMark { 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); } } diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 6966230156cfa..c0e4914efe0bd 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 @@ declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED] 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/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 2ca7c18800ee2..64841f33cc385 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/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 44d5ff0b63ad5..201aa06782405 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/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs new file mode 100644 index 0000000000000..c216a1f81ea54 --- /dev/null +++ b/clippy_lints/src/trailing_empty_array.rs @@ -0,0 +1,77 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_hir::{HirId, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Const; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// 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 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 + /// struct RarelyUseful { + /// some_field: u32, + /// last: [u32; 0], + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// #[repr(C)] + /// struct MoreOftenUseful { + /// some_field: usize, + /// last: [u32; 0], + /// } + /// ``` + pub TRAILING_EMPTY_ARRAY, + nursery, + "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute" +} +declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]); + +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_EMPTY_ARRAY, + item.span, + "trailing zero-sized array in a struct which is not marked with a `repr` attribute", + None, + &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 { + 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; + + // 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 + } + } +} + +fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { + cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr)) +} diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 33ec9c331ce56..e6acf1a94c929 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -3,6 +3,7 @@ mod transmute_float_to_int; 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 @@ declare_clippy_lint! { "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 @@ declare_lint_pass!(Transmute => [ 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 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { 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_int_to_char.rs b/clippy_lints/src/transmute/transmute_int_to_char.rs index 8f884e6a4a17b..e83d2e06b9a8d 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 2b6a4cff81eb5..05eee380d6f40 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 new file mode 100644 index 0000000000000..5ba58a7649401 --- /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), + Applicability::Unspecified, + ); + }, + ); + true + }, + _ => false, + } +} diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs new file mode 100644 index 0000000000000..e08e4d03c7efe --- /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/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs new file mode 100644 index 0000000000000..f3e8b6881058f --- /dev/null +++ b/clippy_lints/src/uninit_vec.rs @@ -0,0 +1,223 @@ +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}; +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}; + +// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std +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 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. 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. + /// + /// ### Example + /// ```rust,ignore + /// let mut vec: Vec = Vec::with_capacity(1000); + /// unsafe { vec.set_len(1000); } + /// reader.read(&mut vec); // undefined behavior! + /// ``` + /// + /// ### 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" +} + +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<'_>) { + 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); + } + } + } +} + +fn handle_uninit_vec_pair( + cx: &LateContext<'tcx>, + maybe_init_or_reserve: &'tcx Stmt<'tcx>, + maybe_set_len: &'tcx Expr<'tcx>, +) { + 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.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(); + // `#[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 { + 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", + ); + } + } + } +} + +/// 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> VecLocation<'tcx> { + pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + match self { + 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> { + 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 let Some(init_kind) = get_vec_init_kind(cx, init_expr); + then { + 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 let Some(init_kind) = get_vec_init_kind(cx, rhs) { + return Some(TargetVec { + location: VecLocation::Expr(lhs), + init_kind: Some(init_kind), + }); + } + }, + 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 +} + +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()` +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 { + // 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)), _) => Some(expr), + _ => None, + } + } else { + None + } + }); + match expr.kind { + 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/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index dd74bf367f3a5..26b56e0f2f316 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 })); } } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 6cbada4c1505b..d05c52122d5ee 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 @@ define_Conf! { /// 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/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 9f9edbf258ac2..824ec53ab9c75 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -770,8 +770,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id(); // Check if the matched type is a diagnostic item - let diag_items = cx.tcx.diagnostic_items(ty_did.krate); - if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None }); + if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did); then { // TODO: check paths constants from external crates. let cx_snippet = snippet(cx, context.span, "_"); diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index d8e241d72af48..b92b6ca4f4380 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -1,16 +1,14 @@ 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::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, path_to_local, path_to_local_id, paths}; +use clippy_utils::{path_to_local, path_to_local_id}; 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 +39,6 @@ pub struct VecInitThenPush { searcher: Option, } -#[derive(Clone, Copy)] -enum VecInitKind { - New, - WithCapacity(u64), -} struct VecPushSearcher { local_id: HirId, init: VecInitKind, @@ -58,7 +51,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 +146,3 @@ impl LateLintPass<'_> for VecInitThenPush { } } } - -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/Cargo.toml b/clippy_utils/Cargo.toml index e7fca3ae5d401..d99a3d9359e1f 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 diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 74cf323720cbb..60c4cb361aa6c 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -2,13 +2,16 @@ #![deny(clippy::missing_docs_in_private_items)] -use crate::{is_expn_of, match_def_path, paths}; +use crate::ty::is_type_diagnostic_item; +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; -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}; +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)`. @@ -569,6 +572,106 @@ impl FormatArgsExpn<'tcx> { } } } + + /// 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. @@ -631,3 +734,51 @@ impl PanicExpn<'tcx> { } } } + +/// 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 == symbol::kw::Default { + return Some(VecInitKind::Default); + } else if name.ident.name.as_str() == "with_capacity" { + 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)) + 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 8e94d16a33a0e..9bc380ca6caa6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -69,11 +69,13 @@ use rustc_hir::def::{DefKind, Res}; 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; @@ -251,11 +253,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 { @@ -1285,10 +1283,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. @@ -1315,7 +1312,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 { @@ -1338,13 +1335,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() { @@ -1467,11 +1464,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 @@ -2062,27 +2057,80 @@ 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 -/// 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<'_>) {} +} + +/// 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 +} - matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test") +/// 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/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 81aff585ded1b..501b08a47f161 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -17,6 +17,12 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [ #[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"]; @@ -41,11 +47,17 @@ pub const DROP: [&str; 3] = ["core", "mem", "drop"]; 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"]; @@ -108,6 +120,10 @@ pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "Permis 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"]; @@ -184,3 +200,7 @@ pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; 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/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 6ebe1a0028a31..ca64ac7de3eea 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/doc/basics.md b/doc/basics.md index ff2e0417435bf..57a90a924ec3c 100644 --- a/doc/basics.md +++ b/doc/basics.md @@ -96,6 +96,7 @@ cargo dev setup git-hook # (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. diff --git a/rust-toolchain b/rust-toolchain index f98819303e682..67eaf286004f9 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"] diff --git a/tests/compile-test.rs b/tests/compile-test.rs index e8b1640c8693e..c15835ef29956 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-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr index 8e04d447fbcaa..12e05eaa7a09a 100644 --- a/tests/ui-internal/unnecessary_symbol_str.stderr +++ b/tests/ui-internal/unnecessary_symbol_str.stderr @@ -27,12 +27,13 @@ error: unnecessary `Symbol` to string conversion --> $DIR/unnecessary_symbol_str.rs:14:5 | LL | &*Ident::empty().as_str() == "clippy"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::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::empty().to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name` error: aborting due to 5 previous errors + diff --git a/tests/ui-toml/toml_disallowed_type/clippy.toml b/tests/ui-toml/toml_disallowed_type/clippy.toml index dac4446703b0f..6cb9e2ef95467 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 0871a3073abd3..410f076505511 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 @@ struct GenArg([u8; U]); 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 90ce7db2cc4e6..08a400a83675b 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 diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 170955e726cc5..0251fada9e85a 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/cfg_attr_rustfmt.fixed b/tests/ui/cfg_attr_rustfmt.fixed index 4e583a25b94c2..061a4ab9b2ef8 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 9c0fcf6fb454c..035169fab85be 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/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index 8f823f1672ba2..03bb30f9083ac 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() {} + } +} diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index ba72cc237b4a5..88918d9671e42 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 12526ca193db6..9a7ab75ef450f 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 79ef919384df2..760ff88f448f0 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 diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index a756d1cf50659..cf923a6a5940c 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 60bbaa89d4282..e6f252259df70 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 6dc796f5cee37..ac48a06671cd2 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/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 787053fb00064..7367910eaa126 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 b56db08ec8a78..3ce4b91a54869 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 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 0000000000000..46704683926b2 --- /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 0000000000000..a6c4a77672f86 --- /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 + diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 5dd64140e8116..73fc750511c78 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 4599fb5207ea8..2f4595650cbf3 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/format_args.fixed b/tests/ui/format_args.fixed new file mode 100644 index 0000000000000..8376566c4d62d --- /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 0000000000000..164cc07066dc3 --- /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 0000000000000..9cfc97edeafb8 --- /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 0000000000000..a8c06c2bde664 --- /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 0000000000000..4476218ad58e9 --- /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 + diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 859765d08a70b..e6f57e9267eac 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 2f32a7b157821..8bb28d149c628 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"); + } } diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr index 366ef36c367bf..d7cedf9f9f159 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_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index 846d665d1d864..ff91c4498ec62 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -10,98 +10,95 @@ 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"), _ => (), } - /* - // 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 359fa49f51be7..c2b3f173c2b80 100644 --- a/tests/ui/match_overlapping_arm.stderr +++ b/tests/ui/match_overlapping_arm.stderr @@ -1,63 +1,75 @@ 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 +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 diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 6cbb4d32b0d71..50246486bb6fc 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -72,4 +72,46 @@ mod 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 072aff445e97f..901820077e20e 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,30 @@ 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 + --> $DIR/match_ref_pats.rs:101:9 | -LL | / match foo_variant!(0) { -LL | | &Foo::A => println!("A"), +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 *foo_variant!(0) { -LL ~ Foo::A => println!("A"), +LL ~ match *foobar_variant!(0) { +LL ~ FooBar::Foo => println!("Foo"), +LL ~ FooBar::Bar => println!("Bar"), +LL ~ FooBar::FooBar => println!("FooBar"), | -error: aborting due to 8 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs new file mode 100644 index 0000000000000..208a4bba3d23c --- /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 0000000000000..fa023477a9c33 --- /dev/null +++ b/tests/ui/match_str_case_mismatch.stderr @@ -0,0 +1,36 @@ +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:68:9 + | +LL | "Bar" => {}, + | ^^^^^ + | + = 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` 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 + diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 8965cef66dedd..be854d9418332 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 0fed6953cb85c..6820a85aa5433 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; | ^^^^^^^^^^^^^ diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 7ec845adfaacf..7bcc4cad0d363 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 6b24675ac2d42..a5dbc9fef455a 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 a3ebe5d070384..4077f1920a383 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 b11df3db60f57..2f414e129d5a7 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 ed748ee8b39e4..803d941c36df8 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) { | _____________^ diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 0b5746cb52270..ccb2e5a302e91 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 0f0825c933467..ca3722371f524 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -134,6 +134,23 @@ fn func() -> 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 6f330cfa385dd..161588cb73cba 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 diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs index 9644a23296831..7a45f1b18d4af 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!(); +} diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 02e838456d0b5..55caef59f7f68 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 8b60e072c9342..feed6e1ba8b86 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 diff --git a/tests/ui/to_string_in_display.rs b/tests/ui/to_string_in_display.rs index eb8105c6b6da0..3ccdcd1117b5a 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; diff --git a/tests/ui/trailing_empty_array.rs b/tests/ui/trailing_empty_array.rs new file mode 100644 index 0000000000000..501c9eb7651f8 --- /dev/null +++ b/tests/ui/trailing_empty_array.rs @@ -0,0 +1,186 @@ +#![warn(clippy::trailing_empty_array)] +#![feature(const_generics_defaults)] + +// Do lint: + +struct RarelyUseful { + field: i32, + last: [usize; 0], +} + +struct OnlyField { + first_and_last: [usize; 0], +} + +struct GenericArrayType { + field: i32, + last: [T; 0], +} + +#[must_use] +struct OnlyAnotherAttribute { + field: i32, + last: [usize; 0], +} + +#[derive(Debug)] +struct OnlyADeriveAttribute { + field: i32, + last: [usize; 0], +} + +const ZERO: usize = 0; +struct ZeroSizedWithConst { + field: i32, + last: [usize; ZERO], +} + +#[allow(clippy::eq_op)] +const fn compute_zero() -> usize { + (4 + 6) - (2 * 5) +} +struct ZeroSizedWithConstFunction { + field: i32, + 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]); + +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], +} + +// Don't lint + +#[repr(C)] +struct GoodReason { + field: i32, + last: [usize; 0], +} + +#[repr(C)] +struct OnlyFieldWithReprC { + first_and_last: [usize; 0], +} + +struct NonZeroSizedArray { + field: i32, + last: [usize; 1], +} + +struct NotLastField { + f1: u32, + zero_sized: [usize; 0], + last: i32, +} + +const ONE: usize = 1; +struct NonZeroSizedWithConst { + field: i32, + last: [usize; ONE], +} + +#[derive(Debug)] +#[repr(C)] +struct AlsoADeriveAttribute { + field: i32, + last: [usize; 0], +} + +#[must_use] +#[repr(C)] +struct AlsoAnotherAttribute { + field: i32, + last: [usize; 0], +} + +#[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] }, +} + +#[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], +} + +struct TwoGenericParams { + field: i32, + last: [T; N], +} + +type A = ConstParamZeroDefault; +type B = ConstParamZeroDefault<0>; +type C = ConstParamNoDefault<0>; +type D = ConstParamNonZeroDefault<0>; + +fn main() {} diff --git a/tests/ui/trailing_empty_array.stderr b/tests/ui/trailing_empty_array.stderr new file mode 100644 index 0000000000000..d88aa0504b537 --- /dev/null +++ b/tests/ui/trailing_empty_array.stderr @@ -0,0 +1,120 @@ +error: trailing zero-sized array in a struct which is not marked with a `repr` attribute + --> $DIR/trailing_empty_array.rs:6:1 + | +LL | / struct RarelyUseful { +LL | | field: i32, +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = 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_empty_array.rs:11:1 + | +LL | / struct OnlyField { +LL | | first_and_last: [usize; 0], +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_empty_array.rs:15:1 + | +LL | / struct GenericArrayType { +LL | | field: i32, +LL | | last: [T; 0], +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_empty_array.rs:21:1 + | +LL | / struct OnlyAnotherAttribute { +LL | | field: i32, +LL | | last: [usize; 0], +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_empty_array.rs:27:1 + | +LL | / struct OnlyADeriveAttribute { +LL | | field: i32, +LL | | last: [usize; 0], +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_empty_array.rs:33:1 + | +LL | / struct ZeroSizedWithConst { +LL | | field: i32, +LL | | last: [usize; ZERO], +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_empty_array.rs:42:1 + | +LL | / struct ZeroSizedWithConstFunction { +LL | | field: i32, +LL | | last: [usize; compute_zero()], +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_empty_array.rs:50: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_empty_array.rs:55:1 + | +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_empty_array.rs:57:1 + | +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_empty_array.rs:59:1 + | +LL | / struct LotsOfFields { +LL | | f1: u32, +LL | | f2: u32, +LL | | f3: u32, +... | +LL | | last: [usize; 0], +LL | | } + | |_^ + | + = help: consider annotating `LotsOfFields` with `#[repr(C)]` or another `repr` attribute + +error: aborting due to 11 previous errors + diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index bce4c81b78aa1..6a7037d8f3826 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -103,6 +103,33 @@ mod int_to_float { } } +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 e31accb982af3..86537153e3228 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 diff --git a/tests/ui/undocumented_unsafe_blocks.rs b/tests/ui/undocumented_unsafe_blocks.rs new file mode 100644 index 0000000000000..52577323a5837 --- /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 0000000000000..613e9ffca4565 --- /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 + diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs new file mode 100644 index 0000000000000..dc150cf28f2cc --- /dev/null +++ b/tests/ui/uninit_vec.rs @@ -0,0 +1,94 @@ +#![warn(clippy::uninit_vec)] + +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); + unsafe { + vec.set_len(200); + } + + // reserve() -> set_len() should be detected + vec.reserve(1000); + unsafe { + 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); + vec.set_len(200); + + vec.reserve(1000); + 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); + } + + // 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); + 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); + } + + // known false negative + let mut vec1: Vec = Vec::with_capacity(1000); + let mut vec2: Vec = Vec::with_capacity(1000); + unsafe { + vec1.set_len(200); + vec2.set_len(200); + } +} diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr new file mode 100644 index 0000000000000..520bfb26b62e1 --- /dev/null +++ b/tests/ui/uninit_vec.stderr @@ -0,0 +1,105 @@ +error: calling `set_len()` immediately after reserving a buffer creates uninitialized values + --> $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` + = 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:18:5 + | +LL | vec.reserve(1000); + | ^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +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(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + +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(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + +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(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + +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); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +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:58: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:63: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:42:9 + | +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:45:9 + | +LL | vec.reserve(1000); + | ^^^^^^^^^^^^^^^^^^ +LL | vec.set_len(200); + | ^^^^^^^^^^^^^^^^ + | + = help: initialize the buffer or wrap the content in `MaybeUninit` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index b45b27d8f23b1..d806d620b176a 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 be2abe7f7014d..6ee9c3af455df 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 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.stderr b/tests/ui/unnecessary_sort_by.stderr index 50607933e18f7..ca9641e880316 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()))` diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index ee9c9045fff55..98bc1e80731ff 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 efaa8f9ef6641..4ef61f9245b58 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -231,4 +231,12 @@ mod super_imports { 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 66267dd27b84f..d7af0c046e886 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 diff --git a/tests/ui_test/eq_op.rs b/tests/ui_test/eq_op.rs new file mode 100644 index 0000000000000..f2f5f1e588ed4 --- /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 1e8d9fb18c5bba7577cea524282dd5cbbc7ec702 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 21 Oct 2021 08:50:50 -0700 Subject: [PATCH 07/65] Handle 'implementation safety' headers as well --- clippy_lints/src/doc.rs | 2 ++ tests/ui/doc_unsafe.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 5511c3ea9b688..c14a3604c2ff8 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -579,6 +579,8 @@ fn check_doc<'a, Events: Iterator, Range Date: Thu, 21 Oct 2021 18:00:57 +0200 Subject: [PATCH 08/65] Fix deploy script I broke this script in #7502, so that the stable symlink isn't generated anymore. This reverts this change. --- .github/deploy.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/deploy.sh b/.github/deploy.sh index a3c57232f557c..34225a5402904 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -13,7 +13,8 @@ cp util/gh-pages/lints.json out/master if [[ -n $TAG_NAME ]]; then echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it" cp -Tr out/master "out/$TAG_NAME" - ln -sf "$TAG_NAME" out/stable + rm -f out/stable + ln -s "$TAG_NAME" out/stable fi if [[ $BETA = "true" ]]; then From 566244a8bcd4f94a0c8c2491c2abde552ee46558 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Wed, 20 Oct 2021 21:44:05 +0200 Subject: [PATCH 09/65] Do not lint when cast is coming from `signum` method call --- clippy_lints/src/casts/cast_possible_truncation.rs | 12 ++++++++++-- clippy_lints/src/casts/mod.rs | 2 +- tests/ui/cast.rs | 8 ++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 833ad122e0d4e..2ae7d16e00bb2 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,12 +1,20 @@ use clippy_utils::diagnostics::span_lint; +use clippy_utils::expr_or_init; use clippy_utils::ty::is_isize_or_usize; -use rustc_hir::Expr; +use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; use super::{utils, CAST_POSSIBLE_TRUNCATION}; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { + // do not lint if cast comes from a `signum` function + if let ExprKind::MethodCall(path, ..) = expr_or_init(cx, cast_expr).kind { + if path.ident.name.as_str() == "signum" { + return; + } + } + let msg = match (cast_from.is_integral(), cast_to.is_integral()) { (true, true) => { let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index f0800c6a6f18f..233abd178943e 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { 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) { - cast_possible_truncation::check(cx, expr, cast_from, cast_to); + cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to); diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 8ee0969b0f076..adc95e63ae565 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -92,4 +92,12 @@ fn main() { (1i64).checked_rem_euclid(-1i64).unwrap() as u64; (1i64).checked_rem_euclid(-1i64).unwrap() as u128; (1isize).checked_rem_euclid(-1isize).unwrap() as usize; + + // no lint for `cast_possible_truncation` + // with `signum` method call (see issue #5395) + let x: i64 = 5; + let _ = x.signum() as i32; + + let s = x.signum(); + let _ = s as i32; } From 081d0f82f490b886753cf2cf32da8076050a5a6c Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 11 Oct 2021 01:03:11 +0100 Subject: [PATCH 10/65] Make useless_format recognize format!("") Closes #7796 --- clippy_lints/src/format.rs | 34 +++++++++++++++++++++++++--------- tests/ui/format.fixed | 2 ++ tests/ui/format.rs | 2 ++ tests/ui/format.stderr | 28 +++++++++++++++++----------- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index c22f9d0e17032..7169ac9ad6c5a 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -49,15 +49,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { let mut applicability = Applicability::MachineApplicable; if format_args.value_args.is_empty() { - if_chain! { - if let [e] = &*format_args.format_string_parts; - if let ExprKind::Lit(lit) = &e.kind; - if let Some(s_src) = snippet_opt(cx, lit.span); - then { - // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = s_src.replace("{{", "{").replace("}}", "}"); - let sugg = format!("{}.to_string()", s_expand); - span_useless_format(cx, call_site, sugg, applicability); + if format_args.format_string_parts.is_empty() { + span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability); + } else { + if_chain! { + if let [e] = &*format_args.format_string_parts; + if let ExprKind::Lit(lit) = &e.kind; + if let Some(s_src) = snippet_opt(cx, lit.span); + then { + // Simulate macro expansion, converting {{ and }} to { and }. + let s_expand = s_src.replace("{{", "{").replace("}}", "}"); + let sugg = format!("{}.to_string()", s_expand); + span_useless_format(cx, call_site, sugg, applicability); + } } } } else if let [value] = *format_args.value_args { @@ -89,6 +93,18 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { } } +fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) { + span_lint_and_sugg( + cx, + USELESS_FORMAT, + span, + "useless use of `format!`", + "consider using `String::new()`", + sugg, + applicability, + ); +} + fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) { span_lint_and_sugg( cx, diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 73fc750511c78..64cb7b1cfb80f 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -16,6 +16,8 @@ fn main() { r##"foo {} " bar"##.to_string(); + let _ = String::new(); + "foo".to_string(); format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 2f4595650cbf3..a065b1b5683c1 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -18,6 +18,8 @@ fn main() { " bar"## ); + let _ = format!(""); + format!("{}", "foo"); format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 701399b32d628..58ad7499bb26f 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -34,64 +34,70 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> $DIR/format.rs:21:5 + --> $DIR/format.rs:21:13 + | +LL | let _ = format!(""); + | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` + +error: useless use of `format!` + --> $DIR/format.rs:23:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:25:5 + --> $DIR/format.rs:27:5 | LL | format!("{:+}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:26:5 + --> $DIR/format.rs:28:5 | LL | format!("{:<}", "foo"); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:31:5 + --> $DIR/format.rs:33:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:35:5 + --> $DIR/format.rs:37:5 | LL | format!("{:+}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:36:5 + --> $DIR/format.rs:38:5 | LL | format!("{:<}", arg); // Warn when the format makes no difference. | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:63:5 + --> $DIR/format.rs:65:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:65:5 + --> $DIR/format.rs:67:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:69:18 + --> $DIR/format.rs:71:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:73:22 + --> $DIR/format.rs:75:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors From 9def82d382220970760baa9d6480663bec3ebf97 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 21 Oct 2021 14:40:33 -0700 Subject: [PATCH 11/65] use a variable --- clippy_lints/src/doc.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index c14a3604c2ff8..ec67adf3f8766 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -578,11 +578,12 @@ fn check_doc<'a, Events: Iterator, Range Date: Fri, 22 Oct 2021 23:47:38 -0700 Subject: [PATCH 12/65] Fix `match_str_case_mismatch` false positives Properly consider uncased and titlecased characters. Fixes #7863. --- clippy_lints/src/match_str_case_mismatch.rs | 10 +-- tests/ui/match_str_case_mismatch.rs | 86 +++++++++++++++++++++ tests/ui/match_str_case_mismatch.stderr | 52 ++++++++++++- 3 files changed, 139 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/match_str_case_mismatch.rs index a83f38e3d516e..f501593c5187e 100644 --- a/clippy_lints/src/match_str_case_mismatch.rs +++ b/clippy_lints/src/match_str_case_mismatch.rs @@ -127,10 +127,10 @@ fn get_case_method(segment_ident_str: &str) -> Option { 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')) }, - CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) }, - CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) }, + CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) }, + CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) }, + CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) }, + CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) }, }; for arm in arms { @@ -153,7 +153,7 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<( 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::LowerCase => ("to_lowercase", 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()), diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs index 208a4bba3d23c..ac555c87d83b2 100644 --- a/tests/ui/match_str_case_mismatch.rs +++ b/tests/ui/match_str_case_mismatch.rs @@ -12,6 +12,49 @@ fn as_str_match() { } } +fn non_alphabetic() { + let var = "~!@#$%^&*()-_=+FOO"; + + match var.to_ascii_lowercase().as_str() { + "1234567890" => {}, + "~!@#$%^&*()-_=+foo" => {}, + "\n\r\t\x7F" => {}, + _ => {}, + } +} + +fn unicode_cased() { + let var = "ВОДЫ"; + + match var.to_lowercase().as_str() { + "水" => {}, + "νερό" => {}, + "воды" => {}, + "물" => {}, + _ => {}, + } +} + +fn titlecase() { + let var = "BarDz"; + + match var.to_lowercase().as_str() { + "foolj" => {}, + "bardz" => {}, + _ => {}, + } +} + +fn no_case_equivalent() { + let var = "barʁ"; + + match var.to_uppercase().as_str() { + "FOOɕ" => {}, + "BARʁ" => {}, + _ => {}, + } +} + fn addrof_unary_match() { let var = "BAR"; @@ -70,6 +113,49 @@ fn as_str_match_mismatch() { } } +fn non_alphabetic_mismatch() { + let var = "~!@#$%^&*()-_=+FOO"; + + match var.to_ascii_lowercase().as_str() { + "1234567890" => {}, + "~!@#$%^&*()-_=+Foo" => {}, + "\n\r\t\x7F" => {}, + _ => {}, + } +} + +fn unicode_cased_mismatch() { + let var = "ВОДЫ"; + + match var.to_lowercase().as_str() { + "水" => {}, + "νερό" => {}, + "Воды" => {}, + "물" => {}, + _ => {}, + } +} + +fn titlecase_mismatch() { + let var = "BarDz"; + + match var.to_lowercase().as_str() { + "foolj" => {}, + "barDz" => {}, + _ => {}, + } +} + +fn no_case_equivalent_mismatch() { + let var = "barʁ"; + + match var.to_uppercase().as_str() { + "FOOɕ" => {}, + "bARʁ" => {}, + _ => {}, + } +} + fn addrof_unary_match_mismatch() { let var = "BAR"; diff --git a/tests/ui/match_str_case_mismatch.stderr b/tests/ui/match_str_case_mismatch.stderr index fa023477a9c33..92baa40ef28f0 100644 --- a/tests/ui/match_str_case_mismatch.stderr +++ b/tests/ui/match_str_case_mismatch.stderr @@ -1,5 +1,5 @@ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:68:9 + --> $DIR/match_str_case_mismatch.rs:111:9 | LL | "Bar" => {}, | ^^^^^ @@ -11,7 +11,51 @@ LL | "bar" => {}, | ~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:78:9 + --> $DIR/match_str_case_mismatch.rs:121:9 + | +LL | "~!@#$%^&*()-_=+Foo" => {}, + | ^^^^^^^^^^^^^^^^^^^^ + | +help: consider changing the case of this arm to respect `to_ascii_lowercase` + | +LL | "~!@#$%^&*()-_=+foo" => {}, + | ~~~~~~~~~~~~~~~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:133:9 + | +LL | "Воды" => {}, + | ^^^^^^ + | +help: consider changing the case of this arm to respect `to_lowercase` + | +LL | "воды" => {}, + | ~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:144:9 + | +LL | "barDz" => {}, + | ^^^^^^ + | +help: consider changing the case of this arm to respect `to_lowercase` + | +LL | "bardz" => {}, + | ~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:154:9 + | +LL | "bARʁ" => {}, + | ^^^^^^ + | +help: consider changing the case of this arm to respect `to_uppercase` + | +LL | "BARʁ" => {}, + | ~~~~~~ + +error: this `match` arm has a differing case than its expression + --> $DIR/match_str_case_mismatch.rs:164:9 | LL | "Bar" => {}, | ^^^^^ @@ -22,7 +66,7 @@ LL | "bar" => {}, | ~~~~~ error: this `match` arm has a differing case than its expression - --> $DIR/match_str_case_mismatch.rs:93:9 + --> $DIR/match_str_case_mismatch.rs:179:9 | LL | "bAR" => {}, | ^^^^^ @@ -32,5 +76,5 @@ help: consider changing the case of this arm to respect `to_ascii_uppercase` LL | "BAR" => {}, | ~~~~~ -error: aborting due to 3 previous errors +error: aborting due to 7 previous errors From a5a3e6192dc0c4a5b7b83ff19f074df3cf526338 Mon Sep 17 00:00:00 2001 From: Dharma Saputra Wijaya Date: Sat, 23 Oct 2021 23:42:31 +0800 Subject: [PATCH 13/65] Fix typo on utils/lib --- clippy_utils/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9bc380ca6caa6..aeb8c12ae8b81 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -712,7 +712,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// Checks if the top level expression can be moved into a closure as is. /// Currently checks for: /// * Break/Continue outside the given loop HIR ids. -/// * Yield/Return statments. +/// * Yield/Return statements. /// * Inline assembly. /// * Usages of a field of a local where the type of the local can be partially moved. /// @@ -2123,7 +2123,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { vis.found } -/// Checks whether item either has `test` attribute appelied, or +/// Checks whether item either has `test` attribute applied, or /// is a module with `test` in its name. /// /// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`. From 1b91d986ea38ad121d760ab8c1320dd2fc5580f2 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 24 Oct 2021 17:42:13 +0200 Subject: [PATCH 14/65] Rename `clippy_utils::camal_case` to `clippy_utils::str_utils` --- clippy_lints/src/enum_variants.rs | 12 ++++++------ clippy_utils/src/lib.rs | 2 +- clippy_utils/src/{camel_case.rs => str_utils.rs} | 0 3 files changed, 7 insertions(+), 7 deletions(-) rename clippy_utils/src/{camel_case.rs => str_utils.rs} (100%) diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 174260fabd228..8d6f7d6fdf195 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,6 +1,6 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use clippy_utils::camel_case; +use clippy_utils::str_utils; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; use rustc_hir::{EnumDef, Item, ItemKind}; @@ -171,14 +171,14 @@ fn check_variant( } } let first = &def.variants[0].ident.name.as_str(); - let mut pre = &first[..camel_case::until(&*first)]; - let mut post = &first[camel_case::from(&*first)..]; + let mut pre = &first[..str_utils::until(&*first)]; + let mut post = &first[str_utils::from(&*first)..]; for var in def.variants { let name = var.ident.name.as_str(); let pre_match = partial_match(pre, &name); pre = &pre[..pre_match]; - let pre_camel = camel_case::until(pre); + let pre_camel = str_utils::until(pre); pre = &pre[..pre_camel]; while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { if next.is_numeric() { @@ -186,7 +186,7 @@ fn check_variant( } if next.is_lowercase() { let last = pre.len() - last.len_utf8(); - let last_camel = camel_case::until(&pre[..last]); + let last_camel = str_utils::until(&pre[..last]); pre = &pre[..last_camel]; } else { break; @@ -196,7 +196,7 @@ fn check_variant( let post_match = partial_rmatch(post, &name); let post_end = post.len() - post_match; post = &post[post_end..]; - let post_camel = camel_case::from(post); + let post_camel = str_utils::from(post); post = &post[post_camel..]; } let (what, value) = match (pre.is_empty(), post.is_empty()) { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index aeb8c12ae8b81..1c5186dba1bad 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -37,7 +37,7 @@ pub mod sym_helper; #[allow(clippy::module_name_repetitions)] pub mod ast_utils; pub mod attrs; -pub mod camel_case; +pub mod str_utils; pub mod comparisons; pub mod consts; pub mod diagnostics; diff --git a/clippy_utils/src/camel_case.rs b/clippy_utils/src/str_utils.rs similarity index 100% rename from clippy_utils/src/camel_case.rs rename to clippy_utils/src/str_utils.rs From 20fb7f291604267447ef95ee437f9bc8699879d1 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 24 Oct 2021 12:52:38 -0500 Subject: [PATCH 15/65] Update rustfmt --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/entry.rs | 13 +++++++----- clippy_lints/src/eta_reduction.rs | 17 ++++++++------- clippy_lints/src/int_plus_one.rs | 4 ++-- clippy_lints/src/loops/utils.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 4 ++-- clippy_lints/src/methods/or_fun_call.rs | 2 +- clippy_lints/src/module_style.rs | 2 +- clippy_lints/src/needless_borrow.rs | 20 ++++++++++-------- clippy_utils/src/higher.rs | 4 ++-- clippy_utils/src/lib.rs | 25 +++++++++++++---------- 11 files changed, 54 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 7825e5f6ed52e..ce59311c4aa96 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { target_mut, }, )); - } + }, _ => (), } }, diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index ac6824672f66c..57fd24bd4f04d 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -245,11 +245,14 @@ fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(Map ExprKind::MethodCall( _, _, - [map, Expr { - kind: ExprKind::AddrOf(_, _, key), - span: key_span, - .. - }], + [ + map, + Expr { + kind: ExprKind::AddrOf(_, _, key), + span: key_span, + .. + }, + ], _, ) if key_span.ctxt() == expr.span.ctxt() => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 765a6c7585a20..9247343b52a53 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -169,13 +169,16 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_ } match *cx.typeck_results().expr_adjustments(arg) { [] => true, - [Adjustment { - kind: Adjust::Deref(None), - .. - }, Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), - .. - }] => { + [ + Adjustment { + kind: Adjust::Deref(None), + .. + }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)), + .. + }, + ] => { // re-borrow with the same mutability is allowed let ty = cx.typeck_results().expr_ty(arg); matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into()) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 49b69dd072a21..6850e0c34767c 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -89,7 +89,7 @@ impl IntPlusOne { }, _ => None, } - } + }, // case where `x + 1 <= ...` or `1 + x <= ...` (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => @@ -104,7 +104,7 @@ impl IntPlusOne { }, _ => None, } - } + }, // case where `... >= y - 1` or `... >= -1 + y` (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) { diff --git a/clippy_lints/src/loops/utils.rs b/clippy_lints/src/loops/utils.rs index 2f7360210ba4d..f9f515cc40a0f 100644 --- a/clippy_lints/src/loops/utils.rs +++ b/clippy_lints/src/loops/utils.rs @@ -338,7 +338,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(), meth_name, ) - } + }, _ => format!( "{}.into_iter()", sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par() diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 1a32af5dc7a38..b4dacb2580c31 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -85,7 +85,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => { return; - } + }, ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) @@ -100,7 +100,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, ) => { return; - } + }, _ => false, }; diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index b5bbbb09092af..fe9ffde0d337c 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -186,7 +186,7 @@ pub(super) fn check<'tcx>( check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); } } - } + }, _ => (), } } diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index f351d0098b750..d41b547456499 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -106,7 +106,7 @@ impl EarlyLintPass for ModStyle { } process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders); check_self_named_mod_exists(cx, path, file); - } + }, _ => {}, } } diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 1b2495d764d2a..f1be90c44f98b 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -107,14 +107,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind { if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() { for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) { - if let [Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Deref(_), .. - }, Adjustment { - kind: Adjust::Borrow(_), - .. - }] = *adj3 + if let [ + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Borrow(_), + .. + }, + ] = *adj3 { let help_msg_ty = if matches!(mutability, Mutability::Not) { format!("&{}", ty) diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 60c4cb361aa6c..7cbd43e6266e9 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -770,13 +770,13 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - } return 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); - } + }, _ => (), } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index aeb8c12ae8b81..bcc38c7225604 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -844,10 +844,13 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind let mut capture_expr_ty = e; for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) { - if let [Adjustment { - kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), - target, - }, ref adjust @ ..] = *cx + if let [ + Adjustment { + kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), + target, + }, + ref adjust @ .., + ] = *cx .typeck_results() .adjustments() .get(child_id) @@ -1232,9 +1235,7 @@ pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Opti for (_, node) in tcx.hir().parent_iter(expr.hir_id) { match node { Node::Expr( - e - @ - Expr { + e @ Expr { kind: ExprKind::Loop(..) | ExprKind::Closure(..), .. }, @@ -1692,10 +1693,12 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool { pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Call( _, - &[Expr { - kind: ExprKind::Closure(_, _, body, _, _), - .. - }], + &[ + Expr { + kind: ExprKind::Closure(_, _, body, _, _), + .. + }, + ], ) = body.value.kind { if let ExprKind::Block( From d38fddd89908cae6767ad599388421f99f71840b Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 24 Oct 2021 21:06:17 +0200 Subject: [PATCH 16/65] Refactor `camel_case` util functions for new `StrIndex` --- clippy_lints/src/enum_variants.rs | 16 ++-- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/str_utils.rs | 144 +++++++++++++++++++----------- 3 files changed, 103 insertions(+), 59 deletions(-) diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 8d6f7d6fdf195..19f1781d0b046 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,8 +1,8 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use clippy_utils::str_utils; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; +use clippy_utils::str_utils; use rustc_hir::{EnumDef, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -171,14 +171,14 @@ fn check_variant( } } let first = &def.variants[0].ident.name.as_str(); - let mut pre = &first[..str_utils::until(&*first)]; - let mut post = &first[str_utils::from(&*first)..]; + let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index]; + let mut post = &first[str_utils::camel_case_start(&*first).byte_index..]; for var in def.variants { let name = var.ident.name.as_str(); let pre_match = partial_match(pre, &name); pre = &pre[..pre_match]; - let pre_camel = str_utils::until(pre); + let pre_camel = str_utils::camel_case_until(pre).byte_index; pre = &pre[..pre_camel]; while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() { if next.is_numeric() { @@ -186,8 +186,8 @@ fn check_variant( } if next.is_lowercase() { let last = pre.len() - last.len_utf8(); - let last_camel = str_utils::until(&pre[..last]); - pre = &pre[..last_camel]; + let last_camel = str_utils::camel_case_until(&pre[..last]); + pre = &pre[..last_camel.byte_index]; } else { break; } @@ -196,8 +196,8 @@ fn check_variant( let post_match = partial_rmatch(post, &name); let post_end = post.len() - post_match; post = &post[post_end..]; - let post_camel = str_utils::from(post); - post = &post[post_camel..]; + let post_camel = str_utils::camel_case_start(post); + post = &post[post_camel.byte_index..]; } let (what, value) = match (pre.is_empty(), post.is_empty()) { (true, true) => return, diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 1c5186dba1bad..0637ae3e97b6b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -37,7 +37,6 @@ pub mod sym_helper; #[allow(clippy::module_name_repetitions)] pub mod ast_utils; pub mod attrs; -pub mod str_utils; pub mod comparisons; pub mod consts; pub mod diagnostics; @@ -50,6 +49,7 @@ pub mod paths; pub mod ptr; pub mod qualify_min_const_fn; pub mod source; +pub mod str_utils; pub mod sugg; pub mod ty; pub mod usage; diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index a6636e391374e..f3de1250d5d80 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -1,117 +1,161 @@ +/// Dealing with sting indices can be hard, this struct ensures that both the +/// character and byte index are provided for correct indexing. +#[derive(Debug, Default, PartialEq, Eq)] +pub struct StrIndex { + pub char_index: usize, + pub byte_index: usize, +} + +impl StrIndex { + pub fn new(char_index: usize, byte_index: usize) -> Self { + Self { char_index, byte_index } + } +} + /// Returns the index of the character after the first camel-case component of `s`. +/// +/// ``` +/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6)); +/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0)); +/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3)); +/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7)); +/// ``` #[must_use] -pub fn until(s: &str) -> usize { - let mut iter = s.char_indices(); - if let Some((_, first)) = iter.next() { +pub fn camel_case_until(s: &str) -> StrIndex { + let mut iter = s.char_indices().enumerate(); + if let Some((_char_index, (_, first))) = iter.next() { if !first.is_uppercase() { - return 0; + return StrIndex::new(0, 0); } } else { - return 0; + return StrIndex::new(0, 0); } let mut up = true; - let mut last_i = 0; - for (i, c) in iter { + let mut last_index = StrIndex::new(0, 0); + for (char_index, (byte_index, c)) in iter { if up { if c.is_lowercase() { up = false; } else { - return last_i; + return last_index; } } else if c.is_uppercase() { up = true; - last_i = i; + last_index.byte_index = byte_index; + last_index.char_index = char_index; } else if !c.is_lowercase() { - return i; + return StrIndex::new(char_index, byte_index); } } - if up { last_i } else { s.len() } + + if up { + last_index + } else { + StrIndex::new(s.chars().count(), s.len()) + } } /// Returns index of the last camel-case component of `s`. +/// +/// ``` +/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0)); +/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3)); +/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4)); +/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4)); +/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6)); +/// ``` #[must_use] -pub fn from(s: &str) -> usize { - let mut iter = s.char_indices().rev(); - if let Some((_, first)) = iter.next() { +pub fn camel_case_start(s: &str) -> StrIndex { + let char_count = s.chars().count(); + let range = 0..char_count; + let mut iter = range.rev().zip(s.char_indices().rev()); + if let Some((char_index, (_, first))) = iter.next() { if !first.is_lowercase() { - return s.len(); + return StrIndex::new(char_index, s.len()); } } else { - return s.len(); + return StrIndex::new(char_count, s.len()); } let mut down = true; - let mut last_i = s.len(); - for (i, c) in iter { + let mut last_index = StrIndex::new(char_count, s.len()); + for (char_index, (byte_index, c)) in iter { if down { if c.is_uppercase() { down = false; - last_i = i; + last_index.byte_index = byte_index; + last_index.char_index = char_index; } else if !c.is_lowercase() { - return last_i; + return last_index; } } else if c.is_lowercase() { down = true; } else if c.is_uppercase() { - last_i = i; + last_index.byte_index = byte_index; + last_index.char_index = char_index; } else { - return last_i; + return last_index; } } - last_i + last_index } #[cfg(test)] mod test { - use super::{from, until}; + use super::*; #[test] - fn from_full() { - assert_eq!(from("AbcDef"), 0); - assert_eq!(from("Abc"), 0); - assert_eq!(from("ABcd"), 0); - assert_eq!(from("ABcdEf"), 0); - assert_eq!(from("AabABcd"), 0); + fn camel_case_start_full() { + assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0)); + assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0)); } #[test] - fn from_partial() { - assert_eq!(from("abcDef"), 3); - assert_eq!(from("aDbc"), 1); - assert_eq!(from("aabABcd"), 3); + fn camel_case_start_partial() { + assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3)); + assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1)); + assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3)); + assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4)); } #[test] - fn from_not() { - assert_eq!(from("AbcDef_"), 7); - assert_eq!(from("AbcDD"), 5); + fn camel_case_start_not() { + assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7)); + assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5)); + assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9)); + assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12)); } #[test] - fn from_caps() { - assert_eq!(from("ABCD"), 4); + fn camel_case_start_caps() { + assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4)); } #[test] - fn until_full() { - assert_eq!(until("AbcDef"), 6); - assert_eq!(until("Abc"), 3); + fn camel_case_until_full() { + assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6)); + assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3)); + assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9)); } #[test] - fn until_not() { - assert_eq!(until("abcDef"), 0); - assert_eq!(until("aDbc"), 0); + fn camel_case_until_not() { + assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0)); + assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0)); } #[test] - fn until_partial() { - assert_eq!(until("AbcDef_"), 6); - assert_eq!(until("CallTypeC"), 8); - assert_eq!(until("AbcDD"), 3); + fn camel_case_until_partial() { + assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6)); + assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8)); + assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3)); + assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7)); } #[test] fn until_caps() { - assert_eq!(until("ABCD"), 0); + assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0)); } } From 1b2c57c2dd11df9c3c3cae51870be67ccfef65bc Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Sun, 24 Oct 2021 15:14:45 -0500 Subject: [PATCH 17/65] docs: recommend new branch --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4273fda4e640d..97ff31b4bc5a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -262,7 +262,9 @@ to be run inside the `rust` directory): 2. Checkout the commit from the latest available nightly. You can get it using `rustup check`. 3. Sync the changes to the rust-copy of Clippy to your Clippy fork: ```bash - # Make sure to change `your-github-name` to your github name in the following command + # Make sure to change `your-github-name` to your github name in the following command. Also be + # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand + # because changes cannot be fast forwarded git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust ``` From f674e6f49c83ba90b50e3fa528f0e4d12b433bed Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 1 Oct 2021 18:09:31 +0000 Subject: [PATCH 18/65] Always sort suggestions before emitting them --- tests/ui/nonminimal_bool.stderr | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/ui/nonminimal_bool.stderr b/tests/ui/nonminimal_bool.stderr index 1d39bce935db8..bb93cbbd5e190 100644 --- a/tests/ui/nonminimal_bool.stderr +++ b/tests/ui/nonminimal_bool.stderr @@ -50,10 +50,10 @@ LL | let _ = a == b && c == 5 && a == b; | help: try | -LL | let _ = a == b && c == 5; - | ~~~~~~~~~~~~~~~~ LL | let _ = !(a != b || c != 5); | ~~~~~~~~~~~~~~~~~~~ +LL | let _ = a == b && c == 5; + | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified --> $DIR/nonminimal_bool.rs:28:13 @@ -63,10 +63,10 @@ LL | let _ = a == b || c == 5 || a == b; | help: try | -LL | let _ = a == b || c == 5; - | ~~~~~~~~~~~~~~~~ LL | let _ = !(a != b && c != 5); | ~~~~~~~~~~~~~~~~~~~ +LL | let _ = a == b || c == 5; + | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified --> $DIR/nonminimal_bool.rs:29:13 @@ -76,10 +76,10 @@ LL | let _ = a == b && c == 5 && b == a; | help: try | -LL | let _ = a == b && c == 5; - | ~~~~~~~~~~~~~~~~ LL | let _ = !(a != b || c != 5); | ~~~~~~~~~~~~~~~~~~~ +LL | let _ = a == b && c == 5; + | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified --> $DIR/nonminimal_bool.rs:30:13 @@ -89,10 +89,10 @@ LL | let _ = a != b || !(a != b || c == d); | help: try | -LL | let _ = a != b || c != d; - | ~~~~~~~~~~~~~~~~ LL | let _ = !(a == b && c == d); | ~~~~~~~~~~~~~~~~~~~ +LL | let _ = a != b || c != d; + | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified --> $DIR/nonminimal_bool.rs:31:13 @@ -102,10 +102,10 @@ LL | let _ = a != b && !(a != b && c == d); | help: try | -LL | let _ = a != b && c != d; - | ~~~~~~~~~~~~~~~~ LL | let _ = !(a == b || c == d); | ~~~~~~~~~~~~~~~~~~~ +LL | let _ = a != b && c != d; + | ~~~~~~~~~~~~~~~~ error: aborting due to 12 previous errors From 7517ae2fb3bc29e91f0f7c2daaac8cd8c8887bb2 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 24 Oct 2021 22:47:39 +0200 Subject: [PATCH 19/65] Refactored some string handling to prevent ICEs and FNs --- clippy_lints/src/enum_variants.rs | 44 ++++++-------------- clippy_utils/src/str_utils.rs | 69 +++++++++++++++++++++++++++++++ tests/ui/crashes/ice-7869.rs | 7 ++++ tests/ui/crashes/ice-7869.stderr | 15 +++++++ tests/ui/enum_variants.stderr | 2 +- tests/ui/match_ref_pats.rs | 2 +- 6 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 tests/ui/crashes/ice-7869.rs create mode 100644 tests/ui/crashes/ice-7869.stderr diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index 19f1781d0b046..404b67c8f29f2 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; -use clippy_utils::str_utils; +use clippy_utils::str_utils::{self, count_match_end, count_match_start}; use rustc_hir::{EnumDef, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [ MODULE_INCEPTION ]); -/// Returns the number of chars that match from the start -#[must_use] -fn partial_match(pre: &str, name: &str) -> usize { - let mut name_iter = name.chars(); - let _ = name_iter.next_back(); // make sure the name is never fully matched - pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count() -} - -/// Returns the number of chars that match from the end -#[must_use] -fn partial_rmatch(post: &str, name: &str) -> usize { - let mut name_iter = name.chars(); - let _ = name_iter.next(); // make sure the name is never fully matched - post.chars() - .rev() - .zip(name_iter.rev()) - .take_while(|&(l, r)| l == r) - .count() -} - fn check_variant( cx: &LateContext<'_>, threshold: u64, @@ -150,7 +130,7 @@ fn check_variant( } for var in def.variants { let name = var.ident.name.as_str(); - if partial_match(item_name, &name) == item_name_chars + if count_match_start(item_name, &name).char_count == item_name_chars && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) { @@ -161,7 +141,7 @@ fn check_variant( "variant name starts with the enum's name", ); } - if partial_rmatch(item_name, &name) == item_name_chars { + if count_match_end(item_name, &name).char_count == item_name_chars { span_lint( cx, ENUM_VARIANT_NAMES, @@ -176,7 +156,7 @@ fn check_variant( for var in def.variants { let name = var.ident.name.as_str(); - let pre_match = partial_match(pre, &name); + let pre_match = count_match_start(pre, &name).byte_count; pre = &pre[..pre_match]; let pre_camel = str_utils::camel_case_until(pre).byte_index; pre = &pre[..pre_camel]; @@ -193,8 +173,8 @@ fn check_variant( } } - let post_match = partial_rmatch(post, &name); - let post_end = post.len() - post_match; + let post_match = count_match_end(post, &name); + let post_end = post.len() - post_match.byte_count; post = &post[post_end..]; let post_camel = str_utils::camel_case_start(post); post = &post[post_camel.byte_index..]; @@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames { ); } } - if item.vis.node.is_pub() { - let matching = partial_match(mod_camel, &item_camel); - let rmatching = partial_rmatch(mod_camel, &item_camel); + // The `module_name_repetitions` lint should only trigger if the item has the module in its + // name. Having the same name is accepted. + if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() { + let matching = count_match_start(mod_camel, &item_camel); + let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric(); - if matching == nchars { + if matching.char_count == nchars { match item_camel.chars().nth(nchars) { Some(c) if is_word_beginning(c) => span_lint( cx, @@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames { _ => (), } } - if rmatching == nchars { + if rmatching.char_count == nchars { span_lint( cx, MODULE_NAME_REPETITIONS, diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs index f3de1250d5d80..cba96e05a2412 100644 --- a/clippy_utils/src/str_utils.rs +++ b/clippy_utils/src/str_utils.rs @@ -99,6 +99,75 @@ pub fn camel_case_start(s: &str) -> StrIndex { last_index } +/// Dealing with sting comparison can be complicated, this struct ensures that both the +/// character and byte count are provided for correct indexing. +#[derive(Debug, Default, PartialEq, Eq)] +pub struct StrCount { + pub char_count: usize, + pub byte_count: usize, +} + +impl StrCount { + pub fn new(char_count: usize, byte_count: usize) -> Self { + Self { char_count, byte_count } + } +} + +/// Returns the number of chars that match from the start +/// +/// ``` +/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6)); +/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0)); +/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11)); +/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5)); +/// ``` +#[must_use] +pub fn count_match_start(str1: &str, str2: &str) -> StrCount { + // (char_index, char1) + let char_count = str1.chars().count(); + let iter1 = (0..=char_count).zip(str1.chars()); + // (byte_index, char2) + let iter2 = str2.char_indices(); + + iter1 + .zip(iter2) + .take_while(|((_, c1), (_, c2))| c1 == c2) + .last() + .map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| { + StrCount::new(char_index + 1, byte_index + character.len_utf8()) + }) +} + +/// Returns the number of chars and bytes that match from the end +/// +/// ``` +/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4)); +/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0)); +/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6)); +/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5)); +/// ``` +#[must_use] +pub fn count_match_end(str1: &str, str2: &str) -> StrCount { + let char_count = str1.chars().count(); + if char_count == 0 { + return StrCount::default(); + } + + // (char_index, char1) + let iter1 = (0..char_count).rev().zip(str1.chars().rev()); + // (byte_index, char2) + let byte_count = str2.len(); + let iter2 = str2.char_indices().rev(); + + iter1 + .zip(iter2) + .take_while(|((_, c1), (_, c2))| c1 == c2) + .last() + .map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| { + StrCount::new(char_count - char_index, byte_count - byte_index) + }) +} + #[cfg(test)] mod test { use super::*; diff --git a/tests/ui/crashes/ice-7869.rs b/tests/ui/crashes/ice-7869.rs new file mode 100644 index 0000000000000..8f97a063a9a9f --- /dev/null +++ b/tests/ui/crashes/ice-7869.rs @@ -0,0 +1,7 @@ +enum Tila { + TyöAlkoi, + TyöKeskeytyi, + TyöValmis, +} + +fn main() {} diff --git a/tests/ui/crashes/ice-7869.stderr b/tests/ui/crashes/ice-7869.stderr new file mode 100644 index 0000000000000..4fa9fb27e7659 --- /dev/null +++ b/tests/ui/crashes/ice-7869.stderr @@ -0,0 +1,15 @@ +error: all variants have the same prefix: `Työ` + --> $DIR/ice-7869.rs:1:1 + | +LL | / enum Tila { +LL | | TyöAlkoi, +LL | | TyöKeskeytyi, +LL | | TyöValmis, +LL | | } + | |_^ + | + = note: `-D clippy::enum-variant-names` implied by `-D warnings` + = help: remove the prefixes and use full paths to the variants instead of glob imports + +error: aborting due to previous error + diff --git a/tests/ui/enum_variants.stderr b/tests/ui/enum_variants.stderr index 447fbb9e1bff3..add8a91e26b85 100644 --- a/tests/ui/enum_variants.stderr +++ b/tests/ui/enum_variants.stderr @@ -60,7 +60,7 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: all variants have the same prefix: `With` +error: all variants have the same prefix: `WithOut` --> $DIR/enum_variants.rs:81:1 | LL | / enum Seallll { diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs index 50246486bb6fc..7e3674ab8c9f2 100644 --- a/tests/ui/match_ref_pats.rs +++ b/tests/ui/match_ref_pats.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_ref_pats)] -#![allow(clippy::equatable_if_let)] +#![allow(clippy::equatable_if_let, clippy::enum_variant_names)] fn ref_pats() { { From 949fc44ccc96741b4b0b3430b21d4fc68553277a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 21 Oct 2021 17:37:57 +0200 Subject: [PATCH 20/65] Update CHANGELOG --- CHANGELOG.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 154 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b4c687209e11..ec204cc064e0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,162 @@ document. ## Unreleased / In Rust Nightly -[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master) +[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master) + +## Rust 1.57 + +Current beta, release 2021-12-02 + +[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f) + +### New Lints + +* [`negative_feature_names`] + [#7539](https://github.com/rust-lang/rust-clippy/pull/7539) +* [`redundant_feature_names`] + [#7539](https://github.com/rust-lang/rust-clippy/pull/7539) +* [`mod_module_files`] + [#7543](https://github.com/rust-lang/rust-clippy/pull/7543) +* [`self_named_module_files`] + [#7543](https://github.com/rust-lang/rust-clippy/pull/7543) +* [`manual_split_once`] + [#7565](https://github.com/rust-lang/rust-clippy/pull/7565) +* [`derivable_impls`] + [#7570](https://github.com/rust-lang/rust-clippy/pull/7570) +* [`needless_option_as_deref`] + [#7596](https://github.com/rust-lang/rust-clippy/pull/7596) +* [`iter_not_returning_iterator`] + [#7610](https://github.com/rust-lang/rust-clippy/pull/7610) +* [`same_name_method`] + [#7653](https://github.com/rust-lang/rust-clippy/pull/7653) +* [`if_then_panic`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669) +* [`non_send_fields_in_send_ty`] + [#7709](https://github.com/rust-lang/rust-clippy/pull/7709) +* [`equatable_if_let`] + [#7762](https://github.com/rust-lang/rust-clippy/pull/7762) + +### Moves and Deprecations + +* Move [`shadow_unrelated`] to `restriction` + [#7338](https://github.com/rust-lang/rust-clippy/pull/7338) +* Move [`option_if_let_else`] to `nursery` + [#7568](https://github.com/rust-lang/rust-clippy/pull/7568) +* Move [`branches_sharing_code`] to `nursery` + [#7595](https://github.com/rust-lang/rust-clippy/pull/7595) +* Rename `if_let_some_result` to [`match_result_ok`] which now also handles + `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608) +* Move [`many_single_char_names`] to `pedantic` + [#7671](https://github.com/rust-lang/rust-clippy/pull/7671) +* Move [`float_cmp`] to `pedantic` + [#7692](https://github.com/rust-lang/rust-clippy/pull/7692) +* Rename `box_vec` to [`box_collection`] and lint on more general cases + [#7693](https://github.com/rust-lang/rust-clippy/pull/7693) +* Uplift `invalid_atomic_ordering` to rustc + [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039) + +### Enhancements + +* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not + limited to certain patterns + [#7338](https://github.com/rust-lang/rust-clippy/pull/7338) +* The `avoid-breaking-exported-api` configuration now also works for + [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`], + [`option_option`], [`linkedlist`], [`rc_mutex`] + [#7560](https://github.com/rust-lang/rust-clippy/pull/7560) +* [`unnecessary_unwrap`]: Now also checks for `expect`s + [#7584](https://github.com/rust-lang/rust-clippy/pull/7584) +* [`disallowed_method`]: Allow adding a reason that will be displayed with the + lint message + [#7621](https://github.com/rust-lang/rust-clippy/pull/7621) +* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10` + [#7629](https://github.com/rust-lang/rust-clippy/pull/7629) +* [`approx_constant`]: Add `TAU` + [#7642](https://github.com/rust-lang/rust-clippy/pull/7642) +* [`needless_borrow`]: Now also lints on needless mutable borrows + [#7657](https://github.com/rust-lang/rust-clippy/pull/7657) +* [`missing_safety_doc`]: Now also lints on unsafe traits + [#7734](https://github.com/rust-lang/rust-clippy/pull/7734) + +### False Positive Fixes + +* [`manual_map`]: No longer lints when the option is borrowed in the match and + also consumed in the arm + [#7531](https://github.com/rust-lang/rust-clippy/pull/7531) +* [`filter_next`]: No longer lints if `filter` method is not the + `Iterator::filter` method + [#7562](https://github.com/rust-lang/rust-clippy/pull/7562) +* [`manual_flatten`]: No longer lints if expression is used after `if let` + [#7566](https://github.com/rust-lang/rust-clippy/pull/7566) +* [`option_if_let_else`]: Multiple fixes + [#7573](https://github.com/rust-lang/rust-clippy/pull/7573) + * `break` and `continue` statements local to the would-be closure are + allowed + * Don't lint in const contexts + * Don't lint when yield expressions are used + * Don't lint when the captures made by the would-be closure conflict with + the other branch + * Don't lint when a field of a local is used when the type could be + potentially moved from + * In some cases, don't lint when scrutinee expression conflicts with the + captures of the would-be closure +* [`redundant_allocation`]: No longer lints on `Box>` which replaces + wide pointers with thin pointers + [#7592](https://github.com/rust-lang/rust-clippy/pull/7592) +* [`bool_assert_comparison`]: No longer lints on types that do not implement the + `Not` trait with `Output = bool` + [#7605](https://github.com/rust-lang/rust-clippy/pull/7605) +* [`mut_range_bound`]: No longer lints on range bound mutations, that are + immediately followed by a `break;` + [#7607](https://github.com/rust-lang/rust-clippy/pull/7607) +* [`mutable_key_type`]: Improve accuracy and document remaining false positives + and false negatives + [#7640](https://github.com/rust-lang/rust-clippy/pull/7640) +* [`redundant_closure`]: Rewrite the lint to fix various false positives and + false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661) +* [`large_enum_variant`]: No longer wrongly identifies the second largest + variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677) +* [`needless_return`]: No longer lints on let-else expressions + [#7685](https://github.com/rust-lang/rust-clippy/pull/7685) +* [`suspicious_else_formatting`]: No longer lints in proc-macros + [#7707](https://github.com/rust-lang/rust-clippy/pull/7707) +* [`excessive_precision`]: No longer lints when in some cases the float was + already written in the shortest form + [#7722](https://github.com/rust-lang/rust-clippy/pull/7722) +* [`doc_markdown`]: No longer lints on intra-doc links + [#7772](https://github.com/rust-lang/rust-clippy/pull/7772) + +### Suggestion Fixes/Improvements + +* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a + function call in an indexing operation + [#7453](https://github.com/rust-lang/rust-clippy/pull/7453) +* [`manual_split_once`]: Produce semantically equivalent suggestion when + `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663) +* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut` + [#7690](https://github.com/rust-lang/rust-clippy/pull/7690) +* [`if_then_panic`]: No better handles complex conditions + [#7741](https://github.com/rust-lang/rust-clippy/pull/7741) +* Correctly handle signs in exponents in numeric literals lints + [#7747](https://github.com/rust-lang/rust-clippy/pull/7747) +* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative + [#7770](https://github.com/rust-lang/rust-clippy/pull/7770) +* Drop exponent from suggestion if it is 0 in numeric literals lints + [#7774](https://github.com/rust-lang/rust-clippy/pull/7774) + +### ICE Fixes + +* [`implicit_hasher`] + [#7761](https://github.com/rust-lang/rust-clippy/pull/7761) + +### Others + +* Clippy now uses the 2021 + [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro) + [#7664](https://github.com/rust-lang/rust-clippy/pull/7664) ## Rust 1.56 -Current beta, release 2021-10-21 +Current stable, released 2021-10-21 [74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e) @@ -74,13 +225,9 @@ Current beta, release 2021-10-21 * [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507) -### New Lints - -* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case. - ## Rust 1.55 -Current stable, released 2021-09-09 +Released 2021-09-09 [3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561) From 1ad04f4054db6af3e64f95449a86753f2259fc5e Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 24 Oct 2021 23:01:44 +0200 Subject: [PATCH 21/65] Move `non_send_fields_in_send_ty` to `suspicious` Also updated one configuration for nicer formatting --- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_nursery.rs | 1 - clippy_lints/src/lib.register_suspicious.rs | 1 + clippy_lints/src/non_send_fields_in_send_ty.rs | 2 +- clippy_lints/src/utils/conf.rs | 4 ++-- doc/adding_lints.md | 3 ++- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index c949ee23ecc7a..e08bfeec7ca39 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -218,6 +218,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 1e54482a8dafd..44c75a11eec08 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -17,7 +17,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ 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), diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 8859787fbc830..a3f964d158042 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -15,6 +15,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::MUT_RANGE_BOUND), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), + LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), ]) diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index 374b7bd59649e..7ebf84d400f56 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -44,7 +44,7 @@ declare_clippy_lint! { /// 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, + suspicious, "there is field that does not implement `Send` in a `Send` struct" } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index d05c52122d5ee..122a5ce3fc8f1 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -288,10 +288,10 @@ define_Conf! { /// /// The list of imports to always rename, a fully qualified path followed by the rename. (enforced_import_renames: Vec = Vec::new()), - /// Lint: RESTRICTED_SCRIPTS. + /// Lint: DISALLOWED_SCRIPT_IDENTS. /// /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec = vec!["Latin".to_string()]), + (allowed_scripts: Vec = ["Latin"].iter().map(ToString::to_string).collect()), /// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 004eb28b44640..e0a9b27777aa4 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -564,7 +564,8 @@ in the following steps: /// (configuration_ident: Type = DefaultValue), ``` - The doc comment will be automatically added to the lint documentation. + The doc comment is automatically added to the documentation of the listed lints. The default + value will be formatted using the `Debug` implementation of the type. 2. Adding the configuration value to the lint impl struct: 1. This first requires the definition of a lint impl struct. Lint impl structs are usually generated with the `declare_lint_pass!` macro. This struct needs to be defined manually From 999b3004c499e96e62d677d79fab47c5c514636a Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 25 Oct 2021 09:46:47 +0200 Subject: [PATCH 22/65] new lint: string-slice --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/strings.rs | 106 +++++++++++++------ tests/ui/string_slice.rs | 10 ++ tests/ui/string_slice.stderr | 22 ++++ 6 files changed, 106 insertions(+), 35 deletions(-) create mode 100644 tests/ui/string_slice.rs create mode 100644 tests/ui/string_slice.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b4c687209e11..fe4c3bf6261ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3000,6 +3000,7 @@ Released 2018-09-13 [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars [`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes +[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index e8dd3708c8ed4..ff0a0f973976a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -431,6 +431,7 @@ store.register_lints(&[ strings::STRING_ADD_ASSIGN, strings::STRING_FROM_UTF8_AS_BYTES, strings::STRING_LIT_AS_BYTES, + strings::STRING_SLICE, strings::STRING_TO_STRING, strings::STR_TO_STRING, strlen_on_c_strings::STRLEN_ON_C_STRINGS, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 3d68a6e900958..4929bbecde090 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -53,6 +53,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(shadow::SHADOW_SAME), LintId::of(shadow::SHADOW_UNRELATED), LintId::of(strings::STRING_ADD), + LintId::of(strings::STRING_SLICE), LintId::of(strings::STRING_TO_STRING), LintId::of(strings::STR_TO_STRING), LintId::of(types::RC_BUFFER), diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 35b6bde56964c..6435107b8b464 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -107,51 +107,87 @@ declare_clippy_lint! { "calling `as_bytes` on a string literal instead of using a byte string literal" } -declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]); +declare_clippy_lint! { + /// ### What it does + /// Checks for slice operations on strings + /// + /// ### Why is this bad? + /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character + /// counts and string indices. This may lead to panics, and should warrant some test cases + /// containing wide UTF-8 characters. This lint is most useful in code that should avoid + /// panics at all costs. + /// + /// ### Known problems + /// Probably lots of false positives. If an index comes from a known valid position (e.g. + /// obtained via `char_indices` over the same string), it is totally OK. + /// + /// # Example + /// ```rust,should_panic + /// &"Ölkanne"[1..]; + /// ``` + pub STRING_SLICE, + restriction, + "slicing a string" +} + +declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]); impl<'tcx> LateLintPass<'tcx> for StringAdd { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), e.span) { return; } - - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Add, .. - }, - left, - _, - ) = e.kind - { - if is_string(cx, left) { - if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { - let parent = get_parent_expr(cx, e); - if let Some(p) = parent { - if let ExprKind::Assign(target, _, _) = p.kind { - // avoid duplicate matches - if SpanlessEq::new(cx).eq_expr(target, left) { - return; + match e.kind { + ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + left, + _, + ) => { + if is_string(cx, left) { + if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { + let parent = get_parent_expr(cx, e); + if let Some(p) = parent { + if let ExprKind::Assign(target, _, _) = p.kind { + // avoid duplicate matches + if SpanlessEq::new(cx).eq_expr(target, left) { + return; + } } } } + span_lint( + cx, + STRING_ADD, + e.span, + "you added something to a string. Consider using `String::push_str()` instead", + ); } - span_lint( - cx, - STRING_ADD, - e.span, - "you added something to a string. Consider using `String::push_str()` instead", - ); - } - } else if let ExprKind::Assign(target, src, _) = e.kind { - if is_string(cx, target) && is_add(cx, src, target) { - span_lint( - cx, - STRING_ADD_ASSIGN, - e.span, - "you assigned the result of adding something to this string. Consider using \ - `String::push_str()` instead", - ); - } + }, + ExprKind::Assign(target, src, _) => { + if is_string(cx, target) && is_add(cx, src, target) { + span_lint( + cx, + STRING_ADD_ASSIGN, + e.span, + "you assigned the result of adding something to this string. Consider using \ + `String::push_str()` instead", + ); + } + }, + ExprKind::Index(target, _idx) => { + let e_ty = cx.typeck_results().expr_ty(target).peel_refs(); + if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) { + span_lint( + cx, + STRING_SLICE, + e.span, + "indexing into a string may panic if the index is within a UTF-8 character", + ); + } + }, + _ => {}, } } } diff --git a/tests/ui/string_slice.rs b/tests/ui/string_slice.rs new file mode 100644 index 0000000000000..be4dfc8816c7f --- /dev/null +++ b/tests/ui/string_slice.rs @@ -0,0 +1,10 @@ +#[warn(clippy::string_slice)] +#[allow(clippy::no_effect)] + +fn main() { + &"Ölkanne"[1..]; + let m = "Mötörhead"; + &m[2..5]; + let s = String::from(m); + &s[0..2]; +} diff --git a/tests/ui/string_slice.stderr b/tests/ui/string_slice.stderr new file mode 100644 index 0000000000000..55040bf5df2de --- /dev/null +++ b/tests/ui/string_slice.stderr @@ -0,0 +1,22 @@ +error: indexing into a string may panic if the index is within a UTF-8 character + --> $DIR/string_slice.rs:5:6 + | +LL | &"Ölkanne"[1..]; + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::string-slice` implied by `-D warnings` + +error: indexing into a string may panic if the index is within a UTF-8 character + --> $DIR/string_slice.rs:7:6 + | +LL | &m[2..5]; + | ^^^^^^^ + +error: indexing into a string may panic if the index is within a UTF-8 character + --> $DIR/string_slice.rs:9:6 + | +LL | &s[0..2]; + | ^^^^^^^ + +error: aborting due to 3 previous errors + From d0c04b4d78504e5ebab17faa1692d8220b5aff92 Mon Sep 17 00:00:00 2001 From: Devon Hollowood Date: Tue, 26 Oct 2021 00:53:53 -0700 Subject: [PATCH 23/65] Clean up tests/ui/rename.rs --- clippy_lints/src/lib.rs | 1 + tests/ui/rename.fixed | 48 +++++++++++ tests/ui/rename.rs | 48 +++++++++++ tests/ui/rename.stderr | 178 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 268 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ed7e827702395..533159eca7063 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -828,6 +828,7 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) { /// /// Used in `./src/driver.rs`. pub fn register_renamed(ls: &mut rustc_lint::LintStore) { + // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions"); ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default"); ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"); diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index a66c2e587c873..dba18d4e784d8 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -6,9 +6,57 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::new_without_default)] #![allow(clippy::redundant_static_lifetimes)] +#![allow(clippy::bind_instead_of_map)] +#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::box_collection)] +#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::map_unwrap_or)] +#![allow(clippy::unwrap_used)] +#![allow(clippy::expect_used)] +#![allow(clippy::for_loops_over_fallibles)] +#![allow(clippy::useless_conversion)] +#![allow(clippy::invisible_characters)] +#![allow(clippy::single_char_add_str)] +#![allow(clippy::match_result_ok)] +// uplifted lints +#![allow(invalid_value)] +#![allow(array_into_iter)] +#![allow(unused_labels)] +#![allow(drop_bounds)] +#![allow(temporary_cstring_as_ptr)] +#![allow(non_fmt_panics)] +#![allow(unknown_lints)] +#![allow(invalid_atomic_ordering)] +#![allow(enum_intrinsics_non_enums)] // warn for the old lint name here, to test if the renaming worked #![warn(clippy::cognitive_complexity)] #![warn(enum_intrinsics_non_enums)] +#![warn(clippy::bind_instead_of_map)] +#![warn(clippy::box_collection)] +#![warn(clippy::map_unwrap_or)] +#![warn(clippy::map_unwrap_or)] +#![warn(clippy::map_unwrap_or)] +#![warn(clippy::unwrap_used)] +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] +#![warn(clippy::expect_used)] +#![warn(clippy::for_loops_over_fallibles)] +#![warn(clippy::for_loops_over_fallibles)] +#![warn(clippy::useless_conversion)] +#![warn(clippy::invisible_characters)] +#![warn(clippy::single_char_add_str)] +#![warn(clippy::match_result_ok)] +// uplifted lints +#![warn(invalid_value)] +#![warn(array_into_iter)] +#![warn(unused_labels)] +#![warn(drop_bounds)] +#![warn(temporary_cstring_as_ptr)] +#![warn(non_fmt_panics)] +#![warn(unknown_lints)] +#![warn(invalid_atomic_ordering)] +#![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 fa81201a2daf3..a4f0997133c02 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -6,9 +6,57 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::new_without_default)] #![allow(clippy::redundant_static_lifetimes)] +#![allow(clippy::bind_instead_of_map)] +#![allow(clippy::block_in_if_condition_expr)] +#![allow(clippy::block_in_if_condition_stmt)] +#![allow(clippy::box_collection)] +#![allow(clippy::blocks_in_if_conditions)] +#![allow(clippy::map_unwrap_or)] +#![allow(clippy::unwrap_used)] +#![allow(clippy::expect_used)] +#![allow(clippy::for_loop_over_fallibles)] +#![allow(clippy::useless_conversion)] +#![allow(clippy::invisible_characters)] +#![allow(clippy::single_char_add_str)] +#![allow(clippy::match_result_ok)] +// uplifted lints +#![allow(invalid_value)] +#![allow(array_into_iter)] +#![allow(unused_labels)] +#![allow(drop_bounds)] +#![allow(temporary_cstring_as_ptr)] +#![allow(non_fmt_panics)] +#![allow(unknown_lints)] +#![allow(invalid_atomic_ordering)] +#![allow(enum_intrinsics_non_enums)] // 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::option_and_then_some)] +#![warn(clippy::box_vec)] +#![warn(clippy::option_map_unwrap_or)] +#![warn(clippy::option_map_unwrap_or_else)] +#![warn(clippy::result_map_unwrap_or_else)] +#![warn(clippy::option_unwrap_used)] +#![warn(clippy::result_unwrap_used)] +#![warn(clippy::option_expect_used)] +#![warn(clippy::result_expect_used)] +#![warn(clippy::for_loop_over_option)] +#![warn(clippy::for_loop_over_result)] +#![warn(clippy::identity_conversion)] +#![warn(clippy::zero_width_space)] +#![warn(clippy::single_char_push_str)] +#![warn(clippy::if_let_some_result)] +// uplifted lints +#![warn(clippy::invalid_ref)] +#![warn(clippy::into_iter_on_array)] +#![warn(clippy::unused_label)] +#![warn(clippy::drop_bounds)] +#![warn(clippy::temporary_cstring_as_ptr)] +#![warn(clippy::panic_params)] +#![warn(clippy::unknown_clippy_lints)] +#![warn(clippy::invalid_atomic_ordering)] +#![warn(clippy::mem_discriminant_non_enum)] #[warn(clippy::stutter)] fn main() {} diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 05c7854074c60..af4ef2762c92e 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,34 +1,198 @@ +error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` + --> $DIR/rename.rs:10:10 + | +LL | #![allow(clippy::block_in_if_condition_expr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` + +error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` + --> $DIR/rename.rs:11:10 + | +LL | #![allow(clippy::block_in_if_condition_stmt)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` + +error: unknown lint: `clippy::for_loop_over_fallibles` + --> $DIR/rename.rs:17:10 + | +LL | #![allow(clippy::for_loop_over_fallibles)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::for_loops_over_fallibles` + | + = note: `-D unknown-lints` implied by `-D warnings` + error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:10:9 + --> $DIR/rename.rs:33:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` + +error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` + --> $DIR/rename.rs:34:9 | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` +LL | #![warn(clippy::mem_discriminant_non_enum)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` + +error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` + --> $DIR/rename.rs:35:9 + | +LL | #![warn(clippy::option_and_then_some)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` + +error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` + --> $DIR/rename.rs:36:9 + | +LL | #![warn(clippy::box_vec)] + | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` + +error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` + --> $DIR/rename.rs:37:9 + | +LL | #![warn(clippy::option_map_unwrap_or)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` + +error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` + --> $DIR/rename.rs:38:9 + | +LL | #![warn(clippy::option_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` + +error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` + --> $DIR/rename.rs:39:9 + | +LL | #![warn(clippy::result_map_unwrap_or_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` + +error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` + --> $DIR/rename.rs:40:9 + | +LL | #![warn(clippy::option_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` + +error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` + --> $DIR/rename.rs:41:9 + | +LL | #![warn(clippy::result_unwrap_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` + +error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` + --> $DIR/rename.rs:42:9 + | +LL | #![warn(clippy::option_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` + +error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` + --> $DIR/rename.rs:43:9 + | +LL | #![warn(clippy::result_expect_used)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` + +error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` + --> $DIR/rename.rs:44:9 + | +LL | #![warn(clippy::for_loop_over_option)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` + +error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` + --> $DIR/rename.rs:45:9 + | +LL | #![warn(clippy::for_loop_over_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` + +error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` + --> $DIR/rename.rs:46:9 + | +LL | #![warn(clippy::identity_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` + +error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` + --> $DIR/rename.rs:47:9 + | +LL | #![warn(clippy::zero_width_space)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` + +error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` + --> $DIR/rename.rs:48:9 + | +LL | #![warn(clippy::single_char_push_str)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` + +error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` + --> $DIR/rename.rs:49:9 + | +LL | #![warn(clippy::if_let_some_result)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` + +error: lint `clippy::invalid_ref` has been renamed to `invalid_value` + --> $DIR/rename.rs:51:9 + | +LL | #![warn(clippy::invalid_ref)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` + +error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` + --> $DIR/rename.rs:52:9 + | +LL | #![warn(clippy::into_iter_on_array)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` + +error: lint `clippy::unused_label` has been renamed to `unused_labels` + --> $DIR/rename.rs:53:9 + | +LL | #![warn(clippy::unused_label)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` + +error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` + --> $DIR/rename.rs:54:9 + | +LL | #![warn(clippy::drop_bounds)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` + +error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` + --> $DIR/rename.rs:55:9 + | +LL | #![warn(clippy::temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` + +error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` + --> $DIR/rename.rs:56:9 + | +LL | #![warn(clippy::panic_params)] + | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` + +error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` + --> $DIR/rename.rs:57:9 + | +LL | #![warn(clippy::unknown_clippy_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` + +error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` + --> $DIR/rename.rs:58:9 + | +LL | #![warn(clippy::invalid_atomic_ordering)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:11:9 + --> $DIR/rename.rs:59: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:13:8 + --> $DIR/rename.rs:61: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:16:8 + --> $DIR/rename.rs:64: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:19:8 + --> $DIR/rename.rs:67:8 | LL | #[warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` -error: aborting due to 5 previous errors +error: aborting due to 32 previous errors From d4196d029314c494d84aed97043b2eb84ecdea5b Mon Sep 17 00:00:00 2001 From: dswij Date: Fri, 22 Oct 2021 13:36:13 +0800 Subject: [PATCH 24/65] Add #7859 FP test case for `question_mark` --- tests/ui/question_mark.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index ca3722371f524..fc68a42e46f21 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -2,6 +2,9 @@ #![allow(unreachable_code)] #![allow(clippy::unnecessary_wraps)] +use std::env; +use std::path::PathBuf; + fn some_func(a: Option) -> Option { if a.is_none() { return None; @@ -134,7 +137,11 @@ fn func() -> Option { Some(0) } -fn result_func(x: Result) -> Result { +fn func_returning_result() -> Result { + Ok(1) +} + +fn result_func(x: Result) -> Result { let _ = if let Ok(x) = x { x } else { return x }; if x.is_err() { @@ -145,9 +152,21 @@ fn result_func(x: Result) -> Result { let y = if let Ok(x) = x { x } else { - return Err("some error"); + return Err("some error".to_string()); }; + // issue #7859 + // no warning + let _ = if let Ok(x) = func_returning_result() { + x + } else { + return Err("some error".to_string()); + }; + + if func_returning_result().is_err() { + return func_returning_result(); + } + Ok(y) } From a1a399d16830ac84c1ce18c2a0e8a77a13edf265 Mon Sep 17 00:00:00 2001 From: dswij Date: Fri, 22 Oct 2021 13:41:46 +0800 Subject: [PATCH 25/65] Fix `question_mark` FP on calls --- clippy_lints/src/question_mark.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 4d616e26bfc1d..01fa523300aa3 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -172,23 +172,17 @@ impl QuestionMark { } } - fn expression_returns_unmodified_err( - cx: &LateContext<'_>, - expression: &Expr<'_>, - origin_hir_id: &Expr<'_>, - ) -> bool { + fn expression_returns_unmodified_err(cx: &LateContext<'_>, expression: &Expr<'_>, cond_expr: &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); + return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr); } 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), + ExprKind::Ret(Some(expr)) => Self::expression_returns_unmodified_err(cx, expr, cond_expr), + ExprKind::Path(_) => path_to_local(expression) == path_to_local(cond_expr), _ => false, } } From a91ec594601cc1b3e11cf110a403c54ae826044b Mon Sep 17 00:00:00 2001 From: dswij Date: Fri, 22 Oct 2021 13:43:21 +0800 Subject: [PATCH 26/65] Update `question_mark` expected test output --- tests/ui/question_mark.fixed | 25 ++++++++++++++++++++++--- tests/ui/question_mark.stderr | 28 ++++++++++++++-------------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index ccb2e5a302e91..060ea8c8c548b 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -2,6 +2,9 @@ #![allow(unreachable_code)] #![allow(clippy::unnecessary_wraps)] +use std::env; +use std::path::PathBuf; + fn some_func(a: Option) -> Option { a?; @@ -104,18 +107,34 @@ fn func() -> Option { Some(0) } -fn result_func(x: Result) -> Result { +fn func_returning_result() -> Result { + Ok(1) +} + +fn result_func(x: Result) -> Result { let _ = x?; - x?; + x.as_ref()?; // No warning let y = if let Ok(x) = x { x } else { - return Err("some error"); + return Err("some error".to_string()); }; + // issue #7859 + // no warning + let _ = if let Ok(x) = func_returning_result() { + x + } else { + return Err("some error".to_string()); + }; + + if func_returning_result().is_err() { + return func_returning_result(); + } + Ok(y) } diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 161588cb73cba..8eee7f8cb18d0 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:6:5 + --> $DIR/question_mark.rs:9:5 | LL | / if a.is_none() { LL | | return None; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:51:9 + --> $DIR/question_mark.rs:54:9 | LL | / if (self.opt).is_none() { LL | | return None; @@ -17,7 +17,7 @@ LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:55:9 + --> $DIR/question_mark.rs:58:9 | LL | / if self.opt.is_none() { LL | | return None @@ -25,7 +25,7 @@ LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:59:17 + --> $DIR/question_mark.rs:62:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -36,7 +36,7 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:65:17 + --> $DIR/question_mark.rs:68:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ @@ -47,7 +47,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:82:9 + --> $DIR/question_mark.rs:85:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -55,7 +55,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:90:9 + --> $DIR/question_mark.rs:93:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -63,7 +63,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:98:9 + --> $DIR/question_mark.rs:101:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -71,7 +71,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:105:26 + --> $DIR/question_mark.rs:108:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ @@ -82,7 +82,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:115:17 + --> $DIR/question_mark.rs:118:17 | LL | let v = if let Some(v) = self.opt { | _________________^ @@ -93,7 +93,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:130:5 + --> $DIR/question_mark.rs:133:5 | LL | / if f().is_none() { LL | | return None; @@ -101,18 +101,18 @@ LL | | } | |_____^ help: replace it with: `f()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:138:13 + --> $DIR/question_mark.rs:145: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 + --> $DIR/question_mark.rs:147:5 | LL | / if x.is_err() { LL | | return x; LL | | } - | |_____^ help: replace it with: `x?;` + | |_____^ help: replace it with: `x.as_ref()?;` error: aborting due to 13 previous errors From 2fd168285a77c0b39941c9b418a6c8418d75d45a Mon Sep 17 00:00:00 2001 From: dswij Date: Fri, 22 Oct 2021 14:11:04 +0800 Subject: [PATCH 27/65] Update `question_mark` test to behave better --- tests/ui/question_mark.fixed | 14 ++++++-------- tests/ui/question_mark.rs | 12 +++++------- tests/ui/question_mark.stderr | 28 ++++++++++++++-------------- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 060ea8c8c548b..e93469e5f556b 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -2,9 +2,6 @@ #![allow(unreachable_code)] #![allow(clippy::unnecessary_wraps)] -use std::env; -use std::path::PathBuf; - fn some_func(a: Option) -> Option { a?; @@ -107,20 +104,20 @@ fn func() -> Option { Some(0) } -fn func_returning_result() -> Result { +fn func_returning_result() -> Result { Ok(1) } -fn result_func(x: Result) -> Result { +fn result_func(x: Result) -> Result { let _ = x?; - x.as_ref()?; + x?; // No warning let y = if let Ok(x) = x { x } else { - return Err("some error".to_string()); + return Err(0); }; // issue #7859 @@ -128,9 +125,10 @@ fn result_func(x: Result) -> Result { let _ = if let Ok(x) = func_returning_result() { x } else { - return Err("some error".to_string()); + return Err(0); }; + // no warning if func_returning_result().is_err() { return func_returning_result(); } diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index fc68a42e46f21..dd179e9bee8f8 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -2,9 +2,6 @@ #![allow(unreachable_code)] #![allow(clippy::unnecessary_wraps)] -use std::env; -use std::path::PathBuf; - fn some_func(a: Option) -> Option { if a.is_none() { return None; @@ -137,11 +134,11 @@ fn func() -> Option { Some(0) } -fn func_returning_result() -> Result { +fn func_returning_result() -> Result { Ok(1) } -fn result_func(x: Result) -> Result { +fn result_func(x: Result) -> Result { let _ = if let Ok(x) = x { x } else { return x }; if x.is_err() { @@ -152,7 +149,7 @@ fn result_func(x: Result) -> Result { let y = if let Ok(x) = x { x } else { - return Err("some error".to_string()); + return Err(0); }; // issue #7859 @@ -160,9 +157,10 @@ fn result_func(x: Result) -> Result { let _ = if let Ok(x) = func_returning_result() { x } else { - return Err("some error".to_string()); + return Err(0); }; + // no warning if func_returning_result().is_err() { return func_returning_result(); } diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 8eee7f8cb18d0..8d782b71dd6a4 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:9:5 + --> $DIR/question_mark.rs:6:5 | LL | / if a.is_none() { LL | | return None; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:54:9 + --> $DIR/question_mark.rs:51:9 | LL | / if (self.opt).is_none() { LL | | return None; @@ -17,7 +17,7 @@ LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:58:9 + --> $DIR/question_mark.rs:55:9 | LL | / if self.opt.is_none() { LL | | return None @@ -25,7 +25,7 @@ LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:62:17 + --> $DIR/question_mark.rs:59:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -36,7 +36,7 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:68:17 + --> $DIR/question_mark.rs:65:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ @@ -47,7 +47,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:85:9 + --> $DIR/question_mark.rs:82:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -55,7 +55,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:93:9 + --> $DIR/question_mark.rs:90:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -63,7 +63,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:101:9 + --> $DIR/question_mark.rs:98:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -71,7 +71,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:108:26 + --> $DIR/question_mark.rs:105:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ @@ -82,7 +82,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:118:17 + --> $DIR/question_mark.rs:115:17 | LL | let v = if let Some(v) = self.opt { | _________________^ @@ -93,7 +93,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:133:5 + --> $DIR/question_mark.rs:130:5 | LL | / if f().is_none() { LL | | return None; @@ -101,18 +101,18 @@ LL | | } | |_____^ help: replace it with: `f()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:145:13 + --> $DIR/question_mark.rs:142: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:147:5 + --> $DIR/question_mark.rs:144:5 | LL | / if x.is_err() { LL | | return x; LL | | } - | |_____^ help: replace it with: `x.as_ref()?;` + | |_____^ help: replace it with: `x?;` error: aborting due to 13 previous errors From fb0fbad5caa97da949cb2c6dbc56a1185bb53af9 Mon Sep 17 00:00:00 2001 From: Dharma Saputra Wijaya Date: Tue, 26 Oct 2021 21:22:22 +0800 Subject: [PATCH 28/65] Rename variable name in `question_mark` --- clippy_lints/src/question_mark.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 01fa523300aa3..f63ef163bcbd0 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -172,8 +172,8 @@ impl QuestionMark { } } - fn expression_returns_unmodified_err(cx: &LateContext<'_>, expression: &Expr<'_>, cond_expr: &Expr<'_>) -> bool { - match expression.kind { + fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool { + match expr.kind { ExprKind::Block(block, _) => { if let Some(return_expression) = Self::return_expression(block) { return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr); @@ -181,8 +181,8 @@ impl QuestionMark { false }, - ExprKind::Ret(Some(expr)) => Self::expression_returns_unmodified_err(cx, expr, cond_expr), - ExprKind::Path(_) => path_to_local(expression) == path_to_local(cond_expr), + ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr), + ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr), _ => false, } } From 6c89c00a98ec754a95673e95402d8901301df609 Mon Sep 17 00:00:00 2001 From: Devon Hollowood Date: Tue, 26 Oct 2021 10:26:35 -0700 Subject: [PATCH 29/65] Further clean up tests/ui/rename.rs Now it is just a collection of lints + an empty main function --- tests/ui/rename.fixed | 10 ++--- tests/ui/rename.rs | 10 ++--- tests/ui/rename.stderr | 88 +++++++++++++++++++++--------------------- 3 files changed, 50 insertions(+), 58 deletions(-) diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index dba18d4e784d8..5607001ac411f 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -30,6 +30,9 @@ #![allow(invalid_atomic_ordering)] #![allow(enum_intrinsics_non_enums)] // warn for the old lint name here, to test if the renaming worked +#![warn(clippy::module_name_repetitions)] +#![warn(clippy::new_without_default)] +#![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] #![warn(enum_intrinsics_non_enums)] #![warn(clippy::bind_instead_of_map)] @@ -58,11 +61,4 @@ #![warn(invalid_atomic_ordering)] #![warn(enum_intrinsics_non_enums)] -#[warn(clippy::module_name_repetitions)] fn main() {} - -#[warn(clippy::new_without_default)] -struct Foo; - -#[warn(clippy::redundant_static_lifetimes)] -fn foo() {} diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index a4f0997133c02..9375dc464d64c 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -30,6 +30,9 @@ #![allow(invalid_atomic_ordering)] #![allow(enum_intrinsics_non_enums)] // warn for the old lint name here, to test if the renaming worked +#![warn(clippy::stutter)] +#![warn(clippy::new_without_default_derive)] +#![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] #![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::option_and_then_some)] @@ -58,11 +61,4 @@ #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::mem_discriminant_non_enum)] -#[warn(clippy::stutter)] fn main() {} - -#[warn(clippy::new_without_default_derive)] -struct Foo; - -#[warn(clippy::const_static_lifetime)] -fn foo() {} diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index af4ef2762c92e..6a9c6d717eebb 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -20,179 +20,179 @@ LL | #![allow(clippy::for_loop_over_fallibles)] | = note: `-D unknown-lints` implied by `-D warnings` -error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` +error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` --> $DIR/rename.rs:33:9 | +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:34:9 + | +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:35:9 + | +LL | #![warn(clippy::const_static_lifetime)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` + +error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` + --> $DIR/rename.rs:36:9 + | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:34:9 + --> $DIR/rename.rs:37:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:35:9 + --> $DIR/rename.rs:38:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:36:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:37:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:62: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:61: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:64: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:67:8 - | -LL | #[warn(clippy::const_static_lifetime)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` - error: aborting due to 32 previous errors From e48ab448f9b3c23e583256f2028731639bb168cd Mon Sep 17 00:00:00 2001 From: Devon Hollowood Date: Tue, 26 Oct 2021 10:52:35 -0700 Subject: [PATCH 30/65] Clean up `tests/ui/deprecated.rs` This also removes the uplifted lints from this test suite -- these are now tested in `tests/ui/rename.rs` --- clippy_lints/src/deprecated_lints.rs | 3 + tests/ui/deprecated.rs | 33 ++++--- tests/ui/deprecated.stderr | 128 +++++++++++++-------------- 3 files changed, 80 insertions(+), 84 deletions(-) diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index c604516742ce5..9d8524ec91cc6 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -1,3 +1,6 @@ +// NOTE: if you add a deprecated lint in this file, please add a corresponding test in +// tests/ui/deprecated.rs + /// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This /// enables the simple extraction of the metadata without changing the current deprecation /// declaration. diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 1943d0092e624..39a2601fee9ac 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -1,19 +1,18 @@ -#[warn(clippy::unstable_as_slice)] -#[warn(clippy::unstable_as_mut_slice)] -#[warn(clippy::misaligned_transmute)] -#[warn(clippy::unused_collect)] -#[warn(clippy::invalid_ref)] -#[warn(clippy::into_iter_on_array)] -#[warn(clippy::unused_label)] -#[warn(clippy::regex_macro)] -#[warn(clippy::drop_bounds)] -#[warn(clippy::temporary_cstring_as_ptr)] -#[warn(clippy::panic_params)] -#[warn(clippy::unknown_clippy_lints)] -#[warn(clippy::find_map)] -#[warn(clippy::filter_map)] -#[warn(clippy::pub_enum_variant_names)] -#[warn(clippy::wrong_pub_self_convention)] -#[warn(clippy::invalid_atomic_ordering)] +#![warn(clippy::should_assert_eq)] +#![warn(clippy::extend_from_slice)] +#![warn(clippy::range_step_by_zero)] +#![warn(clippy::unstable_as_slice)] +#![warn(clippy::unstable_as_mut_slice)] +#![warn(clippy::misaligned_transmute)] +#![warn(clippy::assign_ops)] +#![warn(clippy::if_let_redundant_pattern_matching)] +#![warn(clippy::unsafe_vector_initialization)] +#![warn(clippy::unused_collect)] +#![warn(clippy::replace_consts)] +#![warn(clippy::regex_macro)] +#![warn(clippy::find_map)] +#![warn(clippy::filter_map)] +#![warn(clippy::pub_enum_variant_names)] +#![warn(clippy::wrong_pub_self_convention)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 51048e45c0677..6095f134d55e0 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -1,106 +1,100 @@ -error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 - --> $DIR/deprecated.rs:1:8 +error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011 + --> $DIR/deprecated.rs:1:9 | -LL | #[warn(clippy::unstable_as_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::should_assert_eq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D renamed-and-removed-lints` implied by `-D warnings` -error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7 - --> $DIR/deprecated.rs:2:8 +error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice + --> $DIR/deprecated.rs:2:9 | -LL | #[warn(clippy::unstable_as_mut_slice)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::extend_from_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr - --> $DIR/deprecated.rs:3:8 +error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays + --> $DIR/deprecated.rs:3:9 | -LL | #[warn(clippy::misaligned_transmute)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::range_step_by_zero)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint - --> $DIR/deprecated.rs:4:8 +error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7 + --> $DIR/deprecated.rs:4:9 | -LL | #[warn(clippy::unused_collect)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::unstable_as_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/deprecated.rs:5:8 +error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7 + --> $DIR/deprecated.rs:5:9 | -LL | #[warn(clippy::invalid_ref)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` +LL | #![warn(clippy::unstable_as_mut_slice)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/deprecated.rs:6:8 +error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr + --> $DIR/deprecated.rs:6:9 | -LL | #[warn(clippy::into_iter_on_array)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` +LL | #![warn(clippy::misaligned_transmute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/deprecated.rs:7:8 +error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless + --> $DIR/deprecated.rs:7:9 | -LL | #[warn(clippy::unused_label)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` +LL | #![warn(clippy::assign_ops)] + | ^^^^^^^^^^^^^^^^^^ -error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018 - --> $DIR/deprecated.rs:8:8 +error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching + --> $DIR/deprecated.rs:8:9 | -LL | #[warn(clippy::regex_macro)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::if_let_redundant_pattern_matching)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/deprecated.rs:9:8 +error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior + --> $DIR/deprecated.rs:9:9 | -LL | #[warn(clippy::drop_bounds)] - | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` +LL | #![warn(clippy::unsafe_vector_initialization)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/deprecated.rs:10:8 +error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint + --> $DIR/deprecated.rs:10:9 | -LL | #[warn(clippy::temporary_cstring_as_ptr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` +LL | #![warn(clippy::unused_collect)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/deprecated.rs:11:8 +error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants + --> $DIR/deprecated.rs:11:9 | -LL | #[warn(clippy::panic_params)] - | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` +LL | #![warn(clippy::replace_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^ -error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/deprecated.rs:12:8 +error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018 + --> $DIR/deprecated.rs:12:9 | -LL | #[warn(clippy::unknown_clippy_lints)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` +LL | #![warn(clippy::regex_macro)] + | ^^^^^^^^^^^^^^^^^^^ error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint - --> $DIR/deprecated.rs:13:8 + --> $DIR/deprecated.rs:13:9 | -LL | #[warn(clippy::find_map)] - | ^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::find_map)] + | ^^^^^^^^^^^^^^^^ error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint - --> $DIR/deprecated.rs:14:8 + --> $DIR/deprecated.rs:14:9 | -LL | #[warn(clippy::filter_map)] - | ^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::filter_map)] + | ^^^^^^^^^^^^^^^^^^ error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items - --> $DIR/deprecated.rs:15:8 + --> $DIR/deprecated.rs:15:9 | -LL | #[warn(clippy::pub_enum_variant_names)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clippy::pub_enum_variant_names)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items - --> $DIR/deprecated.rs:16:8 - | -LL | #[warn(clippy::wrong_pub_self_convention)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/deprecated.rs:17:8 + --> $DIR/deprecated.rs:16:9 | -LL | #[warn(clippy::invalid_atomic_ordering)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` +LL | #![warn(clippy::wrong_pub_self_convention)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors From bd778e216d3c58049fe0259ce5c8e8fd45cfcbd6 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 25 Oct 2021 18:14:54 +0100 Subject: [PATCH 31/65] Register the generated lints from `cargo dev new_lint` --- clippy_dev/src/new_lint.rs | 40 +++++++++++++++++++++++---------- clippy_lints/src/lib.rs | 2 +- doc/adding_lints.md | 45 ++++++++++++++++++++------------------ 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 25320907bb492..43a478ee77db8 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -42,7 +42,8 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str }; create_lint(&lint, msrv).context("Unable to create lint implementation")?; - create_test(&lint).context("Unable to create a test for the new lint") + create_test(&lint).context("Unable to create a test for the new lint")?; + add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs") } fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { @@ -80,6 +81,33 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { } } +fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { + let path = "clippy_lints/src/lib.rs"; + let mut lib_rs = fs::read_to_string(path).context("reading")?; + + let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment"); + + let new_lint = if enable_msrv { + format!( + "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ", + lint_pass = lint.pass, + module_name = lint.name, + camel_name = to_camel_case(lint.name), + ) + } else { + format!( + "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ", + lint_pass = lint.pass, + module_name = lint.name, + camel_name = to_camel_case(lint.name), + ) + }; + + lib_rs.insert_str(comment_start, &new_lint); + + fs::write(path, lib_rs).context("writing") +} + fn write_file, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { OpenOptions::new() @@ -151,7 +179,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { }; 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(); @@ -228,18 +255,14 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { 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 { @@ -248,16 +271,11 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { 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})); "}, pass_type = pass_type, pass_lifetimes = pass_lifetimes, - pass_name = pass_name, name_upper = name_upper, name_camel = name_camel, - module_name = lint_name, ) }); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ed7e827702395..86f9d75c06f78 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -777,7 +777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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_empty_array::TrailingEmptyArray)); - + // add lints here, do not remove this comment, it's used in `new_lint` } #[rustfmt::skip] diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 004eb28b44640..0e112e37cbc1a 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -16,6 +16,7 @@ because that's clearly a non-descriptive name. - [Edition 2018 tests](#edition-2018-tests) - [Testing manually](#testing-manually) - [Lint declaration](#lint-declaration) + - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) - [Emitting a lint](#emitting-a-lint) - [Adding the lint logic](#adding-the-lint-logic) @@ -43,9 +44,9 @@ take a look at our [lint naming guidelines][lint_naming]. To get started on this lint you can run `cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` (category will default to nursery if not provided). This command will create two files: `tests/ui/foo_functions.rs` and -`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to -register the new lint. For cargo lints, two project hierarchies (fail/pass) will -be created by default under `tests/ui-cargo`. +`clippy_lints/src/foo_functions.rs`, as well as +[registering the lint](#lint-registration). For cargo lints, two project +hierarchies (fail/pass) will be created by default under `tests/ui-cargo`. Next, we'll open up these files and add our lint! @@ -220,32 +221,34 @@ declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]); impl EarlyLintPass for FooFunctions {} ``` -Normally after declaring the lint, we have to run `cargo dev update_lints`, -which updates some files, so Clippy knows about the new lint. Since we used -`cargo dev new_lint ...` to generate the lint declaration, this was done -automatically. While `update_lints` automates most of the things, it doesn't -automate everything. We will have to register our lint pass manually in the -`register_plugins` function in `clippy_lints/src/lib.rs`: +[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 +[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure +[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints +[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 + +## Lint registration + +When using `cargo dev new_lint`, the lint is automatically registered and +nothing more has to be done. + +When declaring a new lint by hand and `cargo dev update_lints` is used, the lint +pass may have to be registered manually in the `register_plugins` function in +`clippy_lints/src/lib.rs`: ```rust -store.register_early_pass(|| box foo_functions::FooFunctions); +store.register_early_pass(|| Box::new(foo_functions::FooFunctions)); ``` As one may expect, there is a corresponding `register_late_pass` method available as well. Without a call to one of `register_early_pass` or `register_late_pass`, the lint pass in question will not be run. -One reason that `cargo dev` does not automate this step is that multiple lints -can use the same lint pass, so registering the lint pass may already be done -when adding a new lint. Another reason that this step is not automated is that -the order that the passes are registered determines the order the passes -actually run, which in turn affects the order that any emitted lints are output -in. - -[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60 -[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure -[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints -[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110 +One reason that `cargo dev update_lints` does not automate this step is that +multiple lints can use the same lint pass, so registering the lint pass may +already be done when adding a new lint. Another reason that this step is not +automated is that the order that the passes are registered determines the order +the passes actually run, which in turn affects the order that any emitted lints +are output in. ## Lint passes From dea940259e34a7a78f5006562bea5d74201c88b8 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 26 Oct 2021 21:39:32 +0200 Subject: [PATCH 32/65] Remove hidden code lines in Clippy's lint list --- .../src/utils/internal_lints/metadata_collector.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 0d27874b7affb..99cf4c1ed40fb 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -512,12 +512,21 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option { let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str); let mut docs = String::from(&*lines.next()?.as_str()); let mut in_code_block = false; + let mut is_code_block_rust = false; for line in lines { - docs.push('\n'); let line = line.as_str(); let line = &*line; + + // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :) + if is_code_block_rust && line.trim_start().starts_with("# ") { + continue; + } + + // The line should be represented in the lint list, even if it's just an empty line + docs.push('\n'); if let Some(info) = line.trim_start().strip_prefix("```") { in_code_block = !in_code_block; + is_code_block_rust = false; if in_code_block { let lang = info .trim() @@ -528,6 +537,8 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option { .unwrap_or("rust"); docs.push_str("```"); docs.push_str(lang); + + is_code_block_rust = lang == "rust"; continue; } } From 5733c754d553e73a3da31a5bb2b7f3656754e1c9 Mon Sep 17 00:00:00 2001 From: Devon Hollowood Date: Tue, 26 Oct 2021 13:55:51 -0700 Subject: [PATCH 33/65] Apply suggestions from code review Co-authored-by: Fridtjof Stoldt --- tests/ui/rename.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 9375dc464d64c..377075c02464a 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -7,14 +7,12 @@ #![allow(clippy::new_without_default)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::bind_instead_of_map)] -#![allow(clippy::block_in_if_condition_expr)] -#![allow(clippy::block_in_if_condition_stmt)] #![allow(clippy::box_collection)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::map_unwrap_or)] #![allow(clippy::unwrap_used)] #![allow(clippy::expect_used)] -#![allow(clippy::for_loop_over_fallibles)] +#![allow(clippy::for_loops_over_fallibles)] #![allow(clippy::useless_conversion)] #![allow(clippy::invisible_characters)] #![allow(clippy::single_char_add_str)] @@ -34,9 +32,10 @@ #![warn(clippy::new_without_default_derive)] #![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] -#![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::option_and_then_some)] #![warn(clippy::box_vec)] +#![warn(clippy::block_in_if_condition_expr)] +#![warn(clippy::block_in_if_condition_stmt)] #![warn(clippy::option_map_unwrap_or)] #![warn(clippy::option_map_unwrap_or_else)] #![warn(clippy::result_map_unwrap_or_else)] From ab9a8f24cd418c88d87d01115749ceaf7c33ba91 Mon Sep 17 00:00:00 2001 From: Devon Hollowood Date: Tue, 26 Oct 2021 14:01:46 -0700 Subject: [PATCH 34/65] Update tests after reviewer suggestions --- tests/ui/rename.fixed | 5 +-- tests/ui/rename.stderr | 100 ++++++++++++++++++----------------------- 2 files changed, 45 insertions(+), 60 deletions(-) diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 5607001ac411f..cc295b509bc51 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -7,8 +7,6 @@ #![allow(clippy::new_without_default)] #![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::bind_instead_of_map)] -#![allow(clippy::blocks_in_if_conditions)] -#![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::map_unwrap_or)] @@ -34,9 +32,10 @@ #![warn(clippy::new_without_default)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] -#![warn(enum_intrinsics_non_enums)] #![warn(clippy::bind_instead_of_map)] #![warn(clippy::box_collection)] +#![warn(clippy::blocks_in_if_conditions)] +#![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::map_unwrap_or)] #![warn(clippy::map_unwrap_or)] #![warn(clippy::map_unwrap_or)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 6a9c6d717eebb..d720f10d117c0 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,198 +1,184 @@ -error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:10:10 - | -LL | #![allow(clippy::block_in_if_condition_expr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` - -error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:11:10 - | -LL | #![allow(clippy::block_in_if_condition_stmt)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` - -error: unknown lint: `clippy::for_loop_over_fallibles` - --> $DIR/rename.rs:17:10 - | -LL | #![allow(clippy::for_loop_over_fallibles)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::for_loops_over_fallibles` - | - = note: `-D unknown-lints` implied by `-D warnings` - error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:33:9 + --> $DIR/rename.rs:31:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:34:9 + --> $DIR/rename.rs:32:9 | 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:35:9 + --> $DIR/rename.rs:33:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:36:9 + --> $DIR/rename.rs:34:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` -error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:37:9 - | -LL | #![warn(clippy::mem_discriminant_non_enum)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` - error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:35:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:36:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` +error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` + --> $DIR/rename.rs:37:9 + | +LL | #![warn(clippy::block_in_if_condition_expr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` + +error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` + --> $DIR/rename.rs:38:9 + | +LL | #![warn(clippy::block_in_if_condition_stmt)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` + error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` -error: aborting due to 32 previous errors +error: aborting due to 30 previous errors From 73c026b73f247d38461ffd04b7115de28a9a3f2a Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Wed, 27 Oct 2021 09:12:13 +0900 Subject: [PATCH 35/65] Add test case --- tests/ui/crashes/auxiliary/ice-7868-aux.rs | 3 +++ tests/ui/crashes/ice-7868.rs | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/ui/crashes/auxiliary/ice-7868-aux.rs create mode 100644 tests/ui/crashes/ice-7868.rs diff --git a/tests/ui/crashes/auxiliary/ice-7868-aux.rs b/tests/ui/crashes/auxiliary/ice-7868-aux.rs new file mode 100644 index 0000000000000..bee29894b63d5 --- /dev/null +++ b/tests/ui/crashes/auxiliary/ice-7868-aux.rs @@ -0,0 +1,3 @@ +fn zero() { + unsafe { 0 }; +} diff --git a/tests/ui/crashes/ice-7868.rs b/tests/ui/crashes/ice-7868.rs new file mode 100644 index 0000000000000..cfe4e55294875 --- /dev/null +++ b/tests/ui/crashes/ice-7868.rs @@ -0,0 +1,6 @@ +#![warn(clippy::undocumented_unsafe_blocks)] + +#[path = "auxiliary/ice-7868-aux.rs"] +mod zero; + +fn main() {} From 36d4a4ea82b235e65d5ec32bf8f7a81438cf0e10 Mon Sep 17 00:00:00 2001 From: Matt Stavola Date: Sun, 24 Oct 2021 21:14:20 -0700 Subject: [PATCH 36/65] Add unit-hash 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/unit_hash.rs | 77 ++++++++++++++++++++ tests/ui/unit_hash.rs | 27 +++++++ tests/ui/unit_hash.stderr | 27 +++++++ 8 files changed, 137 insertions(+) create mode 100644 clippy_lints/src/unit_hash.rs create mode 100644 tests/ui/unit_hash.rs create mode 100644 tests/ui/unit_hash.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b4c687209e11..c1dba75a4c5b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3046,6 +3046,7 @@ Released 2018-09-13 [`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_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index c949ee23ecc7a..1dd70ce7c1502 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -282,6 +282,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), + LintId::of(unit_hash::UNIT_HASH), 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 ff56a6081fb57..4217fd3a3ea72 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -64,6 +64,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), + LintId::of(unit_hash::UNIT_HASH), 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 e8dd3708c8ed4..d293bb6dfc278 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -476,6 +476,7 @@ store.register_lints(&[ unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, uninit_vec::UNINIT_VEC, + unit_hash::UNIT_HASH, 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 ed7e827702395..a167c65263bb4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -364,6 +364,7 @@ mod undocumented_unsafe_blocks; mod undropped_manually_drops; mod unicode; mod uninit_vec; +mod unit_hash; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -522,6 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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_hash::UnitHash)); 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/unit_hash.rs b/clippy_lints/src/unit_hash.rs new file mode 100644 index 0000000000000..a3a3f2d41c732 --- /dev/null +++ b/clippy_lints/src/unit_hash.rs @@ -0,0 +1,77 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Detects `().hash(_)`. + /// + /// ### Why is this bad? + /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. + /// + /// ### Example + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => ().hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => 0_u8.hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + pub UNIT_HASH, + correctness, + "hashing a unit value, which does nothing" +} +declare_lint_pass!(UnitHash => [UNIT_HASH]); + +impl LateLintPass<'tcx> for UnitHash { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if_chain! { + if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; + if name_ident.ident.name == sym::hash; + if let [recv, state_param] = args; + if cx.typeck_results().expr_ty(recv).is_unit(); + then { + span_lint_and_then( + cx, + UNIT_HASH, + expr.span, + "this call to `hash` on the unit type will do nothing", + |diag| { + diag.span_suggestion( + expr.span, + "remove the call to `hash` or consider using", + format!( + "0_u8.hash({})", + snippet(cx, state_param.span, ".."), + ), + Applicability::MaybeIncorrect, + ); + diag.note("the implementation of `Hash` for `()` is a no-op"); + } + ); + } + } + } +} diff --git a/tests/ui/unit_hash.rs b/tests/ui/unit_hash.rs new file mode 100644 index 0000000000000..989916c239bad --- /dev/null +++ b/tests/ui/unit_hash.rs @@ -0,0 +1,27 @@ +#![warn(clippy::unit_hash)] + +use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; + +enum Foo { + Empty, + WithValue(u8), +} + +fn do_nothing() {} + +fn main() { + let mut state = DefaultHasher::new(); + let my_enum = Foo::Empty; + + match my_enum { + Foo::Empty => ().hash(&mut state), + Foo::WithValue(x) => x.hash(&mut state), + } + + let res = (); + res.hash(&mut state); + + #[allow(clippy::unit_arg)] + do_nothing().hash(&mut state); +} diff --git a/tests/ui/unit_hash.stderr b/tests/ui/unit_hash.stderr new file mode 100644 index 0000000000000..da276296e0282 --- /dev/null +++ b/tests/ui/unit_hash.stderr @@ -0,0 +1,27 @@ +error: this call to `hash` on the unit type will do nothing + --> $DIR/unit_hash.rs:18:23 + | +LL | Foo::Empty => ().hash(&mut state), + | ^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` + | + = note: `-D clippy::unit-hash` implied by `-D warnings` + = note: the implementation of `Hash` for `()` is a no-op + +error: this call to `hash` on the unit type will do nothing + --> $DIR/unit_hash.rs:23:5 + | +LL | res.hash(&mut state); + | ^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` + | + = note: the implementation of `Hash` for `()` is a no-op + +error: this call to `hash` on the unit type will do nothing + --> $DIR/unit_hash.rs:26:5 + | +LL | do_nothing().hash(&mut state); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` + | + = note: the implementation of `Hash` for `()` is a no-op + +error: aborting due to 3 previous errors + From e2c30f05c11bd06d2ba11584407e6671e7d5d1b8 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 27 Oct 2021 16:24:00 +0100 Subject: [PATCH 37/65] Ignore references to type aliases in ptr_arg Works using the fact that the hir path will point to a TyAlias, rather than being resolved to the underlying type --- clippy_lints/src/ptr.rs | 53 +++++++++++++++++++++++++---------------- tests/ui/ptr_arg.rs | 4 ++++ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 92a4801a8468a..8a36e20fc973d 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -3,16 +3,16 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ptr::get_spans; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; +use clippy_utils::ty::walk_ptrs_hir_ty; use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::{ - BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item, - ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, + BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind, + Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -153,7 +153,7 @@ declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USA impl<'tcx> LateLintPass<'tcx> for Ptr { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Fn(ref sig, _, body_id) = item.kind { - check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); + check_fn(cx, sig.decl, Some(body_id)); } } @@ -165,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { return; // ignore trait impls } } - check_fn(cx, sig.decl, item.hir_id(), Some(body_id)); + check_fn(cx, sig.decl, Some(body_id)); } } @@ -176,7 +176,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { } else { None }; - check_fn(cx, sig.decl, item.hir_id(), body_id); + check_fn(cx, sig.decl, body_id); } } @@ -244,13 +244,10 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { } #[allow(clippy::too_many_lines)] -fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option) { - let fn_def_id = cx.tcx.hir().local_def_id(fn_id); - let sig = cx.tcx.fn_sig(fn_def_id); - let fn_ty = sig.skip_binder(); +fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option) { let body = opt_body_id.map(|id| cx.tcx.hir().body(id)); - for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() { + for (idx, arg) in decl.inputs.iter().enumerate() { // Honor the allow attribute on parameters. See issue 5644. if let Some(body) = &body { if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) { @@ -258,8 +255,20 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: } } - if let ty::Ref(_, ty, Mutability::Not) = ty.kind() { - if is_type_diagnostic_item(cx, ty, sym::Vec) { + let (item_name, path) = if_chain! { + if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind; + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind; + if let Res::Def(_, did) = path.res; + if let Some(item_name) = cx.tcx.get_diagnostic_name(did); + then { + (item_name, path) + } else { + continue + } + }; + + match item_name { + sym::Vec => { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) { span_lint_and_then( cx, @@ -289,7 +298,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if is_type_diagnostic_item(cx, ty, sym::String) { + }, + sym::String => { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { span_lint_and_then( cx, @@ -311,7 +321,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if is_type_diagnostic_item(cx, ty, sym::PathBuf) { + }, + sym::PathBuf => { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) { span_lint_and_then( cx, @@ -338,11 +349,10 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if match_type(cx, ty, &paths::COW) { + }, + sym::Cow => { if_chain! { - if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind; - if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind; - if let [ref bx] = *pp.segments; + if let [ref bx] = *path.segments; if let Some(params) = bx.args; if !params.parenthesized; if let Some(inner) = params.args.iter().find_map(|arg| match arg { @@ -363,7 +373,8 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: ); } } - } + }, + _ => {}, } } diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 99e6d2aad8dd6..b29b26583b75f 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -160,3 +160,7 @@ mod issue6509 { let _ = str.clone().clone(); } } + +// No error for types behind an alias (#7699) +type A = Vec; +fn aliased(a: &A) {} From 35bf041c21eeb5e4ce9d892c01741a179811c811 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Thu, 28 Oct 2021 22:10:59 +0900 Subject: [PATCH 38/65] Fix ICE in `undocumented_unsafe_blocks` --- clippy_lints/src/undocumented_unsafe_blocks.rs | 5 +++-- tests/ui/crashes/ice-7868.rs | 1 + tests/ui/crashes/ice-7868.stderr | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/ui/crashes/ice-7868.stderr diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index e08e4d03c7efe..11aef50991b0a 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -145,8 +145,9 @@ impl UndocumentedUnsafeBlocks { 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 lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize; + let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize; + let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string(); let mut pos = 0; let mut comment = false; diff --git a/tests/ui/crashes/ice-7868.rs b/tests/ui/crashes/ice-7868.rs index cfe4e55294875..c6932164e3bff 100644 --- a/tests/ui/crashes/ice-7868.rs +++ b/tests/ui/crashes/ice-7868.rs @@ -1,4 +1,5 @@ #![warn(clippy::undocumented_unsafe_blocks)] +#![allow(clippy::no_effect)] #[path = "auxiliary/ice-7868-aux.rs"] mod zero; diff --git a/tests/ui/crashes/ice-7868.stderr b/tests/ui/crashes/ice-7868.stderr new file mode 100644 index 0000000000000..d7b49eb89a28b --- /dev/null +++ b/tests/ui/crashes/ice-7868.stderr @@ -0,0 +1,15 @@ +error: unsafe block missing a safety comment + --> $DIR/auxiliary/ice-7868-aux.rs:2:5 + | +LL | unsafe { 0 }; + | ^^^^^^^^^^^^ + | + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` +help: consider adding a safety comment + | +LL ~ // Safety: ... +LL ~ unsafe { 0 }; + | + +error: aborting due to previous error + From d8fcfd7d64f102402819aba3ac91954a7a6888cc Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 12 Oct 2021 09:09:54 -0500 Subject: [PATCH 39/65] Move if_then_panic to pedantic --- clippy_lints/src/if_then_panic.rs | 2 +- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 - tests/ui/fallible_impl_from.rs | 1 - tests/ui/fallible_impl_from.stderr | 16 +++++++-------- tests/ui/ptr_arg.rs | 7 +------ tests/ui/ptr_arg.stderr | 24 +++++++++++------------ 8 files changed, 23 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/if_then_panic.rs b/clippy_lints/src/if_then_panic.rs index e8cea5529e889..7946c93c6ec65 100644 --- a/clippy_lints/src/if_then_panic.rs +++ b/clippy_lints/src/if_then_panic.rs @@ -27,7 +27,7 @@ declare_clippy_lint! { /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// ``` pub IF_THEN_PANIC, - style, + pedantic, "`panic!` and only a `panic!` in `if`-then statement" } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 4e123f27ec0a6..15edb79d36c24 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -76,7 +76,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ 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), diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 268349d284811..d22b3b31f6da7 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -34,6 +34,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(functions::MUST_USE_CANDIDATE), LintId::of(functions::TOO_MANY_LINES), LintId::of(if_not_else::IF_NOT_ELSE), + LintId::of(if_then_panic::IF_THEN_PANIC), LintId::of(implicit_hasher::IMPLICIT_HASHER), LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index a39c111c57423..744880bda3e69 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -27,7 +27,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ 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), diff --git a/tests/ui/fallible_impl_from.rs b/tests/ui/fallible_impl_from.rs index 495cd97e05e15..5d5af4e463297 100644 --- a/tests/ui/fallible_impl_from.rs +++ b/tests/ui/fallible_impl_from.rs @@ -1,5 +1,4 @@ #![deny(clippy::fallible_impl_from)] -#![allow(clippy::if_then_panic)] // docs example struct Foo(i32); diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index f5d0b98c10862..5772ff055084f 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -1,5 +1,5 @@ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:6:1 + --> $DIR/fallible_impl_from.rs:5:1 | LL | / impl From for Foo { LL | | fn from(s: String) -> Self { @@ -15,13 +15,13 @@ LL | #![deny(clippy::fallible_impl_from)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:8:13 + --> $DIR/fallible_impl_from.rs:7:13 | LL | Foo(s.parse().unwrap()) | ^^^^^^^^^^^^^^^^^^ error: consider implementing `TryFrom` instead - --> $DIR/fallible_impl_from.rs:27:1 + --> $DIR/fallible_impl_from.rs:26:1 | LL | / impl From for Invalid { LL | | fn from(i: usize) -> Invalid { @@ -34,14 +34,14 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:30:13 + --> $DIR/fallible_impl_from.rs:29: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 - --> $DIR/fallible_impl_from.rs:36:1 + --> $DIR/fallible_impl_from.rs:35:1 | LL | / impl From> for Invalid { LL | | fn from(s: Option) -> Invalid { @@ -54,7 +54,7 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:38:17 + --> $DIR/fallible_impl_from.rs:37:17 | LL | let s = s.unwrap(); | ^^^^^^^^^^ @@ -68,7 +68,7 @@ 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 - --> $DIR/fallible_impl_from.rs:54:1 + --> $DIR/fallible_impl_from.rs:53:1 | LL | / impl<'a> From<&'a mut as ProjStrTrait>::ProjString> for Invalid { LL | | fn from(s: &'a mut as ProjStrTrait>::ProjString) -> Invalid { @@ -81,7 +81,7 @@ LL | | } | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> $DIR/fallible_impl_from.rs:56:12 + --> $DIR/fallible_impl_from.rs:55:12 | LL | if s.parse::().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 99e6d2aad8dd6..06370dfce6518 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -1,9 +1,4 @@ -#![allow( - unused, - clippy::many_single_char_names, - clippy::redundant_clone, - clippy::if_then_panic -)] +#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] #![warn(clippy::ptr_arg)] use std::borrow::Cow; diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 42183447ead73..64594eb870c2c 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:12:14 + --> $DIR/ptr_arg.rs:7:14 | LL | fn do_vec(x: &Vec) { | ^^^^^^^^^ help: change this to: `&[i64]` @@ -7,25 +7,25 @@ LL | fn do_vec(x: &Vec) { = note: `-D clippy::ptr-arg` implied by `-D warnings` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:21:14 + --> $DIR/ptr_arg.rs:16:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:30:15 + --> $DIR/ptr_arg.rs:25:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:43:18 + --> $DIR/ptr_arg.rs:38:18 | LL | fn do_vec(x: &Vec); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:56:14 + --> $DIR/ptr_arg.rs:51:14 | LL | fn cloned(x: &Vec) -> Vec { | ^^^^^^^^ @@ -44,7 +44,7 @@ LL | x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:65:18 + --> $DIR/ptr_arg.rs:60:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -67,7 +67,7 @@ LL | x.to_string() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:73:19 + --> $DIR/ptr_arg.rs:68:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -90,7 +90,7 @@ LL | x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:81:44 + --> $DIR/ptr_arg.rs:76:44 | LL | fn false_positive_capacity(x: &Vec, y: &String) { | ^^^^^^^ @@ -109,13 +109,13 @@ LL | let c = y; | ~ error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:95:25 + --> $DIR/ptr_arg.rs:90:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices - --> $DIR/ptr_arg.rs:148:21 + --> $DIR/ptr_arg.rs:143:21 | LL | fn foo_vec(vec: &Vec) { | ^^^^^^^^ @@ -134,7 +134,7 @@ LL | let _ = vec.to_owned().clone(); | ~~~~~~~~~~~~~~ error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:153:23 + --> $DIR/ptr_arg.rs:148:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -153,7 +153,7 @@ LL | let _ = path.to_path_buf().clone(); | ~~~~~~~~~~~~~~~~~~ error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:158:21 + --> $DIR/ptr_arg.rs:153:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ From 022146d2c3c4e1baa65f19c45205152af1a8b997 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 12 Oct 2021 09:23:05 -0500 Subject: [PATCH 40/65] Rename if_then_panic to manual_assert --- CHANGELOG.md | 6 +++--- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 4 ++-- .../src/{if_then_panic.rs => manual_assert.rs} | 8 ++++---- .../{if_then_panic.fixed => manual_assert.fixed} | 2 +- tests/ui/{if_then_panic.rs => manual_assert.rs} | 2 +- ...if_then_panic.stderr => manual_assert.stderr} | 16 ++++++++-------- 8 files changed, 21 insertions(+), 21 deletions(-) rename clippy_lints/src/{if_then_panic.rs => manual_assert.rs} (96%) rename tests/ui/{if_then_panic.fixed => manual_assert.fixed} (96%) rename tests/ui/{if_then_panic.rs => manual_assert.rs} (97%) rename tests/ui/{if_then_panic.stderr => manual_assert.stderr} (83%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 267bc07d8fa61..c78aa5908de90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ Current beta, release 2021-12-02 [#7610](https://github.com/rust-lang/rust-clippy/pull/7610) * [`same_name_method`] [#7653](https://github.com/rust-lang/rust-clippy/pull/7653) -* [`if_then_panic`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669) +* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669) * [`non_send_fields_in_send_ty`] [#7709](https://github.com/rust-lang/rust-clippy/pull/7709) * [`equatable_if_let`] @@ -139,7 +139,7 @@ Current beta, release 2021-12-02 `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663) * [`while_let_on_iterator`]: Produce correct suggestion when using `&mut` [#7690](https://github.com/rust-lang/rust-clippy/pull/7690) -* [`if_then_panic`]: No better handles complex conditions +* [`manual_assert`]: No better handles complex conditions [#7741](https://github.com/rust-lang/rust-clippy/pull/7741) * Correctly handle signs in exponents in numeric literals lints [#7747](https://github.com/rust-lang/rust-clippy/pull/7747) @@ -2895,7 +2895,6 @@ Released 2018-09-13 [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else -[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone @@ -2953,6 +2952,7 @@ Released 2018-09-13 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion +[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 249bf77a8f288..9b21079157463 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -159,7 +159,6 @@ store.register_lints(&[ 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, @@ -216,6 +215,7 @@ store.register_lints(&[ loops::WHILE_LET_ON_ITERATOR, macro_use::MACRO_USE_IMPORTS, main_recursion::MAIN_RECURSION, + manual_assert::MANUAL_ASSERT, manual_async_fn::MANUAL_ASYNC_FN, manual_map::MANUAL_MAP, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index d22b3b31f6da7..63ab7f1ca6f67 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -34,7 +34,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(functions::MUST_USE_CANDIDATE), LintId::of(functions::TOO_MANY_LINES), LintId::of(if_not_else::IF_NOT_ELSE), - LintId::of(if_then_panic::IF_THEN_PANIC), LintId::of(implicit_hasher::IMPLICIT_HASHER), LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), @@ -49,6 +48,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(loops::EXPLICIT_ITER_LOOP), LintId::of(macro_use::MACRO_USE_IMPORTS), + LintId::of(manual_assert::MANUAL_ASSERT), LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(matches::MATCH_BOOL), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fc15c591623e6..fd5f164e7a1bd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -228,7 +228,6 @@ mod get_last_with_len; mod identity_op; mod if_let_mutex; mod if_not_else; -mod if_then_panic; mod if_then_some_else_none; mod implicit_hasher; mod implicit_return; @@ -255,6 +254,7 @@ mod literal_representation; mod loops; mod macro_use; mod main_recursion; +mod manual_assert; mod manual_async_fn; mod manual_map; mod manual_non_exhaustive; @@ -772,7 +772,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors)); 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)); + store.register_late_pass(move || Box::new(manual_assert::ManualAssert)); 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())); diff --git a/clippy_lints/src/if_then_panic.rs b/clippy_lints/src/manual_assert.rs similarity index 96% rename from clippy_lints/src/if_then_panic.rs rename to clippy_lints/src/manual_assert.rs index 7946c93c6ec65..c639be1bccba4 100644 --- a/clippy_lints/src/if_then_panic.rs +++ b/clippy_lints/src/manual_assert.rs @@ -26,14 +26,14 @@ declare_clippy_lint! { /// let sad_people: Vec<&str> = vec![]; /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); /// ``` - pub IF_THEN_PANIC, + pub MANUAL_ASSERT, pedantic, "`panic!` and only a `panic!` in `if`-then statement" } -declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]); +declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]); -impl LateLintPass<'_> for IfThenPanic { +impl LateLintPass<'_> for ManualAssert { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let Expr { @@ -86,7 +86,7 @@ impl LateLintPass<'_> for IfThenPanic { span_lint_and_sugg( cx, - IF_THEN_PANIC, + MANUAL_ASSERT, expr.span, "only a `panic!` in `if`-then statement", "try", diff --git a/tests/ui/if_then_panic.fixed b/tests/ui/manual_assert.fixed similarity index 96% rename from tests/ui/if_then_panic.fixed rename to tests/ui/manual_assert.fixed index 0998f8ffa9de4..9d461cff68d88 100644 --- a/tests/ui/if_then_panic.fixed +++ b/tests/ui/manual_assert.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::if_then_panic)] +#![warn(clippy::manual_assert)] fn main() { let a = vec![1, 2, 3]; diff --git a/tests/ui/if_then_panic.rs b/tests/ui/manual_assert.rs similarity index 97% rename from tests/ui/if_then_panic.rs rename to tests/ui/manual_assert.rs index 10433c8d54f2d..6aadff887ca8d 100644 --- a/tests/ui/if_then_panic.rs +++ b/tests/ui/manual_assert.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::if_then_panic)] +#![warn(clippy::manual_assert)] fn main() { let a = vec![1, 2, 3]; diff --git a/tests/ui/if_then_panic.stderr b/tests/ui/manual_assert.stderr similarity index 83% rename from tests/ui/if_then_panic.stderr rename to tests/ui/manual_assert.stderr index 5bb62f8756606..ab2786247b1de 100644 --- a/tests/ui/if_then_panic.stderr +++ b/tests/ui/manual_assert.stderr @@ -1,15 +1,15 @@ error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:19:5 + --> $DIR/manual_assert.rs:19:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);` | - = note: `-D clippy::if-then-panic` implied by `-D warnings` + = note: `-D clippy::manual-assert` implied by `-D warnings` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:22:5 + --> $DIR/manual_assert.rs:22:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:39:5 + --> $DIR/manual_assert.rs:39:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> $DIR/if_then_panic.rs:42:5 + --> $DIR/manual_assert.rs:42:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -33,7 +33,7 @@ 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 + --> $DIR/manual_assert.rs:45:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -41,7 +41,7 @@ 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 + --> $DIR/manual_assert.rs:48:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -49,7 +49,7 @@ 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 + --> $DIR/manual_assert.rs:51:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); From 00ea73e1627841fe3da7ba3699bbe99705063df1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 13 Oct 2021 13:45:53 +0200 Subject: [PATCH 41/65] avoid linting `possible_truncation` on bit-reducing operations --- .../src/casts/cast_possible_truncation.rs | 81 +++++++++++++++++-- tests/ui/cast.rs | 15 ++++ tests/ui/cast.stderr | 14 +++- 3 files changed, 101 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 2ae7d16e00bb2..4af412ccaf35d 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,23 +1,88 @@ +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::expr_or_init; use clippy_utils::ty::is_isize_or_usize; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; use super::{utils, CAST_POSSIBLE_TRUNCATION}; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { - // do not lint if cast comes from a `signum` function - if let ExprKind::MethodCall(path, ..) = expr_or_init(cx, cast_expr).kind { - if path.ident.name.as_str() == "signum" { - return; - } +fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { + Some(c) + } else { + None } +} +fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros())) +} + +fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 { + match expr_or_init(cx, expr).kind { + ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed), + ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)), + ExprKind::Binary(op, left, right) => match op.node { + BinOpKind::Div => { + apply_reductions(cx, nbits, left, signed) + - (if signed { + 0 // let's be conservative here + } else { + // by dividing by 1, we remove 0 bits, etc. + get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1)) + }) + }, + BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right) + .unwrap_or(u64::max_value()) + .min(apply_reductions(cx, nbits, left, signed)), + BinOpKind::Shr => { + apply_reductions(cx, nbits, left, signed) + - constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high")) + }, + _ => nbits, + }, + ExprKind::MethodCall(method, _, [left, right], _) => { + if signed { + return nbits; + } + let max_bits = if method.ident.as_str() == "min" { + get_constant_bits(cx, right) + } else { + None + }; + apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value())) + }, + ExprKind::MethodCall(method, _, [_, lo, hi], _) => { + if method.ident.as_str() == "clamp" { + //FIXME: make this a diagnostic item + if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) { + return lo_bits.max(hi_bits); + } + } + nbits + }, + ExprKind::MethodCall(method, _, [_value], _) => { + if method.ident.name.as_str() == "signum" { + 0 // do not lint if cast comes from a `signum` function + } else { + nbits + } + }, + _ => nbits, + } +} + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { let msg = match (cast_from.is_integral(), cast_to.is_integral()) { (true, true) => { - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); + let from_nbits = apply_reductions( + cx, + utils::int_ty_to_nbits(cast_from, cx.tcx), + cast_expr, + cast_from.is_signed(), + ); let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index adc95e63ae565..ebc1ed5587fe3 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -100,4 +100,19 @@ fn main() { let s = x.signum(); let _ = s as i32; + + // Test for signed min + (-99999999999i64).min(1) as i8; // should be linted because signed + + // Test for various operations that remove enough bits for the result to fit + (999999u64 & 1) as u8; + (999999u64 % 15) as u8; + (999999u64 / 0x1_0000_0000_0000) as u16; + ({ 999999u64 >> 56 }) as u8; + ({ + let x = 999999u64; + x.min(1) + }) as u8; + 999999u64.clamp(0, 255) as u8; + 999999u64.clamp(0, 256) as u8; // should still be linted } diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 4c66d73649484..edf8790cf33d8 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -138,5 +138,17 @@ error: casting `isize` to `usize` may lose the sign of the value LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ -error: aborting due to 22 previous errors +error: casting `i64` to `i8` may truncate the value + --> $DIR/cast.rs:105:5 + | +LL | (-99999999999i64).min(1) as i8; // should be linted because signed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: casting `u64` to `u8` may truncate the value + --> $DIR/cast.rs:117:5 + | +LL | 999999u64.clamp(0, 256) as u8; // should still be linted + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors From 2f327aaba594b86ca15a9b81aebc0d8e5667b30f Mon Sep 17 00:00:00 2001 From: Ahmed Karaman <20889958+ahmedkrmn@users.noreply.github.com> Date: Fri, 29 Oct 2021 04:11:43 +0200 Subject: [PATCH 42/65] Disable "if_not_else" lints firing on else-ifs 1. Convert IfNotElse to LateLintPass and use clippy_utils::is_else_clause for checking. 2. Handle the case where the span comes from desugaring. 3. Update tests. --- clippy_lints/src/if_not_else.rs | 23 +++++++++++++++-------- clippy_lints/src/lib.rs | 2 +- tests/ui/if_not_else.rs | 10 ++++++++++ tests/ui/if_not_else.stderr | 4 ++-- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 3ce91d421baca..ac938156237bf 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -2,9 +2,9 @@ //! on the condition use clippy_utils::diagnostics::span_lint_and_help; -use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp}; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_middle::lint::in_external_macro; +use clippy_utils::is_else_clause; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -46,14 +46,21 @@ declare_clippy_lint! { declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]); -impl EarlyLintPass for IfNotElse { - fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { - if in_external_macro(cx.sess, item.span) { +impl LateLintPass<'_> for IfNotElse { + fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { + // While loops will be desugared to ExprKind::If. This will cause the lint to fire. + // To fix this, return early if this span comes from a macro or desugaring. + if item.span.from_expansion() { return; } - if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind { + if let ExprKind::If(cond, _, Some(els)) = item.kind { if let ExprKind::Block(..) = els.kind { - match cond.kind { + // Disable firing the lint in "else if" expressions. + if is_else_clause(cx.tcx, item) { + return; + } + + match cond.peel_drop_temps().kind { ExprKind::Unary(UnOp::Not, _) => { span_lint_and_help( cx, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fd5f164e7a1bd..7174d0a082e0f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -668,7 +668,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(double_parens::DoubleParens)); store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new())); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); - store.register_early_pass(|| Box::new(if_not_else::IfNotElse)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); store.register_early_pass(|| Box::new(formatting::Formatting)); @@ -722,6 +721,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(if_not_else::IfNotElse)); 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)); diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index dc3fb1ceac9a4..b7012b43d2976 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -1,6 +1,9 @@ #![warn(clippy::all)] #![warn(clippy::if_not_else)] +fn foo() -> bool { + unimplemented!() +} fn bla() -> bool { unimplemented!() } @@ -16,4 +19,11 @@ fn main() { } else { println!("Bunny"); } + if !foo() { + println!("Foo"); + } else if !bla() { + println!("Bugs"); + } else { + println!("Bunny"); + } } diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index 53d1b86d02a96..8c8cc44bb0358 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -1,5 +1,5 @@ error: unnecessary boolean `not` operation - --> $DIR/if_not_else.rs:9:5 + --> $DIR/if_not_else.rs:12:5 | LL | / if !bla() { LL | | println!("Bugs"); @@ -12,7 +12,7 @@ LL | | } = help: remove the `!` and swap the blocks of the `if`/`else` error: unnecessary `!=` operation - --> $DIR/if_not_else.rs:14:5 + --> $DIR/if_not_else.rs:17:5 | LL | / if 4 != 5 { LL | | println!("Bugs"); From 665ff57fde7630474b59fc3f292f2b01a26a3493 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 30 Oct 2021 06:22:19 +0200 Subject: [PATCH 43/65] Remove expects from FullInt Partial{Ord,Eq} --- clippy_utils/src/consts.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 3e5d74a66f4e8..3b718d64ce60f 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -246,27 +246,26 @@ impl FullInt { impl PartialEq for FullInt { #[must_use] fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal + self.cmp(other) == Ordering::Equal } } impl PartialOrd for FullInt { #[must_use] fn partial_cmp(&self, other: &Self) -> Option { - Some(match (self, other) { - (&Self::S(s), &Self::S(o)) => s.cmp(&o), - (&Self::U(s), &Self::U(o)) => s.cmp(&o), - (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o), - (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(), - }) + Some(self.cmp(other)) } } impl Ord for FullInt { #[must_use] fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other) - .expect("`partial_cmp` for FullInt can never return `None`") + match (self, other) { + (&Self::S(s), &Self::S(o)) => s.cmp(&o), + (&Self::U(s), &Self::U(o)) => s.cmp(&o), + (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o), + (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(), + } } } From c8edd9a16e2e9db1fa2f26a0164740ae426f4876 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 30 Oct 2021 06:22:19 +0200 Subject: [PATCH 44/65] Remove casts from FullInt impl --- clippy_utils/src/consts.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 3b718d64ce60f..85dad1dcfb26b 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -230,16 +230,9 @@ pub enum FullInt { } impl FullInt { - #[allow(clippy::cast_sign_loss)] #[must_use] fn cmp_s_u(s: i128, u: u128) -> Ordering { - if s < 0 { - Ordering::Less - } else if u > (i128::MAX as u128) { - Ordering::Greater - } else { - (s as u128).cmp(&u) - } + u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u)) } } From c6dca68eca75a46af31d7175486909c720c2aebc Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 30 Oct 2021 06:22:19 +0200 Subject: [PATCH 45/65] Simplify FullInt Ord impl --- clippy_utils/src/consts.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 85dad1dcfb26b..7ce9676ed05ae 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -253,11 +253,11 @@ impl PartialOrd for FullInt { impl Ord for FullInt { #[must_use] fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (&Self::S(s), &Self::S(o)) => s.cmp(&o), - (&Self::U(s), &Self::U(o)) => s.cmp(&o), - (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o), - (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(), + match (*self, *other) { + (Self::S(s), Self::S(o)) => s.cmp(&o), + (Self::U(s), Self::U(o)) => s.cmp(&o), + (Self::S(s), Self::U(o)) => Self::cmp_s_u(s, o), + (Self::U(s), Self::S(o)) => Self::cmp_s_u(o, s).reverse(), } } } From 4a86156c66a8cb66da85ffe68b90bd0f643e441b Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 30 Oct 2021 06:22:19 +0200 Subject: [PATCH 46/65] Simplify FullInt Ord impl (2) --- clippy_utils/src/consts.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 7ce9676ed05ae..e40a1d2f2798e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -253,11 +253,13 @@ impl PartialOrd for FullInt { impl Ord for FullInt { #[must_use] fn cmp(&self, other: &Self) -> Ordering { + use FullInt::{S, U}; + match (*self, *other) { - (Self::S(s), Self::S(o)) => s.cmp(&o), - (Self::U(s), Self::U(o)) => s.cmp(&o), - (Self::S(s), Self::U(o)) => Self::cmp_s_u(s, o), - (Self::U(s), Self::S(o)) => Self::cmp_s_u(o, s).reverse(), + (S(s), S(o)) => s.cmp(&o), + (U(s), U(o)) => s.cmp(&o), + (S(s), U(o)) => Self::cmp_s_u(s, o), + (U(s), S(o)) => Self::cmp_s_u(o, s).reverse(), } } } From e8c4046841b43e4b3ea3ff8f5c22858f34c8fe9f Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 30 Oct 2021 06:22:19 +0200 Subject: [PATCH 47/65] Simplify FullInt Ord impl `cmp_s_u` is a tiny helper function only used by `cmp` and isn't useful on it's own. Making it a nested function of `cmp` makes that clear and as a bonus it's easier to call and doesn't require a `#[must_use]` attribute. --- clippy_utils/src/consts.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e40a1d2f2798e..04347672e0fbb 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -229,13 +229,6 @@ pub enum FullInt { U(u128), } -impl FullInt { - #[must_use] - fn cmp_s_u(s: i128, u: u128) -> Ordering { - u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u)) - } -} - impl PartialEq for FullInt { #[must_use] fn eq(&self, other: &Self) -> bool { @@ -255,11 +248,15 @@ impl Ord for FullInt { fn cmp(&self, other: &Self) -> Ordering { use FullInt::{S, U}; + fn cmp_s_u(s: i128, u: u128) -> Ordering { + u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u)) + } + match (*self, *other) { (S(s), S(o)) => s.cmp(&o), (U(s), U(o)) => s.cmp(&o), - (S(s), U(o)) => Self::cmp_s_u(s, o), - (U(s), S(o)) => Self::cmp_s_u(o, s).reverse(), + (S(s), U(o)) => cmp_s_u(s, o), + (U(s), S(o)) => cmp_s_u(o, s).reverse(), } } } From a4ede72b3d2bea7ff3877e431139e7ae7c11d276 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sat, 23 Oct 2021 09:42:52 +0200 Subject: [PATCH 48/65] update most tests to 2021 edition --- Cargo.toml | 2 +- tests/compile-test.rs | 5 +- tests/ui-toml/functions_maxlines/test.rs | 2 - tests/ui-toml/functions_maxlines/test.stderr | 8 +-- tests/ui/assertions_on_constants.rs | 4 +- tests/ui/assertions_on_constants.stderr | 19 ++---- tests/ui/async_yields_async.fixed | 1 - tests/ui/async_yields_async.rs | 1 - tests/ui/async_yields_async.stderr | 12 ++-- tests/ui/await_holding_lock.rs | 1 - tests/ui/await_holding_lock.stderr | 16 ++--- tests/ui/await_holding_refcell_ref.rs | 1 - tests/ui/await_holding_refcell_ref.stderr | 24 +++---- tests/ui/crashes/ice-3969.rs | 5 +- tests/ui/crashes/ice-3969.stderr | 44 +++++++------ tests/ui/crashes/ice-5207.rs | 2 - tests/ui/crashes/ice-6252.rs | 1 - tests/ui/crashes/ice-6252.stderr | 12 ++-- tests/ui/crashes/ice-7231.rs | 1 - .../crashes/used_underscore_binding_macro.rs | 2 - tests/ui/debug_assert_with_mut_call.rs | 2 +- tests/ui/diverging_sub_expression.rs | 1 - tests/ui/diverging_sub_expression.stderr | 22 +++++-- tests/ui/doc_errors.rs | 1 - tests/ui/doc_errors.stderr | 14 ++-- tests/ui/eval_order_dependence.rs | 2 - tests/ui/eval_order_dependence.stderr | 16 ++--- tests/ui/fallible_impl_from.stderr | 6 +- tests/ui/future_not_send.rs | 1 - tests/ui/future_not_send.stderr | 36 +++++------ tests/ui/implicit_hasher.rs | 1 - tests/ui/implicit_hasher.stderr | 24 +++---- tests/ui/implicit_return.fixed | 1 - tests/ui/implicit_return.rs | 1 - tests/ui/implicit_return.stderr | 32 +++++----- .../ui/inconsistent_struct_constructor.fixed | 1 - tests/ui/inconsistent_struct_constructor.rs | 1 - .../ui/inconsistent_struct_constructor.stderr | 4 +- tests/ui/issue-7447.stderr | 19 ++++++ tests/ui/issue_4266.rs | 1 - tests/ui/issue_4266.stderr | 4 +- tests/ui/len_without_is_empty.rs | 2 - tests/ui/len_without_is_empty.stderr | 34 +++++----- tests/ui/macro_use_imports.fixed | 1 - tests/ui/macro_use_imports.rs | 1 - tests/ui/macro_use_imports.stderr | 14 ++-- tests/ui/manual_assert.fixed | 2 + tests/ui/manual_assert.rs | 2 + tests/ui/manual_assert.stderr | 14 ++-- tests/ui/manual_async_fn.fixed | 1 - tests/ui/manual_async_fn.rs | 1 - tests/ui/manual_async_fn.stderr | 20 +++--- tests/ui/manual_map_option.fixed | 1 - tests/ui/manual_map_option.rs | 1 - tests/ui/manual_map_option.stderr | 42 ++++++------ tests/ui/match_wild_err_arm.rs | 4 +- tests/ui/match_wild_err_arm.stderr | 8 +-- tests/ui/methods.rs | 1 - tests/ui/methods.stderr | 4 +- tests/ui/missing-doc.rs | 9 ++- tests/ui/missing-doc.stderr | 48 +++++++------- tests/ui/missing_panics_doc.rs | 1 - tests/ui/missing_panics_doc.stderr | 34 +++++----- tests/ui/needless_borrow_pat.rs | 1 - tests/ui/needless_borrow_pat.stderr | 24 +++---- tests/ui/needless_return.fixed | 1 - tests/ui/needless_return.rs | 1 - tests/ui/needless_return.stderr | 64 +++++++++---------- tests/ui/non_expressive_names.rs | 4 +- tests/ui/option_if_let_else.fixed | 1 - tests/ui/option_if_let_else.rs | 1 - tests/ui/option_if_let_else.stderr | 28 ++++---- tests/ui/panic_in_result_fn.rs | 1 - tests/ui/panic_in_result_fn.stderr | 28 ++++---- tests/ui/redundant_clone.fixed | 2 +- tests/ui/redundant_clone.stderr | 14 +++- tests/ui/ref_binding_to_reference.rs | 1 - tests/ui/ref_binding_to_reference.stderr | 14 ++-- tests/ui/should_impl_trait/corner_cases.rs | 2 - tests/ui/should_impl_trait/method_list_1.rs | 2 - .../ui/should_impl_trait/method_list_1.stderr | 28 ++++---- tests/ui/should_impl_trait/method_list_2.rs | 2 - .../ui/should_impl_trait/method_list_2.stderr | 30 ++++----- tests/ui/single_component_path_imports.fixed | 1 - tests/ui/single_component_path_imports.rs | 1 - tests/ui/single_component_path_imports.stderr | 4 +- .../single_component_path_imports_macro.fixed | 1 - .../ui/single_component_path_imports_macro.rs | 1 - ...single_component_path_imports_macro.stderr | 2 +- ...gle_component_path_imports_nested_first.rs | 1 - ...component_path_imports_nested_first.stderr | 6 +- ...ingle_component_path_imports_self_after.rs | 1 - ...ngle_component_path_imports_self_before.rs | 1 - tests/ui/unused_async.rs | 1 - tests/ui/unused_async.stderr | 2 +- tests/ui/use_self.fixed | 1 - tests/ui/use_self.rs | 1 - tests/ui/use_self.stderr | 56 ++++++++-------- tests/ui/used_underscore_binding.rs | 1 - tests/ui/used_underscore_binding.stderr | 12 ++-- tests/ui/wildcard_imports.fixed | 7 +- tests/ui/wildcard_imports.rs | 7 +- tests/ui/wildcard_imports.stderr | 42 ++++++------ tests/ui/wrong_self_convention.rs | 1 - tests/ui/wrong_self_convention.stderr | 48 +++++++------- tests/ui/wrong_self_convention2.rs | 1 - tests/ui/wrong_self_convention2.stderr | 4 +- tests/ui/wrong_self_conventions_mut.rs | 1 - tests/ui/wrong_self_conventions_mut.stderr | 4 +- 109 files changed, 525 insertions(+), 530 deletions(-) create mode 100644 tests/ui/issue-7447.stderr diff --git a/Cargo.toml b/Cargo.toml index ed7fb1440139f..cbf3a6515cfba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true } [dev-dependencies] cargo_metadata = "0.12" -compiletest_rs = { version = "0.7", features = ["tmp"] } +compiletest_rs = { version = "0.7.1", features = ["tmp"] } tester = "0.9" regex = "1.5" # This is used by the `collect-metadata` alias. diff --git a/tests/compile-test.rs b/tests/compile-test.rs index c15835ef29956..f25cf1d3ef561 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -104,7 +104,10 @@ fn extern_flags() -> String { } fn default_config() -> compiletest::Config { - let mut config = compiletest::Config::default(); + let mut config = compiletest::Config { + edition: Some("2021".into()), + ..compiletest::Config::default() + }; if let Ok(filters) = env::var("TESTNAME") { config.filters = filters.split(',').map(std::string::ToString::to_string).collect(); diff --git a/tests/ui-toml/functions_maxlines/test.rs b/tests/ui-toml/functions_maxlines/test.rs index 33a3ef7513631..e678c896fd3e3 100644 --- a/tests/ui-toml/functions_maxlines/test.rs +++ b/tests/ui-toml/functions_maxlines/test.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::too_many_lines)] // This function should be considered one line. diff --git a/tests/ui-toml/functions_maxlines/test.stderr b/tests/ui-toml/functions_maxlines/test.stderr index 7551cac9f504b..d736bf899735a 100644 --- a/tests/ui-toml/functions_maxlines/test.stderr +++ b/tests/ui-toml/functions_maxlines/test.stderr @@ -1,5 +1,5 @@ error: this function has too many lines (2/1) - --> $DIR/test.rs:20:1 + --> $DIR/test.rs:18:1 | LL | / fn too_many_lines() { LL | | println!("This is bad."); @@ -10,7 +10,7 @@ LL | | } = note: `-D clippy::too-many-lines` implied by `-D warnings` error: this function has too many lines (4/1) - --> $DIR/test.rs:26:1 + --> $DIR/test.rs:24:1 | LL | / async fn async_too_many_lines() { LL | | println!("This is bad."); @@ -19,7 +19,7 @@ LL | | } | |_^ error: this function has too many lines (4/1) - --> $DIR/test.rs:32:1 + --> $DIR/test.rs:30:1 | LL | / fn closure_too_many_lines() { LL | | let _ = { @@ -30,7 +30,7 @@ LL | | } | |_^ error: this function has too many lines (2/1) - --> $DIR/test.rs:54:1 + --> $DIR/test.rs:52:1 | LL | / fn comment_before_code() { LL | | let _ = "test"; diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index 2180f848d62cd..cb516d0f97783 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -1,3 +1,4 @@ +//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843 #![allow(non_fmt_panics)] macro_rules! assert_const { @@ -6,7 +7,6 @@ macro_rules! assert_const { debug_assert!($len < 0); }; } - fn main() { assert!(true); assert!(false); @@ -14,7 +14,7 @@ fn main() { assert!(false, "false message"); let msg = "panic message"; - assert!(false, msg.to_uppercase()); + assert!(false, "{}", msg.to_uppercase()); const B: bool = true; assert!(B); diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr index 4ca1e6f6e88cc..ec80ec702fb57 100644 --- a/tests/ui/assertions_on_constants.stderr +++ b/tests/ui/assertions_on_constants.stderr @@ -26,22 +26,13 @@ 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) -error: `assert!(false, "false message")` should probably be replaced +error: `assert!(false, $crate::const_format_args!($($t)+))` 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) - -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())` + = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(true)` will be optimized out by the compiler @@ -62,13 +53,13 @@ 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) -error: `assert!(false, "C message")` should probably be replaced +error: `assert!(false, $crate::const_format_args!($($t)+))` 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")` + = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))` = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: `debug_assert!(true)` will be optimized out by the compiler @@ -80,5 +71,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) -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/async_yields_async.fixed b/tests/ui/async_yields_async.fixed index 9b1a7ac3ba9de..e20b58269b93e 100644 --- a/tests/ui/async_yields_async.fixed +++ b/tests/ui/async_yields_async.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/tests/ui/async_yields_async.rs b/tests/ui/async_yields_async.rs index 731c094edb42b..c1dfa39845025 100644 --- a/tests/ui/async_yields_async.rs +++ b/tests/ui/async_yields_async.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/tests/ui/async_yields_async.stderr b/tests/ui/async_yields_async.stderr index 3f2051458f677..b0c4215e7ddf1 100644 --- a/tests/ui/async_yields_async.stderr +++ b/tests/ui/async_yields_async.stderr @@ -1,5 +1,5 @@ error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:40:9 + --> $DIR/async_yields_async.rs:39:9 | LL | let _h = async { | ____________________- @@ -20,7 +20,7 @@ LL + }.await | error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:45:9 + --> $DIR/async_yields_async.rs:44:9 | LL | let _i = async { | ____________________- @@ -33,7 +33,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:51:9 + --> $DIR/async_yields_async.rs:50:9 | LL | let _j = async || { | _______________________- @@ -53,7 +53,7 @@ LL + }.await | error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:56:9 + --> $DIR/async_yields_async.rs:55:9 | LL | let _k = async || { | _______________________- @@ -66,7 +66,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:58:23 + --> $DIR/async_yields_async.rs:57:23 | LL | let _l = async || CustomFutureType; | ^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | let _l = async || CustomFutureType; | help: consider awaiting this value: `CustomFutureType.await` error: an async construct yields a type which is itself awaitable - --> $DIR/async_yields_async.rs:64:9 + --> $DIR/async_yields_async.rs:63:9 | LL | let _m = async || { | _______________________- diff --git a/tests/ui/await_holding_lock.rs b/tests/ui/await_holding_lock.rs index 0458950edee1c..dd6640a387a23 100644 --- a/tests/ui/await_holding_lock.rs +++ b/tests/ui/await_holding_lock.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::await_holding_lock)] use std::sync::Mutex; diff --git a/tests/ui/await_holding_lock.stderr b/tests/ui/await_holding_lock.stderr index a5fcff7e0e443..ddfb104cdfbd0 100644 --- a/tests/ui/await_holding_lock.stderr +++ b/tests/ui/await_holding_lock.stderr @@ -1,12 +1,12 @@ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:7:9 + --> $DIR/await_holding_lock.rs:6:9 | LL | let guard = x.lock().unwrap(); | ^^^^^ | = note: `-D clippy::await-holding-lock` implied by `-D warnings` note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:7:5 + --> $DIR/await_holding_lock.rs:6:5 | LL | / let guard = x.lock().unwrap(); LL | | baz().await @@ -14,13 +14,13 @@ LL | | } | |_^ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:28:9 + --> $DIR/await_holding_lock.rs:27:9 | LL | let guard = x.lock().unwrap(); | ^^^^^ | note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:28:5 + --> $DIR/await_holding_lock.rs:27:5 | LL | / let guard = x.lock().unwrap(); LL | | @@ -32,13 +32,13 @@ LL | | } | |_^ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:41:13 + --> $DIR/await_holding_lock.rs:40:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:41:9 + --> $DIR/await_holding_lock.rs:40:9 | LL | / let guard = x.lock().unwrap(); LL | | baz().await @@ -46,13 +46,13 @@ LL | | }; | |_____^ error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await - --> $DIR/await_holding_lock.rs:53:13 + --> $DIR/await_holding_lock.rs:52:13 | LL | let guard = x.lock().unwrap(); | ^^^^^ | note: these are all the await points this lock is held through - --> $DIR/await_holding_lock.rs:53:9 + --> $DIR/await_holding_lock.rs:52:9 | LL | / let guard = x.lock().unwrap(); LL | | baz().await diff --git a/tests/ui/await_holding_refcell_ref.rs b/tests/ui/await_holding_refcell_ref.rs index 88841597bb60b..23b7095de3a39 100644 --- a/tests/ui/await_holding_refcell_ref.rs +++ b/tests/ui/await_holding_refcell_ref.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::await_holding_refcell_ref)] use std::cell::RefCell; diff --git a/tests/ui/await_holding_refcell_ref.stderr b/tests/ui/await_holding_refcell_ref.stderr index 55e41dbca96f8..67cc0032be2f4 100644 --- a/tests/ui/await_holding_refcell_ref.stderr +++ b/tests/ui/await_holding_refcell_ref.stderr @@ -1,12 +1,12 @@ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:7:9 + --> $DIR/await_holding_refcell_ref.rs:6:9 | LL | let b = x.borrow(); | ^ | = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings` note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:7:5 + --> $DIR/await_holding_refcell_ref.rs:6:5 | LL | / let b = x.borrow(); LL | | baz().await @@ -14,13 +14,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:12:9 + --> $DIR/await_holding_refcell_ref.rs:11:9 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:12:5 + --> $DIR/await_holding_refcell_ref.rs:11:5 | LL | / let b = x.borrow_mut(); LL | | baz().await @@ -28,13 +28,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:33:9 + --> $DIR/await_holding_refcell_ref.rs:32:9 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:33:5 + --> $DIR/await_holding_refcell_ref.rs:32:5 | LL | / let b = x.borrow_mut(); LL | | @@ -46,13 +46,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:45:9 + --> $DIR/await_holding_refcell_ref.rs:44:9 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:45:5 + --> $DIR/await_holding_refcell_ref.rs:44:5 | LL | / let b = x.borrow_mut(); LL | | @@ -64,13 +64,13 @@ LL | | } | |_^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:60:13 + --> $DIR/await_holding_refcell_ref.rs:59:13 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:60:9 + --> $DIR/await_holding_refcell_ref.rs:59:9 | LL | / let b = x.borrow_mut(); LL | | baz().await @@ -78,13 +78,13 @@ LL | | }; | |_____^ error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await - --> $DIR/await_holding_refcell_ref.rs:72:13 + --> $DIR/await_holding_refcell_ref.rs:71:13 | LL | let b = x.borrow_mut(); | ^ | note: these are all the await points this ref is held through - --> $DIR/await_holding_refcell_ref.rs:72:9 + --> $DIR/await_holding_refcell_ref.rs:71:9 | LL | / let b = x.borrow_mut(); LL | | baz().await diff --git a/tests/ui/crashes/ice-3969.rs b/tests/ui/crashes/ice-3969.rs index 4feab7910b744..9b68cac7ff485 100644 --- a/tests/ui/crashes/ice-3969.rs +++ b/tests/ui/crashes/ice-3969.rs @@ -7,7 +7,6 @@ // in type inference. #![feature(trivial_bounds)] #![allow(unused)] - trait A {} impl A for i32 {} @@ -22,9 +21,9 @@ where fn unsized_local() where - for<'a> Dst: Sized, + for<'a> Dst: Sized, { - let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); + let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); } fn return_str() -> str diff --git a/tests/ui/crashes/ice-3969.stderr b/tests/ui/crashes/ice-3969.stderr index 9a89047f07277..79018080886c0 100644 --- a/tests/ui/crashes/ice-3969.stderr +++ b/tests/ui/crashes/ice-3969.stderr @@ -1,30 +1,34 @@ -error: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-3969.rs:25:17 +error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:20:10 | -LL | for<'a> Dst: Sized, - | ^^^^^^ help: use `dyn`: `dyn A + 'a` +LL | str: Sized; + | ^^^^^ | - = note: `-D bare-trait-objects` implied by `-D warnings` - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see + = note: `-D trivial-bounds` implied by `-D warnings` -error: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-3969.rs:27:16 +error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:24:30 | -LL | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); - | ^ help: use `dyn`: `dyn A` +LL | for<'a> Dst: Sized, + | ^^^^^ + +error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:31:10 | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see +LL | str: Sized, + | ^^^^^ -error: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-3969.rs:27:57 +error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:38:13 | -LL | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); - | ^ help: use `dyn`: `dyn A` +LL | String: ::std::ops::Neg, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters + --> $DIR/ice-3969.rs:45:10 | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see +LL | i32: Iterator, + | ^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/crashes/ice-5207.rs b/tests/ui/crashes/ice-5207.rs index 1b20c9defac82..f463f78a99ab7 100644 --- a/tests/ui/crashes/ice-5207.rs +++ b/tests/ui/crashes/ice-5207.rs @@ -1,5 +1,3 @@ -// edition:2018 - // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 pub async fn bar<'a, T: 'a>(_: T) {} diff --git a/tests/ui/crashes/ice-6252.rs b/tests/ui/crashes/ice-6252.rs index 2e3d9fd1e9240..0ccf0aae9d742 100644 --- a/tests/ui/crashes/ice-6252.rs +++ b/tests/ui/crashes/ice-6252.rs @@ -1,6 +1,5 @@ // originally from glacier fixed/77919.rs // encountered errors resolving bounds after type-checking - trait TypeVal { const VAL: T; } diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr index eaa5e6f51cb4a..926ae39cc218d 100644 --- a/tests/ui/crashes/ice-6252.stderr +++ b/tests/ui/crashes/ice-6252.stderr @@ -1,16 +1,20 @@ error[E0412]: cannot find type `PhantomData` in this scope - --> $DIR/ice-6252.rs:9:9 + --> $DIR/ice-6252.rs:8:9 | LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope | -help: consider importing this struct +help: consider importing one of these items + | +LL | use serde::__private::PhantomData; | LL | use std::marker::PhantomData; | +LL | use core::marker::PhantomData; + | error[E0412]: cannot find type `VAL` in this scope - --> $DIR/ice-6252.rs:11:63 + --> $DIR/ice-6252.rs:10:63 | LL | impl TypeVal for Multiply where N: TypeVal {} | - ^^^ not found in this scope @@ -18,7 +22,7 @@ LL | impl TypeVal for Multiply where N: TypeVal {} | help: you might be missing a type parameter: `, VAL` error[E0046]: not all trait items implemented, missing: `VAL` - --> $DIR/ice-6252.rs:11:1 + --> $DIR/ice-6252.rs:10:1 | LL | const VAL: T; | ------------- `VAL` from trait diff --git a/tests/ui/crashes/ice-7231.rs b/tests/ui/crashes/ice-7231.rs index 5595d8d1d6269..4ad0d351372f7 100644 --- a/tests/ui/crashes/ice-7231.rs +++ b/tests/ui/crashes/ice-7231.rs @@ -1,4 +1,3 @@ -// edition:2018 #![allow(clippy::never_loop)] async fn f() { diff --git a/tests/ui/crashes/used_underscore_binding_macro.rs b/tests/ui/crashes/used_underscore_binding_macro.rs index c57a45dc7aab9..901eb4e503988 100644 --- a/tests/ui/crashes/used_underscore_binding_macro.rs +++ b/tests/ui/crashes/used_underscore_binding_macro.rs @@ -1,5 +1,3 @@ -// edition:2018 - use serde::Deserialize; /// Tests that we do not lint for unused underscores in a `MacroAttribute` diff --git a/tests/ui/debug_assert_with_mut_call.rs b/tests/ui/debug_assert_with_mut_call.rs index 477a47118d411..c5de412556567 100644 --- a/tests/ui/debug_assert_with_mut_call.rs +++ b/tests/ui/debug_assert_with_mut_call.rs @@ -1,9 +1,9 @@ -// compile-flags: --edition=2018 #![feature(custom_inner_attributes)] #![rustfmt::skip] #![warn(clippy::debug_assert_with_mut_call)] #![allow(clippy::redundant_closure_call)] + struct S; impl S { diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index 4df241c9fc39b..e27f9fea708ee 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,6 +1,5 @@ #![warn(clippy::diverging_sub_expression)] #![allow(clippy::match_same_arms, clippy::logic_bug)] - #[allow(clippy::empty_loop)] fn diverge() -> ! { loop {} diff --git a/tests/ui/diverging_sub_expression.stderr b/tests/ui/diverging_sub_expression.stderr index 170e7d92de4ac..c712a6a7e38ea 100644 --- a/tests/ui/diverging_sub_expression.stderr +++ b/tests/ui/diverging_sub_expression.stderr @@ -1,5 +1,5 @@ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:20:10 + --> $DIR/diverging_sub_expression.rs:19:10 | LL | b || diverge(); | ^^^^^^^^^ @@ -7,34 +7,42 @@ LL | b || diverge(); = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:21:10 + --> $DIR/diverging_sub_expression.rs:20:10 | LL | b || A.foo(); | ^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:30:26 + --> $DIR/diverging_sub_expression.rs:29:26 | LL | 6 => true || return, | ^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:31:26 + --> $DIR/diverging_sub_expression.rs:30:26 | LL | 7 => true || continue, | ^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:34:26 + --> $DIR/diverging_sub_expression.rs:33:26 | LL | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:39:26 + --> $DIR/diverging_sub_expression.rs:36:30 + | +LL | _ => true || panic!("boo"), + | ^^^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: sub-expression diverges + --> $DIR/diverging_sub_expression.rs:38:26 | LL | _ => true || break, | ^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/doc_errors.rs b/tests/ui/doc_errors.rs index c77a74a58f22c..30fdd3b087371 100644 --- a/tests/ui/doc_errors.rs +++ b/tests/ui/doc_errors.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::missing_errors_doc)] #![allow(clippy::result_unit_err)] #![allow(clippy::unnecessary_wraps)] diff --git a/tests/ui/doc_errors.stderr b/tests/ui/doc_errors.stderr index b5a81419daee3..c7b616e289708 100644 --- a/tests/ui/doc_errors.stderr +++ b/tests/ui/doc_errors.stderr @@ -1,5 +1,5 @@ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:8:1 + --> $DIR/doc_errors.rs:7:1 | LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::missing-errors-doc` implied by `-D warnings` error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:12:1 + --> $DIR/doc_errors.rs:11:1 | LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -17,7 +17,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:17:1 + --> $DIR/doc_errors.rs:16:1 | LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -25,7 +25,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:22:1 + --> $DIR/doc_errors.rs:21:1 | LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -33,7 +33,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:52:5 + --> $DIR/doc_errors.rs:51:5 | LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -41,7 +41,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:57:5 + --> $DIR/doc_errors.rs:56:5 | LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -49,7 +49,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:86:5 + --> $DIR/doc_errors.rs:85:5 | LL | fn trait_method_missing_errors_header() -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/eval_order_dependence.rs b/tests/ui/eval_order_dependence.rs index 8e6a32b7be33d..aad78319d4820 100644 --- a/tests/ui/eval_order_dependence.rs +++ b/tests/ui/eval_order_dependence.rs @@ -1,5 +1,3 @@ -// edition:2018 - #[warn(clippy::eval_order_dependence)] #[allow( unused_assignments, diff --git a/tests/ui/eval_order_dependence.stderr b/tests/ui/eval_order_dependence.stderr index 4f611e308e186..7c6265a08790d 100644 --- a/tests/ui/eval_order_dependence.stderr +++ b/tests/ui/eval_order_dependence.stderr @@ -1,48 +1,48 @@ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:16:9 + --> $DIR/eval_order_dependence.rs:14:9 | LL | } + x; | ^ | = note: `-D clippy::eval-order-dependence` implied by `-D warnings` note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:14:9 + --> $DIR/eval_order_dependence.rs:12:9 | LL | x = 1; | ^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:19:5 + --> $DIR/eval_order_dependence.rs:17:5 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:20:9 + --> $DIR/eval_order_dependence.rs:18:9 | LL | x = 20; | ^^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:32:12 + --> $DIR/eval_order_dependence.rs:30:12 | LL | a: x, | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:34:13 + --> $DIR/eval_order_dependence.rs:32:13 | LL | x = 6; | ^^^^^ error: unsequenced read of `x` - --> $DIR/eval_order_dependence.rs:41:9 + --> $DIR/eval_order_dependence.rs:39:9 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> $DIR/eval_order_dependence.rs:42:13 + --> $DIR/eval_order_dependence.rs:40:13 | LL | x = 20; | ^^^^^^ diff --git a/tests/ui/fallible_impl_from.stderr b/tests/ui/fallible_impl_from.stderr index 5772ff055084f..4e0f08a1215c0 100644 --- a/tests/ui/fallible_impl_from.stderr +++ b/tests/ui/fallible_impl_from.stderr @@ -38,7 +38,7 @@ note: potential failure(s) | LL | panic!(); | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead --> $DIR/fallible_impl_from.rs:35:1 @@ -65,7 +65,7 @@ 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) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead --> $DIR/fallible_impl_from.rs:53:1 @@ -87,7 +87,7 @@ 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) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/future_not_send.rs b/tests/ui/future_not_send.rs index d3a920de4b6ad..858036692d68f 100644 --- a/tests/ui/future_not_send.rs +++ b/tests/ui/future_not_send.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::future_not_send)] use std::cell::Cell; diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr index c734051ccf320..3cc05e2fdbec6 100644 --- a/tests/ui/future_not_send.stderr +++ b/tests/ui/future_not_send.stderr @@ -1,12 +1,12 @@ error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:8:62 + --> $DIR/future_not_send.rs:7:62 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ future returned by `private_future` is not `Send` | = note: `-D clippy::future-not-send` implied by `-D warnings` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:9:5 + --> $DIR/future_not_send.rs:8:5 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` @@ -16,7 +16,7 @@ LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:9:5 + --> $DIR/future_not_send.rs:8:5 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ---- has type `&std::cell::Cell` which is not `Send` @@ -27,13 +27,13 @@ LL | } = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:12:42 + --> $DIR/future_not_send.rs:11:42 | LL | pub async fn public_future(rc: Rc<[u8]>) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:13:5 + --> $DIR/future_not_send.rs:12:5 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` @@ -44,45 +44,45 @@ LL | } = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:20:63 + --> $DIR/future_not_send.rs:19:63 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ future returned by `private_future2` is not `Send` | note: captured value is not `Send` - --> $DIR/future_not_send.rs:20:26 + --> $DIR/future_not_send.rs:19:26 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> $DIR/future_not_send.rs:20:40 + --> $DIR/future_not_send.rs:19:40 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:24:43 + --> $DIR/future_not_send.rs:23:43 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^ future returned by `public_future2` is not `Send` | note: captured value is not `Send` - --> $DIR/future_not_send.rs:24:29 + --> $DIR/future_not_send.rs:23:29 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:35:39 + --> $DIR/future_not_send.rs:34:39 | LL | async fn private_future(&self) -> usize { | ^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:36:9 + --> $DIR/future_not_send.rs:35:9 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` @@ -94,13 +94,13 @@ LL | } = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:40:39 + --> $DIR/future_not_send.rs:39:39 | LL | pub async fn public_future(&self) { | ^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:41:9 + --> $DIR/future_not_send.rs:40:9 | LL | pub async fn public_future(&self) { | ----- has type `&Dummy` which is not `Send` @@ -111,13 +111,13 @@ LL | } = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:50:37 + --> $DIR/future_not_send.rs:49:37 | LL | async fn generic_future(t: T) -> T | ^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:55:5 + --> $DIR/future_not_send.rs:54:5 | LL | let rt = &t; | -- has type `&T` which is not `Send` @@ -129,13 +129,13 @@ LL | } = note: `T` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> $DIR/future_not_send.rs:66:34 + --> $DIR/future_not_send.rs:65:34 | LL | async fn unclear_future(t: T) {} | ^ future returned by `unclear_future` is not `Send` | note: captured value is not `Send` - --> $DIR/future_not_send.rs:66:28 + --> $DIR/future_not_send.rs:65:28 | LL | async fn unclear_future(t: T) {} | ^ has type `T` which is not `Send` diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index aa69b0974101c..fd96ca3f466ea 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,4 +1,3 @@ -// edition:2018 // aux-build:implicit_hasher_macros.rs #![deny(clippy::implicit_hasher)] #![allow(unused)] diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr index 3f5f56b923fe2..59b0fba2a4cfe 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:17:35 + --> $DIR/implicit_hasher.rs:16:35 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/implicit_hasher.rs:3:9 + --> $DIR/implicit_hasher.rs:2: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:26:36 + --> $DIR/implicit_hasher.rs:25: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:31:19 + --> $DIR/implicit_hasher.rs:30: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:48:32 + --> $DIR/implicit_hasher.rs:47: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:53:19 + --> $DIR/implicit_hasher.rs:52: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:70:23 + --> $DIR/implicit_hasher.rs:69: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:70:53 + --> $DIR/implicit_hasher.rs:69: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:74:43 + --> $DIR/implicit_hasher.rs:73: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:82:33 + --> $DIR/implicit_hasher.rs:81: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:82:63 + --> $DIR/implicit_hasher.rs:81:63 | LL | pub fn $name(_map: &mut HashMap, _set: &mut HashSet) {} | ^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL | pub fn $name(_map: &mut HashMap $DIR/implicit_hasher.rs:101:35 + --> $DIR/implicit_hasher.rs:100:35 | LL | pub async fn election_vote(_data: HashMap) {} | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/implicit_return.fixed b/tests/ui/implicit_return.fixed index 7698b88a88c8a..a51f7bc6a29ff 100644 --- a/tests/ui/implicit_return.fixed +++ b/tests/ui/implicit_return.fixed @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::implicit_return)] diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs index 45bbc2ec670e0..03f8ec49d51e5 100644 --- a/tests/ui/implicit_return.rs +++ b/tests/ui/implicit_return.rs @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::implicit_return)] diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr index 5e078b15ce393..522bc3bf895a7 100644 --- a/tests/ui/implicit_return.stderr +++ b/tests/ui/implicit_return.stderr @@ -1,5 +1,5 @@ error: missing `return` statement - --> $DIR/implicit_return.rs:13:5 + --> $DIR/implicit_return.rs:12:5 | LL | true | ^^^^ help: add `return` as shown: `return true` @@ -7,85 +7,85 @@ LL | true = note: `-D clippy::implicit-return` implied by `-D warnings` error: missing `return` statement - --> $DIR/implicit_return.rs:17:15 + --> $DIR/implicit_return.rs:16:15 | LL | if true { true } else { false } | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:17:29 + --> $DIR/implicit_return.rs:16:29 | LL | if true { true } else { false } | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:23:17 + --> $DIR/implicit_return.rs:22:17 | LL | true => false, | ^^^^^ help: add `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:24:20 + --> $DIR/implicit_return.rs:23:20 | LL | false => { true }, | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:37:9 + --> $DIR/implicit_return.rs:36:9 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:44:13 + --> $DIR/implicit_return.rs:43:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:52:13 + --> $DIR/implicit_return.rs:51:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:70:18 + --> $DIR/implicit_return.rs:69:18 | LL | let _ = || { true }; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:71:16 + --> $DIR/implicit_return.rs:70:16 | LL | let _ = || true; | ^^^^ help: add `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:79:5 + --> $DIR/implicit_return.rs:78:5 | LL | format!("test {}", "test") | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")` error: missing `return` statement - --> $DIR/implicit_return.rs:88:5 + --> $DIR/implicit_return.rs:87:5 | LL | m!(true, false) | ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)` error: missing `return` statement - --> $DIR/implicit_return.rs:94:13 + --> $DIR/implicit_return.rs:93:13 | LL | break true; | ^^^^^^^^^^ help: change `break` to `return` as shown: `return true` error: missing `return` statement - --> $DIR/implicit_return.rs:99:17 + --> $DIR/implicit_return.rs:98:17 | LL | break 'outer false; | ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false` error: missing `return` statement - --> $DIR/implicit_return.rs:114:5 + --> $DIR/implicit_return.rs:113:5 | LL | / loop { LL | | m!(true); @@ -100,7 +100,7 @@ LL + } | error: missing `return` statement - --> $DIR/implicit_return.rs:128:5 + --> $DIR/implicit_return.rs:127:5 | LL | true | ^^^^ help: add `return` as shown: `return true` diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index d1025743790a9..eb66d1afddce3 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs index b095aa64a2174..5caadc7c62083 100644 --- a/tests/ui/inconsistent_struct_constructor.rs +++ b/tests/ui/inconsistent_struct_constructor.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unnecessary_operation)] diff --git a/tests/ui/inconsistent_struct_constructor.stderr b/tests/ui/inconsistent_struct_constructor.stderr index ef308dedb1661..c90189e964f09 100644 --- a/tests/ui/inconsistent_struct_constructor.stderr +++ b/tests/ui/inconsistent_struct_constructor.stderr @@ -1,5 +1,5 @@ error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:34:9 + --> $DIR/inconsistent_struct_constructor.rs:33:9 | LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` @@ -7,7 +7,7 @@ LL | Foo { y, x, z }; = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings` error: struct constructor field order is inconsistent with struct definition field order - --> $DIR/inconsistent_struct_constructor.rs:56:9 + --> $DIR/inconsistent_struct_constructor.rs:55:9 | LL | / Foo { LL | | z, diff --git a/tests/ui/issue-7447.stderr b/tests/ui/issue-7447.stderr new file mode 100644 index 0000000000000..463a48b24a321 --- /dev/null +++ b/tests/ui/issue-7447.stderr @@ -0,0 +1,19 @@ +error: sub-expression diverges + --> $DIR/issue-7447.rs:23:15 + | +LL | byte_view(panic!()); + | ^^^^^^^^ + | + = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: sub-expression diverges + --> $DIR/issue-7447.rs:24:19 + | +LL | group_entries(panic!()); + | ^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + diff --git a/tests/ui/issue_4266.rs b/tests/ui/issue_4266.rs index cc699b79e433c..d9d48189bd74e 100644 --- a/tests/ui/issue_4266.rs +++ b/tests/ui/issue_4266.rs @@ -1,4 +1,3 @@ -// edition:2018 #![allow(dead_code)] async fn sink1<'a>(_: &'a str) {} // lint diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr index 0426508e622f8..20419457b47f0 100644 --- a/tests/ui/issue_4266.stderr +++ b/tests/ui/issue_4266.stderr @@ -1,5 +1,5 @@ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/issue_4266.rs:4:1 + --> $DIR/issue_4266.rs:3:1 | LL | async fn sink1<'a>(_: &'a str) {} // lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | async fn sink1<'a>(_: &'a str) {} // lint = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/issue_4266.rs:8:1 + --> $DIR/issue_4266.rs:7:1 | LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs index b9d66347c2748..1e938e72b5777 100644 --- a/tests/ui/len_without_is_empty.rs +++ b/tests/ui/len_without_is_empty.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::len_without_is_empty)] #![allow(dead_code, unused)] diff --git a/tests/ui/len_without_is_empty.stderr b/tests/ui/len_without_is_empty.stderr index 3282709bcd671..a1f48f7610b44 100644 --- a/tests/ui/len_without_is_empty.stderr +++ b/tests/ui/len_without_is_empty.stderr @@ -1,5 +1,5 @@ error: struct `PubOne` has a public `len` method, but no `is_empty` method - --> $DIR/len_without_is_empty.rs:9:5 + --> $DIR/len_without_is_empty.rs:7:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pub fn len(&self) -> isize { = note: `-D clippy::len-without-is-empty` implied by `-D warnings` error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_without_is_empty.rs:57:1 + --> $DIR/len_without_is_empty.rs:55:1 | LL | / pub trait PubTraitsToo { LL | | fn len(&self) -> isize; @@ -15,45 +15,45 @@ LL | | } | |_^ error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method - --> $DIR/len_without_is_empty.rs:70:5 + --> $DIR/len_without_is_empty.rs:68:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:74:5 + --> $DIR/len_without_is_empty.rs:72:5 | LL | fn is_empty(&self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:82:5 + --> $DIR/len_without_is_empty.rs:80:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:86:5 + --> $DIR/len_without_is_empty.rs:84:5 | LL | pub fn is_empty(&self, x: u32) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:94:5 + --> $DIR/len_without_is_empty.rs:92:5 | LL | pub fn len(self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:98:5 + --> $DIR/len_without_is_empty.rs:96:5 | LL | pub fn is_empty(&self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(self) -> bool` error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method - --> $DIR/len_without_is_empty.rs:173:1 + --> $DIR/len_without_is_empty.rs:171:1 | LL | / pub trait DependsOnFoo: Foo { LL | | fn len(&mut self) -> usize; @@ -61,33 +61,33 @@ LL | | } | |_^ error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:218:5 + --> $DIR/len_without_is_empty.rs:216:5 | LL | pub fn len(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:223:5 + --> $DIR/len_without_is_empty.rs:221:5 | LL | pub fn is_empty(&self) -> Option { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature - --> $DIR/len_without_is_empty.rs:230:5 + --> $DIR/len_without_is_empty.rs:228:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> $DIR/len_without_is_empty.rs:235:5 + --> $DIR/len_without_is_empty.rs:233:5 | LL | pub fn is_empty(&self) -> Option { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` or `(&self) -> Result error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:230:5 + --> $DIR/len_without_is_empty.rs:228:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | pub fn len(&self) -> Result { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:242:5 + --> $DIR/len_without_is_empty.rs:240:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | pub fn len(&self) -> Result { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:246:5 + --> $DIR/len_without_is_empty.rs:244:5 | LL | pub fn is_empty(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | pub fn is_empty(&self) -> Result { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> $DIR/len_without_is_empty.rs:253:5 + --> $DIR/len_without_is_empty.rs:251:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index 70d49d9f2c4ae..9171558f3a2d7 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -1,4 +1,3 @@ -// compile-flags: --edition 2018 // aux-build:macro_rules.rs // aux-build:macro_use_helper.rs // aux-build:proc_macro_derive.rs diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index 6837002386114..cd01fd43f6d32 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -1,4 +1,3 @@ -// compile-flags: --edition 2018 // aux-build:macro_rules.rs // aux-build:macro_use_helper.rs // aux-build:proc_macro_derive.rs diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index 49314b7506d33..f8c86c8d9179f 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -1,5 +1,5 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:19:5 + --> $DIR/macro_use_imports.rs:18:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` @@ -7,22 +7,22 @@ LL | #[macro_use] = note: `-D clippy::macro-use-imports` implied by `-D warnings` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:25:5 + --> $DIR/macro_use_imports.rs:20:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:21:5 + --> $DIR/macro_use_imports.rs:22:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:23:5 + --> $DIR/macro_use_imports.rs:24:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` error: aborting due to 4 previous errors diff --git a/tests/ui/manual_assert.fixed b/tests/ui/manual_assert.fixed index 9d461cff68d88..8943bc80897e0 100644 --- a/tests/ui/manual_assert.fixed +++ b/tests/ui/manual_assert.fixed @@ -1,4 +1,6 @@ +// edition:2018 // run-rustfix +//FIXME: This does not correctly match in edition 2021, see #7843 #![warn(clippy::manual_assert)] fn main() { diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 6aadff887ca8d..4c474777e8dd6 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -1,4 +1,6 @@ +// edition:2018 // run-rustfix +//FIXME: This does not correctly match in edition 2021, see #7843 #![warn(clippy::manual_assert)] fn main() { diff --git a/tests/ui/manual_assert.stderr b/tests/ui/manual_assert.stderr index ab2786247b1de..a8e907d25db3b 100644 --- a/tests/ui/manual_assert.stderr +++ b/tests/ui/manual_assert.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:19:5 + --> $DIR/manual_assert.rs:21:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-assert` implied by `-D warnings` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:22:5 + --> $DIR/manual_assert.rs:24:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:39:5 + --> $DIR/manual_assert.rs:41:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:42:5 + --> $DIR/manual_assert.rs:44:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -33,7 +33,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:45:5 + --> $DIR/manual_assert.rs:47:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -41,7 +41,7 @@ LL | | } | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:48:5 + --> $DIR/manual_assert.rs:50:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -49,7 +49,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:51:5 + --> $DIR/manual_assert.rs:53:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index 5184f6fdb88b3..136cc96be70ca 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index 68c0e591f0b6e..ddc453ffdb750 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index 51f1a52b6dd65..7435f46074c81 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -1,5 +1,5 @@ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:8:1 + --> $DIR/manual_async_fn.rs:7:1 | LL | fn fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | fn fut() -> impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:13:1 + --> $DIR/manual_async_fn.rs:12:1 | LL | fn fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | fn fut2() ->impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:18:1 + --> $DIR/manual_async_fn.rs:17:1 | LL | fn fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | fn fut3()-> impl Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:22:1 + --> $DIR/manual_async_fn.rs:21:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | fn empty_fut() -> impl Future {} | ~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:27:1 + --> $DIR/manual_async_fn.rs:26:1 | LL | fn empty_fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | fn empty_fut2() ->impl Future {} | ~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:32:1 + --> $DIR/manual_async_fn.rs:31:1 | LL | fn empty_fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | fn empty_fut3()-> impl Future {} | ~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:36:1 + --> $DIR/manual_async_fn.rs:35:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | fn core_fut() -> impl core::future::Future { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:58:5 + --> $DIR/manual_async_fn.rs:57:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL + let c = 21; ... error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:93:1 + --> $DIR/manual_async_fn.rs:92:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future + '_ { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:102:1 + --> $DIR/manual_async_fn.rs:101:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/manual_map_option.fixed b/tests/ui/manual_map_option.fixed index 40d01df6379a6..294d79abc0459 100644 --- a/tests/ui/manual_map_option.fixed +++ b/tests/ui/manual_map_option.fixed @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::manual_map)] diff --git a/tests/ui/manual_map_option.rs b/tests/ui/manual_map_option.rs index cfef0c5cc4ec6..d11bf5ecb825a 100644 --- a/tests/ui/manual_map_option.rs +++ b/tests/ui/manual_map_option.rs @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::manual_map)] diff --git a/tests/ui/manual_map_option.stderr b/tests/ui/manual_map_option.stderr index cdc2c0e62a9b9..0036b8151ded0 100644 --- a/tests/ui/manual_map_option.stderr +++ b/tests/ui/manual_map_option.stderr @@ -1,5 +1,5 @@ error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:15:5 + --> $DIR/manual_map_option.rs:14:5 | LL | / match Some(0) { LL | | Some(_) => Some(2), @@ -10,7 +10,7 @@ LL | | }; = note: `-D clippy::manual-map` implied by `-D warnings` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:20:5 + --> $DIR/manual_map_option.rs:19:5 | LL | / match Some(0) { LL | | Some(x) => Some(x + 1), @@ -19,7 +19,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| x + 1)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:25:5 + --> $DIR/manual_map_option.rs:24:5 | LL | / match Some("") { LL | | Some(x) => Some(x.is_empty()), @@ -28,7 +28,7 @@ LL | | }; | |_____^ help: try this: `Some("").map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:30:5 + --> $DIR/manual_map_option.rs:29:5 | LL | / if let Some(x) = Some(0) { LL | | Some(!x) @@ -38,7 +38,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| !x)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:37:5 + --> $DIR/manual_map_option.rs:36:5 | LL | / match Some(0) { LL | | Some(x) => { Some(std::convert::identity(x)) } @@ -47,7 +47,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(std::convert::identity)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:42:5 + --> $DIR/manual_map_option.rs:41:5 | LL | / match Some(&String::new()) { LL | | Some(x) => Some(str::len(x)), @@ -56,7 +56,7 @@ LL | | }; | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:52:5 + --> $DIR/manual_map_option.rs:51:5 | LL | / match &Some([0, 1]) { LL | | Some(x) => Some(x[0]), @@ -65,7 +65,7 @@ LL | | }; | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:57:5 + --> $DIR/manual_map_option.rs:56:5 | LL | / match &Some(0) { LL | | &Some(x) => Some(x * 2), @@ -74,7 +74,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| x * 2)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:62:5 + --> $DIR/manual_map_option.rs:61:5 | LL | / match Some(String::new()) { LL | | Some(ref x) => Some(x.is_empty()), @@ -83,7 +83,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:67:5 + --> $DIR/manual_map_option.rs:66:5 | LL | / match &&Some(String::new()) { LL | | Some(x) => Some(x.len()), @@ -92,7 +92,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:72:5 + --> $DIR/manual_map_option.rs:71:5 | LL | / match &&Some(0) { LL | | &&Some(x) => Some(x + x), @@ -101,7 +101,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| x + x)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:85:9 + --> $DIR/manual_map_option.rs:84:9 | LL | / match &mut Some(String::new()) { LL | | Some(x) => Some(x.push_str("")), @@ -110,7 +110,7 @@ LL | | }; | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:91:5 + --> $DIR/manual_map_option.rs:90:5 | LL | / match &mut Some(String::new()) { LL | | Some(ref x) => Some(x.len()), @@ -119,7 +119,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:96:5 + --> $DIR/manual_map_option.rs:95:5 | LL | / match &mut &Some(String::new()) { LL | | Some(x) => Some(x.is_empty()), @@ -128,7 +128,7 @@ LL | | }; | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:101:5 + --> $DIR/manual_map_option.rs:100:5 | LL | / match Some((0, 1, 2)) { LL | | Some((x, y, z)) => Some(x + y + z), @@ -137,7 +137,7 @@ LL | | }; | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:106:5 + --> $DIR/manual_map_option.rs:105:5 | LL | / match Some([1, 2, 3]) { LL | | Some([first, ..]) => Some(first), @@ -146,7 +146,7 @@ LL | | }; | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:111:5 + --> $DIR/manual_map_option.rs:110:5 | LL | / match &Some((String::new(), "test")) { LL | | Some((x, y)) => Some((y, x)), @@ -155,7 +155,7 @@ LL | | }; | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:169:5 + --> $DIR/manual_map_option.rs:168:5 | LL | / match Some(0) { LL | | Some(x) => Some(vec![x]), @@ -164,7 +164,7 @@ LL | | }; | |_____^ help: try this: `Some(0).map(|x| vec![x])` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:174:5 + --> $DIR/manual_map_option.rs:173:5 | LL | / match option_env!("") { LL | | Some(x) => Some(String::from(x)), @@ -173,7 +173,7 @@ LL | | }; | |_____^ help: try this: `option_env!("").map(String::from)` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:194:12 + --> $DIR/manual_map_option.rs:193:12 | LL | } else if let Some(x) = Some(0) { | ____________^ @@ -184,7 +184,7 @@ LL | | }; | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }` error: manual implementation of `Option::map` - --> $DIR/manual_map_option.rs:202:12 + --> $DIR/manual_map_option.rs:201:12 | LL | } else if let Some(x) = Some(0) { | ____________^ diff --git a/tests/ui/match_wild_err_arm.rs b/tests/ui/match_wild_err_arm.rs index 823be65efe065..010cb7e03015e 100644 --- a/tests/ui/match_wild_err_arm.rs +++ b/tests/ui/match_wild_err_arm.rs @@ -1,10 +1,12 @@ +//edition:2015 +//FIXME: The lint only triggers once on edition 2021, so I'm leaving this at 2015 for now. + #![feature(exclusive_range_pattern)] #![allow(clippy::match_same_arms)] #![warn(clippy::match_wild_err_arm)] fn match_wild_err_arm() { let x: Result = Ok(3); - match x { Ok(3) => println!("ok"), Ok(_) => println!("ok"), diff --git a/tests/ui/match_wild_err_arm.stderr b/tests/ui/match_wild_err_arm.stderr index 6a2a02987dea7..d5ec722d5691b 100644 --- a/tests/ui/match_wild_err_arm.stderr +++ b/tests/ui/match_wild_err_arm.stderr @@ -1,5 +1,5 @@ error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:11:9 + --> $DIR/match_wild_err_arm.rs:13:9 | LL | Err(_) => panic!("err"), | ^^^^^^ @@ -8,7 +8,7 @@ LL | Err(_) => panic!("err"), = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:17:9 + --> $DIR/match_wild_err_arm.rs:19:9 | LL | Err(_) => panic!(), | ^^^^^^ @@ -16,7 +16,7 @@ LL | Err(_) => panic!(), = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:23:9 + --> $DIR/match_wild_err_arm.rs:25:9 | LL | Err(_) => { | ^^^^^^ @@ -24,7 +24,7 @@ LL | Err(_) => { = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_e)` matches all errors - --> $DIR/match_wild_err_arm.rs:31:9 + --> $DIR/match_wild_err_arm.rs:33:9 | LL | Err(_e) => panic!(), | ^^^^^^^ diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index c441b35b99203..977ce54327b3d 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,5 +1,4 @@ // aux-build:option_helpers.rs -// edition:2018 #![warn(clippy::all, clippy::pedantic)] #![allow( diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 4643e09e27028..b63672dd6fdbb 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:105:5 + --> $DIR/methods.rs:104:5 | LL | / fn new() -> i32 { LL | | 0 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods.rs:126:13 + --> $DIR/methods.rs:125:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing-doc.rs index a9bf7140a1e59..148531c285d3d 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing-doc.rs @@ -3,7 +3,6 @@ // injected intrinsics by the compiler. #![allow(dead_code)] #![feature(global_asm)] - //! Some garbage docs for the crate here #![doc = "More garbage"] @@ -90,10 +89,10 @@ mod internal_impl { } /// dox pub mod public_interface { - pub use internal_impl::documented as foo; - pub use internal_impl::globbed::*; - pub use internal_impl::undocumented1 as bar; - pub use internal_impl::{documented, undocumented2}; + pub use crate::internal_impl::documented as foo; + pub use crate::internal_impl::globbed::*; + pub use crate::internal_impl::undocumented1 as bar; + pub use crate::internal_impl::{documented, undocumented2}; } fn main() {} diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing-doc.stderr index a876dc078ebff..7a3a448c9d6c2 100644 --- a/tests/ui/missing-doc.stderr +++ b/tests/ui/missing-doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a type alias - --> $DIR/missing-doc.rs:10:1 + --> $DIR/missing-doc.rs:9:1 | LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | type Typedef = String; = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a type alias - --> $DIR/missing-doc.rs:11:1 + --> $DIR/missing-doc.rs:10:1 | LL | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:13:1 + --> $DIR/missing-doc.rs:12:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:14:1 + --> $DIR/missing-doc.rs:13:1 | LL | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:18:1 + --> $DIR/missing-doc.rs:17:1 | LL | pub fn foo2() {} | ^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:19:1 + --> $DIR/missing-doc.rs:18:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:33:1 + --> $DIR/missing-doc.rs:32:1 | LL | / enum Baz { LL | | BazA { a: isize, b: isize }, @@ -46,31 +46,31 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:34:5 + --> $DIR/missing-doc.rs:33:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:12 + --> $DIR/missing-doc.rs:33:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:22 + --> $DIR/missing-doc.rs:33:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:35:5 + --> $DIR/missing-doc.rs:34:5 | LL | BarB, | ^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:38:1 + --> $DIR/missing-doc.rs:37:1 | LL | / pub enum PubBaz { LL | | PubBazA { a: isize }, @@ -78,43 +78,43 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:39:5 + --> $DIR/missing-doc.rs:38:5 | LL | PubBazA { a: isize }, | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:39:15 + --> $DIR/missing-doc.rs:38:15 | LL | PubBazA { a: isize }, | ^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:59:1 + --> $DIR/missing-doc.rs:58:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:66:1 + --> $DIR/missing-doc.rs:65:1 | LL | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:68:1 + --> $DIR/missing-doc.rs:67:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:75:1 + --> $DIR/missing-doc.rs:74:1 | LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:77:1 + --> $DIR/missing-doc.rs:76:1 | LL | / mod internal_impl { LL | | /// dox @@ -126,31 +126,31 @@ LL | | } | |_^ error: missing documentation for a function - --> $DIR/missing-doc.rs:80:5 + --> $DIR/missing-doc.rs:79:5 | LL | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:81:5 + --> $DIR/missing-doc.rs:80:5 | LL | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:82:5 + --> $DIR/missing-doc.rs:81:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:87:9 + --> $DIR/missing-doc.rs:86:9 | LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:88:9 + --> $DIR/missing-doc.rs:87:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing_panics_doc.rs b/tests/ui/missing_panics_doc.rs index 2e1379a58a67b..7dc44529206d5 100644 --- a/tests/ui/missing_panics_doc.rs +++ b/tests/ui/missing_panics_doc.rs @@ -1,6 +1,5 @@ #![warn(clippy::missing_panics_doc)] #![allow(clippy::option_map_unit_fn)] - fn main() {} /// This needs to be documented diff --git a/tests/ui/missing_panics_doc.stderr b/tests/ui/missing_panics_doc.stderr index b863063b626db..60282939ef033 100644 --- a/tests/ui/missing_panics_doc.stderr +++ b/tests/ui/missing_panics_doc.stderr @@ -1,5 +1,5 @@ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:7:1 + --> $DIR/missing_panics_doc.rs:6:1 | LL | / pub fn unwrap() { LL | | let result = Err("Hi"); @@ -9,13 +9,13 @@ LL | | } | = note: `-D clippy::missing-panics-doc` implied by `-D warnings` note: first possible panic found here - --> $DIR/missing_panics_doc.rs:9:5 + --> $DIR/missing_panics_doc.rs:8:5 | LL | result.unwrap() | ^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:13:1 + --> $DIR/missing_panics_doc.rs:12:1 | LL | / pub fn panic() { LL | | panic!("This function panics") @@ -23,14 +23,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:14:5 + --> $DIR/missing_panics_doc.rs:13:5 | LL | panic!("This function panics") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:18:1 + --> $DIR/missing_panics_doc.rs:17:1 | LL | / pub fn todo() { LL | | todo!() @@ -38,14 +38,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:19:5 + --> $DIR/missing_panics_doc.rs:18:5 | LL | todo!() | ^^^^^^^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:23:1 + --> $DIR/missing_panics_doc.rs:22:1 | LL | / pub fn inner_body(opt: Option) { LL | | opt.map(|x| { @@ -57,14 +57,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:26:13 + --> $DIR/missing_panics_doc.rs:25: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) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:32:1 + --> $DIR/missing_panics_doc.rs:31:1 | LL | / pub fn unreachable_and_panic() { LL | | if true { unreachable!() } else { panic!() } @@ -72,14 +72,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:33:39 + --> $DIR/missing_panics_doc.rs:32:39 | LL | if true { unreachable!() } else { panic!() } | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:37:1 + --> $DIR/missing_panics_doc.rs:36:1 | LL | / pub fn assert_eq() { LL | | let x = 0; @@ -88,14 +88,14 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:39:5 + --> $DIR/missing_panics_doc.rs:38: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 - --> $DIR/missing_panics_doc.rs:43:1 + --> $DIR/missing_panics_doc.rs:42:1 | LL | / pub fn assert_ne() { LL | | let x = 0; @@ -104,7 +104,7 @@ LL | | } | |_^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:45:5 + --> $DIR/missing_panics_doc.rs:44:5 | LL | assert_ne!(x, 0); | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/needless_borrow_pat.rs b/tests/ui/needless_borrow_pat.rs index 7a8137778b446..04b6283da3c3b 100644 --- a/tests/ui/needless_borrow_pat.rs +++ b/tests/ui/needless_borrow_pat.rs @@ -1,4 +1,3 @@ -// edition:2018 // FIXME: run-rustfix waiting on multi-span suggestions #![warn(clippy::needless_borrow)] diff --git a/tests/ui/needless_borrow_pat.stderr b/tests/ui/needless_borrow_pat.stderr index 365ecd68d8ff2..db3b52b8850e1 100644 --- a/tests/ui/needless_borrow_pat.stderr +++ b/tests/ui/needless_borrow_pat.stderr @@ -1,5 +1,5 @@ error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:60:14 + --> $DIR/needless_borrow_pat.rs:59:14 | LL | Some(ref x) => x, | ^^^^^ help: try this: `x` @@ -7,7 +7,7 @@ LL | Some(ref x) => x, = note: `-D clippy::needless-borrow` implied by `-D warnings` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:66:14 + --> $DIR/needless_borrow_pat.rs:65:14 | LL | Some(ref x) => *x, | ^^^^^ @@ -18,7 +18,7 @@ LL | Some(x) => x, | ~ ~ error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:72:14 + --> $DIR/needless_borrow_pat.rs:71:14 | LL | Some(ref x) => { | ^^^^^ @@ -31,19 +31,19 @@ LL ~ f1(x); | error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:82:14 + --> $DIR/needless_borrow_pat.rs:81:14 | LL | Some(ref x) => m1!(x), | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:87:15 + --> $DIR/needless_borrow_pat.rs:86:15 | LL | let _ = |&ref x: &&String| { | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:92:10 + --> $DIR/needless_borrow_pat.rs:91:10 | LL | let (ref y,) = (&x,); | ^^^^^ @@ -55,13 +55,13 @@ LL ~ let _: &String = y; | error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:102:14 + --> $DIR/needless_borrow_pat.rs:101:14 | LL | Some(ref x) => x.0, | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:112:14 + --> $DIR/needless_borrow_pat.rs:111:14 | LL | E::A(ref x) | E::B(ref x) => *x, | ^^^^^ ^^^^^ @@ -72,13 +72,13 @@ LL | E::A(x) | E::B(x) => x, | ~ ~ ~ error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:118:21 + --> $DIR/needless_borrow_pat.rs:117:21 | LL | if let Some(ref x) = Some(&String::new()); | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:126:12 + --> $DIR/needless_borrow_pat.rs:125:12 | LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ @@ -91,13 +91,13 @@ LL ~ x | error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:133:11 + --> $DIR/needless_borrow_pat.rs:132:11 | LL | fn f(&ref x: &&String) { | ^^^^^ help: try this: `x` error: this pattern creates a reference to a reference - --> $DIR/needless_borrow_pat.rs:141:11 + --> $DIR/needless_borrow_pat.rs:140:11 | LL | fn f(&ref x: &&String) { | ^^^^^ diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed index 9c999e12b4cbc..812ce7163cd50 100644 --- a/tests/ui/needless_return.fixed +++ b/tests/ui/needless_return.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(let_else)] #![allow(unused)] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index da7dcf4f0a9ea..c42567b517c91 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![feature(let_else)] #![allow(unused)] diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 2e802cff1e686..74dda971fdabb 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:25:5 + --> $DIR/needless_return.rs:24: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:29:5 + --> $DIR/needless_return.rs:28:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:34:9 + --> $DIR/needless_return.rs:33:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:36:9 + --> $DIR/needless_return.rs:35:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:42:17 + --> $DIR/needless_return.rs:41:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:44:13 + --> $DIR/needless_return.rs:43:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:51:9 + --> $DIR/needless_return.rs:50:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:53:16 + --> $DIR/needless_return.rs:52:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:61:5 + --> $DIR/needless_return.rs:60:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:66:9 + --> $DIR/needless_return.rs:65:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:68:9 + --> $DIR/needless_return.rs:67:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:75:14 + --> $DIR/needless_return.rs:74:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:90:9 + --> $DIR/needless_return.rs:89:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:92:9 + --> $DIR/needless_return.rs:91:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` error: unneeded `return` statement - --> $DIR/needless_return.rs:113:32 + --> $DIR/needless_return.rs:112:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:118:13 + --> $DIR/needless_return.rs:117:13 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:120:20 + --> $DIR/needless_return.rs:119:20 | LL | let _ = || return; | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:126:32 + --> $DIR/needless_return.rs:125:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ help: remove `return`: `Foo` error: unneeded `return` statement - --> $DIR/needless_return.rs:135:5 + --> $DIR/needless_return.rs:134:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:139:5 + --> $DIR/needless_return.rs:138:5 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:144:9 + --> $DIR/needless_return.rs:143:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:146:9 + --> $DIR/needless_return.rs:145:9 | LL | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:152:17 + --> $DIR/needless_return.rs:151:17 | LL | true => return false, | ^^^^^^^^^^^^ help: remove `return`: `false` error: unneeded `return` statement - --> $DIR/needless_return.rs:154:13 + --> $DIR/needless_return.rs:153:13 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:161:9 + --> $DIR/needless_return.rs:160:9 | LL | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:163:16 + --> $DIR/needless_return.rs:162:16 | LL | let _ = || return true; | ^^^^^^^^^^^ help: remove `return`: `true` error: unneeded `return` statement - --> $DIR/needless_return.rs:171:5 + --> $DIR/needless_return.rs:170:5 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:176:9 + --> $DIR/needless_return.rs:175:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:178:9 + --> $DIR/needless_return.rs:177:9 | LL | return; | ^^^^^^^ help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:185:14 + --> $DIR/needless_return.rs:184:14 | LL | _ => return, | ^^^^^^ help: replace `return` with an empty block: `{}` error: unneeded `return` statement - --> $DIR/needless_return.rs:200:9 + --> $DIR/needless_return.rs:199:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")` error: unneeded `return` statement - --> $DIR/needless_return.rs:202:9 + --> $DIR/needless_return.rs:201:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()` diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index 58415b4aede26..961f6f409ddd2 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -15,8 +15,8 @@ struct InstSplit { impl MaybeInst { fn fill(&mut self) { let filled = match *self { - MaybeInst::Split1(goto1) => panic!(1), - MaybeInst::Split2(goto2) => panic!(2), + MaybeInst::Split1(goto1) => panic!("1"), + MaybeInst::Split2(goto2) => panic!("2"), _ => unimplemented!(), }; unimplemented!() diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 4077f1920a383..9cb6a9d1ecc9b 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)] diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 2f414e129d5a7..b3ba5eb870a69 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,4 +1,3 @@ -// edition:2018 // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)] diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 803d941c36df8..685bb48ea37bc 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:7:5 + --> $DIR/option_if_let_else.rs:6: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:25:13 + --> $DIR/option_if_let_else.rs:24: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:26:13 + --> $DIR/option_if_let_else.rs:25: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:27:13 + --> $DIR/option_if_let_else.rs:26: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:33:13 + --> $DIR/option_if_let_else.rs:32: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:34:13 + --> $DIR/option_if_let_else.rs:33: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:40:13 + --> $DIR/option_if_let_else.rs:39: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:49:5 + --> $DIR/option_if_let_else.rs:48: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:62:13 + --> $DIR/option_if_let_else.rs:61: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:71:13 + --> $DIR/option_if_let_else.rs:70: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:100:13 + --> $DIR/option_if_let_else.rs:99: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:109:13 + --> $DIR/option_if_let_else.rs:108: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:137:13 + --> $DIR/option_if_let_else.rs:136: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:141:13 + --> $DIR/option_if_let_else.rs:140:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs index 3d3c19a1be519..e75eb1b6eadd8 100644 --- a/tests/ui/panic_in_result_fn.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -1,6 +1,5 @@ #![warn(clippy::panic_in_result_fn)] #![allow(clippy::unnecessary_wraps)] - struct A; impl A { diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index f56c2d03c664f..78d09b8b2108a 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -1,5 +1,5 @@ error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:7:5 + --> $DIR/panic_in_result_fn.rs:6:5 | LL | / fn result_with_panic() -> Result // should emit lint LL | | { @@ -10,14 +10,14 @@ LL | | } = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:9:9 + --> $DIR/panic_in_result_fn.rs:8: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) + = note: this error originates in the macro `$crate::panic::panic_2021` (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` - --> $DIR/panic_in_result_fn.rs:12:5 + --> $DIR/panic_in_result_fn.rs:11:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint LL | | { @@ -27,14 +27,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:14:9 + --> $DIR/panic_in_result_fn.rs:13: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` - --> $DIR/panic_in_result_fn.rs:17:5 + --> $DIR/panic_in_result_fn.rs:16:5 | LL | / fn result_with_unreachable() -> Result // should emit lint LL | | { @@ -44,14 +44,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:19:9 + --> $DIR/panic_in_result_fn.rs:18: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` - --> $DIR/panic_in_result_fn.rs:22:5 + --> $DIR/panic_in_result_fn.rs:21:5 | LL | / fn result_with_todo() -> Result // should emit lint LL | | { @@ -61,14 +61,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:24:9 + --> $DIR/panic_in_result_fn.rs:23: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` - --> $DIR/panic_in_result_fn.rs:53:1 + --> $DIR/panic_in_result_fn.rs:52:1 | LL | / fn function_result_with_panic() -> Result // should emit lint LL | | { @@ -78,14 +78,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:55:5 + --> $DIR/panic_in_result_fn.rs:54: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) + = note: this error originates in the macro `$crate::panic::panic_2021` (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` - --> $DIR/panic_in_result_fn.rs:68:1 + --> $DIR/panic_in_result_fn.rs:67:1 | LL | / fn main() -> Result<(), String> { LL | | todo!("finish main method"); @@ -95,7 +95,7 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:69:5 + --> $DIR/panic_in_result_fn.rs:68:5 | LL | todo!("finish main method"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index 2d711082746e7..16b40dcd90286 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -196,7 +196,7 @@ fn clone_then_move_cloned() { fn foo(_: &Alpha, _: F) {} let x = Alpha; // ok, data is moved while the clone is in use. - foo(&x.clone(), move || { + foo(&x, move || { let _ = x; }); diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index fbc90493ae94b..9f59017b26199 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -167,5 +167,17 @@ note: cloned value is neither consumed nor mutated LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ -error: aborting due to 14 previous errors +error: redundant clone + --> $DIR/redundant_clone.rs:199:11 + | +LL | foo(&x.clone(), move || { + | ^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/redundant_clone.rs:199:10 + | +LL | foo(&x.clone(), move || { + | ^ + +error: aborting due to 15 previous errors diff --git a/tests/ui/ref_binding_to_reference.rs b/tests/ui/ref_binding_to_reference.rs index cd6db8ddc8864..fe742a4c2f4c5 100644 --- a/tests/ui/ref_binding_to_reference.rs +++ b/tests/ui/ref_binding_to_reference.rs @@ -1,4 +1,3 @@ -// edition:2018 // FIXME: run-rustfix waiting on multi-span suggestions #![warn(clippy::ref_binding_to_reference)] diff --git a/tests/ui/ref_binding_to_reference.stderr b/tests/ui/ref_binding_to_reference.stderr index eb36cd516a246..c5856e15fa987 100644 --- a/tests/ui/ref_binding_to_reference.stderr +++ b/tests/ui/ref_binding_to_reference.stderr @@ -1,5 +1,5 @@ error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:31:14 + --> $DIR/ref_binding_to_reference.rs:30:14 | LL | Some(ref x) => x, | ^^^^^ @@ -11,7 +11,7 @@ LL | Some(x) => &x, | ~ ~~ error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:37:14 + --> $DIR/ref_binding_to_reference.rs:36:14 | LL | Some(ref x) => { | ^^^^^ @@ -25,7 +25,7 @@ LL ~ &x | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:47:14 + --> $DIR/ref_binding_to_reference.rs:46:14 | LL | Some(ref x) => m2!(x), | ^^^^^ @@ -36,7 +36,7 @@ LL | Some(x) => m2!(&x), | ~ ~~ error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:52:15 + --> $DIR/ref_binding_to_reference.rs:51:15 | LL | let _ = |&ref x: &&String| { | ^^^^^ @@ -48,7 +48,7 @@ LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:58:12 + --> $DIR/ref_binding_to_reference.rs:57:12 | LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ @@ -61,7 +61,7 @@ LL ~ x | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:65:11 + --> $DIR/ref_binding_to_reference.rs:64:11 | LL | fn f(&ref x: &&String) { | ^^^^^ @@ -73,7 +73,7 @@ LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> $DIR/ref_binding_to_reference.rs:73:11 + --> $DIR/ref_binding_to_reference.rs:72:11 | LL | fn f(&ref x: &&String) { | ^^^^^ diff --git a/tests/ui/should_impl_trait/corner_cases.rs b/tests/ui/should_impl_trait/corner_cases.rs index a7f8f54f2be04..d7e8d02bd1998 100644 --- a/tests/ui/should_impl_trait/corner_cases.rs +++ b/tests/ui/should_impl_trait/corner_cases.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, diff --git a/tests/ui/should_impl_trait/method_list_1.rs b/tests/ui/should_impl_trait/method_list_1.rs index 69a3390b03b0b..ea962f943173a 100644 --- a/tests/ui/should_impl_trait/method_list_1.rs +++ b/tests/ui/should_impl_trait/method_list_1.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, diff --git a/tests/ui/should_impl_trait/method_list_1.stderr b/tests/ui/should_impl_trait/method_list_1.stderr index 86c63946516ce..bf8b47d5626d2 100644 --- a/tests/ui/should_impl_trait/method_list_1.stderr +++ b/tests/ui/should_impl_trait/method_list_1.stderr @@ -1,5 +1,5 @@ error: method `add` can be confused for the standard trait method `std::ops::Add::add` - --> $DIR/method_list_1.rs:26:5 + --> $DIR/method_list_1.rs:24:5 | LL | / pub fn add(self, other: T) -> T { LL | | unimplemented!() @@ -10,7 +10,7 @@ LL | | } = help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` - --> $DIR/method_list_1.rs:30:5 + --> $DIR/method_list_1.rs:28:5 | LL | / pub fn as_mut(&mut self) -> &mut T { LL | | unimplemented!() @@ -20,7 +20,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref` - --> $DIR/method_list_1.rs:34:5 + --> $DIR/method_list_1.rs:32:5 | LL | / pub fn as_ref(&self) -> &T { LL | | unimplemented!() @@ -30,7 +30,7 @@ LL | | } = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand` - --> $DIR/method_list_1.rs:38:5 + --> $DIR/method_list_1.rs:36:5 | LL | / pub fn bitand(self, rhs: T) -> T { LL | | unimplemented!() @@ -40,7 +40,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor` - --> $DIR/method_list_1.rs:42:5 + --> $DIR/method_list_1.rs:40:5 | LL | / pub fn bitor(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -50,7 +50,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor` - --> $DIR/method_list_1.rs:46:5 + --> $DIR/method_list_1.rs:44:5 | LL | / pub fn bitxor(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -60,7 +60,7 @@ LL | | } = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow` - --> $DIR/method_list_1.rs:50:5 + --> $DIR/method_list_1.rs:48:5 | LL | / pub fn borrow(&self) -> &str { LL | | unimplemented!() @@ -70,7 +70,7 @@ LL | | } = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut` - --> $DIR/method_list_1.rs:54:5 + --> $DIR/method_list_1.rs:52:5 | LL | / pub fn borrow_mut(&mut self) -> &mut str { LL | | unimplemented!() @@ -80,7 +80,7 @@ LL | | } = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone` - --> $DIR/method_list_1.rs:58:5 + --> $DIR/method_list_1.rs:56:5 | LL | / pub fn clone(&self) -> Self { LL | | unimplemented!() @@ -90,7 +90,7 @@ LL | | } = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp` - --> $DIR/method_list_1.rs:62:5 + --> $DIR/method_list_1.rs:60:5 | LL | / pub fn cmp(&self, other: &Self) -> Self { LL | | unimplemented!() @@ -100,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` - --> $DIR/method_list_1.rs:70:5 + --> $DIR/method_list_1.rs:68:5 | LL | / pub fn deref(&self) -> &Self { LL | | unimplemented!() @@ -110,7 +110,7 @@ LL | | } = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut` - --> $DIR/method_list_1.rs:74:5 + --> $DIR/method_list_1.rs:72:5 | LL | / pub fn deref_mut(&mut self) -> &mut Self { LL | | unimplemented!() @@ -120,7 +120,7 @@ LL | | } = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name error: method `div` can be confused for the standard trait method `std::ops::Div::div` - --> $DIR/method_list_1.rs:78:5 + --> $DIR/method_list_1.rs:76:5 | LL | / pub fn div(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -130,7 +130,7 @@ LL | | } = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop` - --> $DIR/method_list_1.rs:82:5 + --> $DIR/method_list_1.rs:80:5 | LL | / pub fn drop(&mut self) { LL | | unimplemented!() diff --git a/tests/ui/should_impl_trait/method_list_2.rs b/tests/ui/should_impl_trait/method_list_2.rs index 2cdc1a06fe689..b663568806d21 100644 --- a/tests/ui/should_impl_trait/method_list_2.rs +++ b/tests/ui/should_impl_trait/method_list_2.rs @@ -1,5 +1,3 @@ -// edition:2018 - #![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index 0142e2991081c..426fe3b1adc9d 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -1,5 +1,5 @@ error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq` - --> $DIR/method_list_2.rs:27:5 + --> $DIR/method_list_2.rs:25:5 | LL | / pub fn eq(&self, other: &Self) -> bool { LL | | unimplemented!() @@ -10,7 +10,7 @@ LL | | } = help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` - --> $DIR/method_list_2.rs:31:5 + --> $DIR/method_list_2.rs:29:5 | LL | / pub fn from_iter(iter: T) -> Self { LL | | unimplemented!() @@ -20,7 +20,7 @@ LL | | } = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str` - --> $DIR/method_list_2.rs:35:5 + --> $DIR/method_list_2.rs:33:5 | LL | / pub fn from_str(s: &str) -> Result { LL | | unimplemented!() @@ -30,7 +30,7 @@ LL | | } = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash` - --> $DIR/method_list_2.rs:39:5 + --> $DIR/method_list_2.rs:37:5 | LL | / pub fn hash(&self, state: &mut T) { LL | | unimplemented!() @@ -40,7 +40,7 @@ LL | | } = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name error: method `index` can be confused for the standard trait method `std::ops::Index::index` - --> $DIR/method_list_2.rs:43:5 + --> $DIR/method_list_2.rs:41:5 | LL | / pub fn index(&self, index: usize) -> &Self { LL | | unimplemented!() @@ -50,7 +50,7 @@ LL | | } = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` - --> $DIR/method_list_2.rs:47:5 + --> $DIR/method_list_2.rs:45:5 | LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { LL | | unimplemented!() @@ -60,7 +60,7 @@ LL | | } = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` - --> $DIR/method_list_2.rs:51:5 + --> $DIR/method_list_2.rs:49:5 | LL | / pub fn into_iter(self) -> Self { LL | | unimplemented!() @@ -70,7 +70,7 @@ LL | | } = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` - --> $DIR/method_list_2.rs:55:5 + --> $DIR/method_list_2.rs:53:5 | LL | / pub fn mul(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -80,7 +80,7 @@ LL | | } = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` - --> $DIR/method_list_2.rs:59:5 + --> $DIR/method_list_2.rs:57:5 | LL | / pub fn neg(self) -> Self { LL | | unimplemented!() @@ -90,7 +90,7 @@ LL | | } = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` - --> $DIR/method_list_2.rs:63:5 + --> $DIR/method_list_2.rs:61:5 | LL | / pub fn next(&mut self) -> Option { LL | | unimplemented!() @@ -100,7 +100,7 @@ LL | | } = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name error: method `not` can be confused for the standard trait method `std::ops::Not::not` - --> $DIR/method_list_2.rs:67:5 + --> $DIR/method_list_2.rs:65:5 | LL | / pub fn not(self) -> Self { LL | | unimplemented!() @@ -110,7 +110,7 @@ LL | | } = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` - --> $DIR/method_list_2.rs:71:5 + --> $DIR/method_list_2.rs:69:5 | LL | / pub fn rem(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -120,7 +120,7 @@ LL | | } = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` - --> $DIR/method_list_2.rs:75:5 + --> $DIR/method_list_2.rs:73:5 | LL | / pub fn shl(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -130,7 +130,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` - --> $DIR/method_list_2.rs:79:5 + --> $DIR/method_list_2.rs:77:5 | LL | / pub fn shr(self, rhs: Self) -> Self { LL | | unimplemented!() @@ -140,7 +140,7 @@ LL | | } = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` - --> $DIR/method_list_2.rs:83:5 + --> $DIR/method_list_2.rs:81:5 | LL | / pub fn sub(self, rhs: Self) -> Self { LL | | unimplemented!() diff --git a/tests/ui/single_component_path_imports.fixed b/tests/ui/single_component_path_imports.fixed index f66b445b7b6a3..4c40739d6f553 100644 --- a/tests/ui/single_component_path_imports.fixed +++ b/tests/ui/single_component_path_imports.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports.rs b/tests/ui/single_component_path_imports.rs index 09d4865859584..9280bab3c71b5 100644 --- a/tests/ui/single_component_path_imports.rs +++ b/tests/ui/single_component_path_imports.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports.stderr b/tests/ui/single_component_path_imports.stderr index 7005fa8f125d3..509c88ac256a8 100644 --- a/tests/ui/single_component_path_imports.stderr +++ b/tests/ui/single_component_path_imports.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports.rs:24:5 + --> $DIR/single_component_path_imports.rs:23:5 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely @@ -7,7 +7,7 @@ LL | use regex; = note: `-D clippy::single-component-path-imports` implied by `-D warnings` error: this import is redundant - --> $DIR/single_component_path_imports.rs:6:1 + --> $DIR/single_component_path_imports.rs:5:1 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely diff --git a/tests/ui/single_component_path_imports_macro.fixed b/tests/ui/single_component_path_imports_macro.fixed index 05863f9a2bf48..e43f5d381aaa1 100644 --- a/tests/ui/single_component_path_imports_macro.fixed +++ b/tests/ui/single_component_path_imports_macro.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports_macro.rs b/tests/ui/single_component_path_imports_macro.rs index 633deea348b81..3c65ca3054c69 100644 --- a/tests/ui/single_component_path_imports_macro.rs +++ b/tests/ui/single_component_path_imports_macro.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports_macro.stderr b/tests/ui/single_component_path_imports_macro.stderr index 239efb393b1ab..37d5176129ff3 100644 --- a/tests/ui/single_component_path_imports_macro.stderr +++ b/tests/ui/single_component_path_imports_macro.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports_macro.rs:16:1 + --> $DIR/single_component_path_imports_macro.rs:15:1 | LL | use m2; // fail | ^^^^^^^ help: remove it entirely diff --git a/tests/ui/single_component_path_imports_nested_first.rs b/tests/ui/single_component_path_imports_nested_first.rs index 94117061b270d..c75beb7478618 100644 --- a/tests/ui/single_component_path_imports_nested_first.rs +++ b/tests/ui/single_component_path_imports_nested_first.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports_nested_first.stderr b/tests/ui/single_component_path_imports_nested_first.stderr index 0c3256c1ce43a..cf990be1b9ff1 100644 --- a/tests/ui/single_component_path_imports_nested_first.stderr +++ b/tests/ui/single_component_path_imports_nested_first.stderr @@ -1,5 +1,5 @@ error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:14:10 + --> $DIR/single_component_path_imports_nested_first.rs:13:10 | LL | use {regex, serde}; | ^^^^^ @@ -8,7 +8,7 @@ LL | use {regex, serde}; = help: remove this import error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:14:17 + --> $DIR/single_component_path_imports_nested_first.rs:13:17 | LL | use {regex, serde}; | ^^^^^ @@ -16,7 +16,7 @@ LL | use {regex, serde}; = help: remove this import error: this import is redundant - --> $DIR/single_component_path_imports_nested_first.rs:5:1 + --> $DIR/single_component_path_imports_nested_first.rs:4:1 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely diff --git a/tests/ui/single_component_path_imports_self_after.rs b/tests/ui/single_component_path_imports_self_after.rs index 94319ade0ac4b..48e8e530261be 100644 --- a/tests/ui/single_component_path_imports_self_after.rs +++ b/tests/ui/single_component_path_imports_self_after.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/single_component_path_imports_self_before.rs b/tests/ui/single_component_path_imports_self_before.rs index c7437b234566a..4fb0cf40b6e00 100644 --- a/tests/ui/single_component_path_imports_self_before.rs +++ b/tests/ui/single_component_path_imports_self_before.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/tests/ui/unused_async.rs b/tests/ui/unused_async.rs index 4f4203f5fdbf6..2a3a506a57b14 100644 --- a/tests/ui/unused_async.rs +++ b/tests/ui/unused_async.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::unused_async)] async fn foo() -> i32 { diff --git a/tests/ui/unused_async.stderr b/tests/ui/unused_async.stderr index 8b834d205b176..cc6096d65d9f3 100644 --- a/tests/ui/unused_async.stderr +++ b/tests/ui/unused_async.stderr @@ -1,5 +1,5 @@ error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:4:1 + --> $DIR/unused_async.rs:3:1 | LL | / async fn foo() -> i32 { LL | | 4 diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index dcf818f807630..4e33e343ce0e9 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 // aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 9da6fef7a380c..7b621ff9bcabf 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,5 +1,4 @@ // run-rustfix -// edition:2018 // aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index e14368a11aa74..ecb78b3f9721b 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> $DIR/use_self.rs:23:21 + --> $DIR/use_self.rs:22:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -7,163 +7,163 @@ LL | fn new() -> Foo { = note: `-D clippy::use-self` implied by `-D warnings` error: unnecessary structure name repetition - --> $DIR/use_self.rs:24:13 + --> $DIR/use_self.rs:23:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:26:22 + --> $DIR/use_self.rs:25:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:27:13 + --> $DIR/use_self.rs:26:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:32:25 + --> $DIR/use_self.rs:31:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:33:13 + --> $DIR/use_self.rs:32:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:98:24 + --> $DIR/use_self.rs:97:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:98:55 + --> $DIR/use_self.rs:97:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:113:13 + --> $DIR/use_self.rs:112:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:148:29 + --> $DIR/use_self.rs:147:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:149:21 + --> $DIR/use_self.rs:148:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:160:21 + --> $DIR/use_self.rs:159:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:161:13 + --> $DIR/use_self.rs:160:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:178:21 + --> $DIR/use_self.rs:177:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:179:21 + --> $DIR/use_self.rs:178:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:180:21 + --> $DIR/use_self.rs:179:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:222:13 + --> $DIR/use_self.rs:221:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:223:13 + --> $DIR/use_self.rs:222:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:225:13 + --> $DIR/use_self.rs:224:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:244:13 + --> $DIR/use_self.rs:243:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:258:25 + --> $DIR/use_self.rs:257:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:259:13 + --> $DIR/use_self.rs:258:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:263:16 + --> $DIR/use_self.rs:262:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:263:22 + --> $DIR/use_self.rs:262:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:286:29 + --> $DIR/use_self.rs:285:29 | LL | fn foo(value: T) -> Foo { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:287:13 + --> $DIR/use_self.rs:286:13 | LL | Foo:: { value } | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:459:13 + --> $DIR/use_self.rs:458:13 | LL | A::new::(submod::B {}) | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:496:13 + --> $DIR/use_self.rs:495:13 | LL | S2::new() | ^^ help: use the applicable keyword: `Self` diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index d8bda7e8f48a7..21d66d5df79ec 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,4 +1,3 @@ -// edition:2018 // aux-build:proc_macro_derive.rs #![feature(rustc_private)] diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 2cbfc5ca2e270..790b849210c9b 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -1,5 +1,5 @@ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:26:5 + --> $DIR/used_underscore_binding.rs:25:5 | LL | _foo + 1 | ^^^^ @@ -7,31 +7,31 @@ LL | _foo + 1 = note: `-D clippy::used-underscore-binding` implied by `-D warnings` error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:31:20 + --> $DIR/used_underscore_binding.rs:30:20 | LL | println!("{}", _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:32:16 + --> $DIR/used_underscore_binding.rs:31:16 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:32:22 + --> $DIR/used_underscore_binding.rs:31:22 | LL | assert_eq!(_foo, _foo); | ^^^^ error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:45:5 + --> $DIR/used_underscore_binding.rs:44:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used - --> $DIR/used_underscore_binding.rs:100:16 + --> $DIR/used_underscore_binding.rs:99:16 | LL | uses_i(_i); | ^^ diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 98bc1e80731ff..8402c33a4cd5f 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -1,8 +1,13 @@ +// edition:2015 // run-rustfix // aux-build:wildcard_imports_helper.rs +// the 2015 edition here is needed because edition 2018 changed the module system +// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint +// no longer detects some of the cases starting with Rust 2018. +// FIXME: We should likely add another edition 2021 test case for this lint + #![warn(clippy::wildcard_imports)] -//#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 4ef61f9245b58..faaeaade9b02b 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -1,8 +1,13 @@ +// edition:2015 // run-rustfix // aux-build:wildcard_imports_helper.rs +// the 2015 edition here is needed because edition 2018 changed the module system +// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint +// no longer detects some of the cases starting with Rust 2018. +// FIXME: We should likely add another edition 2021 test case for this lint + #![warn(clippy::wildcard_imports)] -//#![allow(clippy::redundant_pub_crate)] #![allow(unused)] #![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index d7af0c046e886..7534a65ec9bd5 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:12:5 + --> $DIR/wildcard_imports.rs:17:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:13:5 + --> $DIR/wildcard_imports.rs:18:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:14:5 + --> $DIR/wildcard_imports.rs:19:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:16:5 + --> $DIR/wildcard_imports.rs:21:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:20:5 + --> $DIR/wildcard_imports.rs:25:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:21:5 + --> $DIR/wildcard_imports.rs:26:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:92:13 + --> $DIR/wildcard_imports.rs:97:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:98:75 + --> $DIR/wildcard_imports.rs:103:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:99:13 + --> $DIR/wildcard_imports.rs:104:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:110:20 + --> $DIR/wildcard_imports.rs:115:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:110:30 + --> $DIR/wildcard_imports.rs:115:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:117:13 + --> $DIR/wildcard_imports.rs:122:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:146:9 + --> $DIR/wildcard_imports.rs:151:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:155:9 + --> $DIR/wildcard_imports.rs:160:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:156:9 + --> $DIR/wildcard_imports.rs:161:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,37 +93,37 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:167:13 + --> $DIR/wildcard_imports.rs:172:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:202:17 + --> $DIR/wildcard_imports.rs:207:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:210:13 + --> $DIR/wildcard_imports.rs:215:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:219:17 + --> $DIR/wildcard_imports.rs:224:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:228:13 + --> $DIR/wildcard_imports.rs:233:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:236:13 + --> $DIR/wildcard_imports.rs:241:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 151dd0c27d57d..1b9da8a55e53f 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::wrong_self_convention)] #![allow(dead_code)] diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index ce23317abf651..590ee6d9c529d 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:17:17 + --> $DIR/wrong_self_convention.rs:16:17 | LL | fn from_i32(self) {} | ^^^^ @@ -8,7 +8,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:23:21 + --> $DIR/wrong_self_convention.rs:22:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -16,7 +16,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:35:15 + --> $DIR/wrong_self_convention.rs:34:15 | LL | fn as_i32(self) {} | ^^^^ @@ -24,7 +24,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:37:17 + --> $DIR/wrong_self_convention.rs:36:17 | LL | fn into_i32(&self) {} | ^^^^^ @@ -32,7 +32,7 @@ LL | fn into_i32(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:39:15 + --> $DIR/wrong_self_convention.rs:38:15 | LL | fn is_i32(self) {} | ^^^^ @@ -40,7 +40,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:41:15 + --> $DIR/wrong_self_convention.rs:40:15 | LL | fn to_i32(self) {} | ^^^^ @@ -48,7 +48,7 @@ LL | fn to_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:43:17 + --> $DIR/wrong_self_convention.rs:42:17 | LL | fn from_i32(self) {} | ^^^^ @@ -56,7 +56,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:45:19 + --> $DIR/wrong_self_convention.rs:44:19 | LL | pub fn as_i64(self) {} | ^^^^ @@ -64,7 +64,7 @@ LL | pub fn as_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:46:21 + --> $DIR/wrong_self_convention.rs:45:21 | LL | pub fn into_i64(&self) {} | ^^^^^ @@ -72,7 +72,7 @@ LL | pub fn into_i64(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:47:19 + --> $DIR/wrong_self_convention.rs:46:19 | LL | pub fn is_i64(self) {} | ^^^^ @@ -80,7 +80,7 @@ LL | pub fn is_i64(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:48:19 + --> $DIR/wrong_self_convention.rs:47:19 | LL | pub fn to_i64(self) {} | ^^^^ @@ -88,7 +88,7 @@ LL | pub fn to_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:49:21 + --> $DIR/wrong_self_convention.rs:48:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -96,7 +96,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:94:19 + --> $DIR/wrong_self_convention.rs:93:19 | LL | fn as_i32(self) {} | ^^^^ @@ -104,7 +104,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:97:25 + --> $DIR/wrong_self_convention.rs:96:25 | LL | fn into_i32_ref(&self) {} | ^^^^^ @@ -112,7 +112,7 @@ LL | fn into_i32_ref(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:99:19 + --> $DIR/wrong_self_convention.rs:98:19 | LL | fn is_i32(self) {} | ^^^^ @@ -120,7 +120,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:103:21 + --> $DIR/wrong_self_convention.rs:102:21 | LL | fn from_i32(self) {} | ^^^^ @@ -128,7 +128,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:118:19 + --> $DIR/wrong_self_convention.rs:117:19 | LL | fn as_i32(self); | ^^^^ @@ -136,7 +136,7 @@ LL | fn as_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:121:25 + --> $DIR/wrong_self_convention.rs:120:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -144,7 +144,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:123:19 + --> $DIR/wrong_self_convention.rs:122:19 | LL | fn is_i32(self); | ^^^^ @@ -152,7 +152,7 @@ LL | fn is_i32(self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:127:21 + --> $DIR/wrong_self_convention.rs:126:21 | LL | fn from_i32(self); | ^^^^ @@ -160,7 +160,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:145:25 + --> $DIR/wrong_self_convention.rs:144:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -168,7 +168,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:151:21 + --> $DIR/wrong_self_convention.rs:150:21 | LL | fn from_i32(self); | ^^^^ @@ -176,7 +176,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value - --> $DIR/wrong_self_convention.rs:175:22 + --> $DIR/wrong_self_convention.rs:174:22 | LL | fn to_u64_v2(&self) -> u64 { | ^^^^^ @@ -184,7 +184,7 @@ LL | fn to_u64_v2(&self) -> u64 { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:184:19 + --> $DIR/wrong_self_convention.rs:183:19 | LL | fn to_u64(self) -> u64 { | ^^^^ diff --git a/tests/ui/wrong_self_convention2.rs b/tests/ui/wrong_self_convention2.rs index 0d827c1feb3e7..a8fe833113377 100644 --- a/tests/ui/wrong_self_convention2.rs +++ b/tests/ui/wrong_self_convention2.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::wrong_self_convention)] #![allow(dead_code)] diff --git a/tests/ui/wrong_self_convention2.stderr b/tests/ui/wrong_self_convention2.stderr index 0e0d066d656b5..5bdc47f91f65b 100644 --- a/tests/ui/wrong_self_convention2.stderr +++ b/tests/ui/wrong_self_convention2.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention2.rs:55:29 + --> $DIR/wrong_self_convention2.rs:54:29 | LL | pub fn from_be_self(self) -> Self { | ^^^^ @@ -8,7 +8,7 @@ LL | pub fn from_be_self(self) -> Self { = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention2.rs:64:25 + --> $DIR/wrong_self_convention2.rs:63:25 | LL | fn from_be_self(self) -> Self; | ^^^^ diff --git a/tests/ui/wrong_self_conventions_mut.rs b/tests/ui/wrong_self_conventions_mut.rs index 486a0d7723585..5bb2116bd339a 100644 --- a/tests/ui/wrong_self_conventions_mut.rs +++ b/tests/ui/wrong_self_conventions_mut.rs @@ -1,4 +1,3 @@ -// edition:2018 #![warn(clippy::wrong_self_convention)] #![allow(dead_code)] diff --git a/tests/ui/wrong_self_conventions_mut.stderr b/tests/ui/wrong_self_conventions_mut.stderr index 6ce37c5949111..8665d8dc9a9de 100644 --- a/tests/ui/wrong_self_conventions_mut.stderr +++ b/tests/ui/wrong_self_conventions_mut.stderr @@ -1,5 +1,5 @@ error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_conventions_mut.rs:15:24 + --> $DIR/wrong_self_conventions_mut.rs:14:24 | LL | pub fn to_many(&mut self) -> Option<&mut [T]> { | ^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub fn to_many(&mut self) -> Option<&mut [T]> { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference - --> $DIR/wrong_self_conventions_mut.rs:23:28 + --> $DIR/wrong_self_conventions_mut.rs:22:28 | LL | pub fn to_many_mut(&self) -> Option<&[T]> { | ^^^^^ From 892063ed2d6362c8aea114b03468cc4d0029210b Mon Sep 17 00:00:00 2001 From: John Kugelman Date: Mon, 11 Oct 2021 16:15:50 -0400 Subject: [PATCH 49/65] Add #[must_use] to len and is_empty --- tests/ui/iter_count.fixed | 7 +++-- tests/ui/iter_count.rs | 7 +++-- tests/ui/iter_count.stderr | 62 +++++++++++++++++++------------------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/tests/ui/iter_count.fixed b/tests/ui/iter_count.fixed index 97c5929783d88..90a6eef75261f 100644 --- a/tests/ui/iter_count.fixed +++ b/tests/ui/iter_count.fixed @@ -33,6 +33,7 @@ impl HasIter { } } +#[allow(unused_must_use)] fn main() { let mut vec = vec![0, 1, 2, 3]; let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); @@ -50,7 +51,7 @@ fn main() { linked_list.push_back(1); binary_heap.push(1); - let _ = &vec[..].len(); + &vec[..].len(); vec.len(); boxed_slice.len(); vec_deque.len(); @@ -62,13 +63,13 @@ fn main() { binary_heap.len(); vec.len(); - let _ = &vec[..].len(); + &vec[..].len(); vec_deque.len(); hash_map.len(); b_tree_map.len(); linked_list.len(); - let _ = &vec[..].len(); + &vec[..].len(); vec.len(); vec_deque.len(); hash_set.len(); diff --git a/tests/ui/iter_count.rs b/tests/ui/iter_count.rs index 70bb734763f09..6681a480a28c8 100644 --- a/tests/ui/iter_count.rs +++ b/tests/ui/iter_count.rs @@ -33,6 +33,7 @@ impl HasIter { } } +#[allow(unused_must_use)] fn main() { let mut vec = vec![0, 1, 2, 3]; let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); @@ -50,7 +51,7 @@ fn main() { linked_list.push_back(1); binary_heap.push(1); - let _ = &vec[..].iter().count(); + &vec[..].iter().count(); vec.iter().count(); boxed_slice.iter().count(); vec_deque.iter().count(); @@ -62,13 +63,13 @@ fn main() { binary_heap.iter().count(); vec.iter_mut().count(); - let _ = &vec[..].iter_mut().count(); + &vec[..].iter_mut().count(); vec_deque.iter_mut().count(); hash_map.iter_mut().count(); b_tree_map.iter_mut().count(); linked_list.iter_mut().count(); - let _ = &vec[..].into_iter().count(); + &vec[..].into_iter().count(); vec.into_iter().count(); vec_deque.into_iter().count(); hash_set.into_iter().count(); diff --git a/tests/ui/iter_count.stderr b/tests/ui/iter_count.stderr index 1d2c22f9dfad5..2e3d7fc35de9c 100644 --- a/tests/ui/iter_count.stderr +++ b/tests/ui/iter_count.stderr @@ -1,151 +1,151 @@ error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:53:14 + --> $DIR/iter_count.rs:54:6 | -LL | let _ = &vec[..].iter().count(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` +LL | &vec[..].iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` | = note: `-D clippy::iter-count` implied by `-D warnings` error: called `.iter().count()` on a `Vec` - --> $DIR/iter_count.rs:54:5 + --> $DIR/iter_count.rs:55:5 | LL | vec.iter().count(); | ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:55:5 + --> $DIR/iter_count.rs:56:5 | LL | boxed_slice.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()` error: called `.iter().count()` on a `VecDeque` - --> $DIR/iter_count.rs:56:5 + --> $DIR/iter_count.rs:57:5 | LL | vec_deque.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.iter().count()` on a `HashSet` - --> $DIR/iter_count.rs:57:5 + --> $DIR/iter_count.rs:58:5 | LL | hash_set.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` error: called `.iter().count()` on a `HashMap` - --> $DIR/iter_count.rs:58:5 + --> $DIR/iter_count.rs:59:5 | LL | hash_map.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.iter().count()` on a `BTreeMap` - --> $DIR/iter_count.rs:59:5 + --> $DIR/iter_count.rs:60:5 | LL | b_tree_map.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.iter().count()` on a `BTreeSet` - --> $DIR/iter_count.rs:60:5 + --> $DIR/iter_count.rs:61:5 | LL | b_tree_set.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` error: called `.iter().count()` on a `LinkedList` - --> $DIR/iter_count.rs:61:5 + --> $DIR/iter_count.rs:62:5 | LL | linked_list.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.iter().count()` on a `BinaryHeap` - --> $DIR/iter_count.rs:62:5 + --> $DIR/iter_count.rs:63:5 | LL | binary_heap.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` error: called `.iter_mut().count()` on a `Vec` - --> $DIR/iter_count.rs:64:5 + --> $DIR/iter_count.rs:65:5 | LL | vec.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter_mut().count()` on a `slice` - --> $DIR/iter_count.rs:65:14 + --> $DIR/iter_count.rs:66:6 | -LL | let _ = &vec[..].iter_mut().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` +LL | &vec[..].iter_mut().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.iter_mut().count()` on a `VecDeque` - --> $DIR/iter_count.rs:66:5 + --> $DIR/iter_count.rs:67:5 | LL | vec_deque.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.iter_mut().count()` on a `HashMap` - --> $DIR/iter_count.rs:67:5 + --> $DIR/iter_count.rs:68:5 | LL | hash_map.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.iter_mut().count()` on a `BTreeMap` - --> $DIR/iter_count.rs:68:5 + --> $DIR/iter_count.rs:69:5 | LL | b_tree_map.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.iter_mut().count()` on a `LinkedList` - --> $DIR/iter_count.rs:69:5 + --> $DIR/iter_count.rs:70:5 | LL | linked_list.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.into_iter().count()` on a `slice` - --> $DIR/iter_count.rs:71:14 + --> $DIR/iter_count.rs:72:6 | -LL | let _ = &vec[..].into_iter().count(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` +LL | &vec[..].into_iter().count(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.into_iter().count()` on a `Vec` - --> $DIR/iter_count.rs:72:5 + --> $DIR/iter_count.rs:73:5 | LL | vec.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.into_iter().count()` on a `VecDeque` - --> $DIR/iter_count.rs:73:5 + --> $DIR/iter_count.rs:74:5 | LL | vec_deque.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.into_iter().count()` on a `HashSet` - --> $DIR/iter_count.rs:74:5 + --> $DIR/iter_count.rs:75:5 | LL | hash_set.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` error: called `.into_iter().count()` on a `HashMap` - --> $DIR/iter_count.rs:75:5 + --> $DIR/iter_count.rs:76:5 | LL | hash_map.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.into_iter().count()` on a `BTreeMap` - --> $DIR/iter_count.rs:76:5 + --> $DIR/iter_count.rs:77:5 | LL | b_tree_map.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.into_iter().count()` on a `BTreeSet` - --> $DIR/iter_count.rs:77:5 + --> $DIR/iter_count.rs:78:5 | LL | b_tree_set.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` error: called `.into_iter().count()` on a `LinkedList` - --> $DIR/iter_count.rs:78:5 + --> $DIR/iter_count.rs:79:5 | LL | linked_list.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.into_iter().count()` on a `BinaryHeap` - --> $DIR/iter_count.rs:79:5 + --> $DIR/iter_count.rs:80:5 | LL | binary_heap.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` From 28c225f7758f68b25205953919b74c1c7fe03e2a Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 31 Oct 2021 12:25:53 +0000 Subject: [PATCH 50/65] Move non_ascii_literal to restriction --- clippy_lints/src/lib.register_pedantic.rs | 1 - clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/unicode.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 63ab7f1ca6f67..6893bfd473d78 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -89,7 +89,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ 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), diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 4929bbecde090..6b4c1b7db5173 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -59,6 +59,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(types::RC_BUFFER), LintId::of(types::RC_MUTEX), LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS), + LintId::of(unicode::NON_ASCII_LITERAL), 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/unicode.rs b/clippy_lints/src/unicode.rs index f337dec8f2b96..f49ce696a04b7 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// let x = String::from("\u{20ac}"); /// ``` pub NON_ASCII_LITERAL, - pedantic, + restriction, "using any literal non-ASCII chars in a string literal instead of using the `\\u` escape" } From 1085df58ac898fdaea416e592c8667bef162ea87 Mon Sep 17 00:00:00 2001 From: Dharma Saputra Wijaya Date: Wed, 22 Sep 2021 22:13:54 +0800 Subject: [PATCH 51/65] Add `separated_literal_suffix` as an alternative for `unseparated_literal_suffix` This commit adds a configuration `literal-suffix-style` to enforce a specific style for unseparated_literal_suffix. The configuration accepts two values: - "separated" enforce all literals to be written separately (e.g. `123_i32`) - "unseparated" enforce all literals to be written as unseparated (e.g. `123i32`) Not specifying a value means that there is no preference on style and any style should not be warned. --- clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_restriction.rs | 1 + clippy_lints/src/misc_early/double_neg.rs | 23 +++--- clippy_lints/src/misc_early/literal_suffix.rs | 38 ++++++++++ clippy_lints/src/misc_early/mod.rs | 39 ++++++++-- .../misc_early/unseparated_literal_suffix.rs | 26 ------- tests/ui/literals.rs | 3 +- tests/ui/literals.stderr | 74 ++++++++++++++++--- 8 files changed, 148 insertions(+), 57 deletions(-) create mode 100644 clippy_lints/src/misc_early/literal_suffix.rs delete mode 100644 clippy_lints/src/misc_early/unseparated_literal_suffix.rs diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 28d54246fbbb2..48ceecde7c9e9 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -323,6 +323,7 @@ store.register_lints(&[ misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, misc_early::MIXED_CASE_HEX_LITERALS, misc_early::REDUNDANT_PATTERN, + misc_early::SEPARATED_LITERAL_SUFFIX, misc_early::UNNEEDED_FIELD_PATTERN, misc_early::UNNEEDED_WILDCARD_PATTERN, misc_early::UNSEPARATED_LITERAL_SUFFIX, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 419a40b1bb8a6..bc71602f67e86 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -34,6 +34,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::GET_UNWRAP), LintId::of(methods::UNWRAP_USED), LintId::of(misc::FLOAT_CMP_CONST), + LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), diff --git a/clippy_lints/src/misc_early/double_neg.rs b/clippy_lints/src/misc_early/double_neg.rs index 6f65778e1193c..06ba968fa4ed3 100644 --- a/clippy_lints/src/misc_early/double_neg.rs +++ b/clippy_lints/src/misc_early/double_neg.rs @@ -1,4 +1,3 @@ -use super::MiscEarlyLints; use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind, UnOp}; use rustc_lint::EarlyContext; @@ -6,18 +5,14 @@ use rustc_lint::EarlyContext; use super::DOUBLE_NEG; pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) { - match expr.kind { - ExprKind::Unary(UnOp::Neg, ref inner) => { - if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { - span_lint( - cx, - DOUBLE_NEG, - expr.span, - "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", - ); - } - }, - ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit), - _ => (), + if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind { + if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { + span_lint( + cx, + DOUBLE_NEG, + expr.span, + "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", + ); + } } } diff --git a/clippy_lints/src/misc_early/literal_suffix.rs b/clippy_lints/src/misc_early/literal_suffix.rs new file mode 100644 index 0000000000000..1165c19a0cf0b --- /dev/null +++ b/clippy_lints/src/misc_early/literal_suffix.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::ast::Lit; +use rustc_errors::Applicability; +use rustc_lint::EarlyContext; + +use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX}; + +pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) { + let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { + val + } else { + return; // It's useless so shouldn't lint. + }; + // Do not lint when literal is unsuffixed. + if !suffix.is_empty() { + if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' { + span_lint_and_sugg( + cx, + SEPARATED_LITERAL_SUFFIX, + lit.span, + &format!("{} type suffix should not be separated by an underscore", sugg_type), + "remove the underscore", + format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + UNSEPARATED_LITERAL_SUFFIX, + lit.span, + &format!("{} type suffix should be separated by an underscore", sugg_type), + "add an underscore", + format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 5aad08cdd46c0..7c3f5f22ade0f 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -1,15 +1,15 @@ mod builtin_type_shadow; mod double_neg; +mod literal_suffix; mod mixed_case_hex_literals; mod redundant_pattern; mod unneeded_field_pattern; mod unneeded_wildcard_pattern; -mod unseparated_literal_suffix; mod zero_prefixed_literal; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; +use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -115,9 +115,11 @@ declare_clippy_lint! { /// ### What it does /// Warns if literal suffixes are not separated by an /// underscore. + /// To enforce unseparated literal suffix style, + /// see the `separated_literal_suffix` lint. /// /// ### Why is this bad? - /// It is much less readable. + /// Suffix style should be consistent. /// /// ### Example /// ```rust @@ -132,6 +134,28 @@ declare_clippy_lint! { "literals whose suffix is not separated by an underscore" } +declare_clippy_lint! { + /// ### What it does + /// Warns if literal suffixes are separated by an underscore. + /// To enforce separated literal suffix style, + /// see the `unseparated_literal_suffix` lint. + /// + /// ### Why is this bad? + /// Suffix style should be consistent. + /// + /// ### Example + /// ```rust + /// // Bad + /// let y = 123832_i32; + /// + /// // Good + /// let y = 123832i32; + /// ``` + pub SEPARATED_LITERAL_SUFFIX, + restriction, + "literals whose suffix is separated by an underscore" +} + declare_clippy_lint! { /// ### What it does /// Warns if an integral constant literal starts with `0`. @@ -260,6 +284,7 @@ declare_lint_pass!(MiscEarlyLints => [ DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, + SEPARATED_LITERAL_SUFFIX, ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW, REDUNDANT_PATTERN, @@ -310,6 +335,10 @@ impl EarlyLintPass for MiscEarlyLints { if in_external_macro(cx.sess, expr.span) { return; } + + if let ExprKind::Lit(ref lit) = expr.kind { + MiscEarlyLints::check_lit(cx, lit); + } double_neg::check(cx, expr); } } @@ -332,7 +361,7 @@ impl MiscEarlyLints { LitIntType::Unsigned(ty) => ty.name_str(), LitIntType::Unsuffixed => "", }; - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); + literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); if lit_snip.starts_with("0x") { mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip); } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") { @@ -342,7 +371,7 @@ impl MiscEarlyLints { } } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind { let suffix = float_ty.name_str(); - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); + literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); } } } diff --git a/clippy_lints/src/misc_early/unseparated_literal_suffix.rs b/clippy_lints/src/misc_early/unseparated_literal_suffix.rs deleted file mode 100644 index 2018aa6184a8d..0000000000000 --- a/clippy_lints/src/misc_early/unseparated_literal_suffix.rs +++ /dev/null @@ -1,26 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::ast::Lit; -use rustc_errors::Applicability; -use rustc_lint::EarlyContext; - -use super::UNSEPARATED_LITERAL_SUFFIX; - -pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) { - let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) { - val - } else { - return; // It's useless so shouldn't lint. - }; - // Do not lint when literal is unsuffixed. - if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' { - span_lint_and_sugg( - cx, - UNSEPARATED_LITERAL_SUFFIX, - lit.span, - &format!("{} type suffix should be separated by an underscore", sugg_type), - "add an underscore", - format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix), - Applicability::MachineApplicable, - ); - } -} diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index a72a74b9131d8..e60ce8492fc77 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -2,7 +2,8 @@ #![warn(clippy::mixed_case_hex_literals)] #![warn(clippy::zero_prefixed_literal)] -#![allow(clippy::unseparated_literal_suffix)] +#![warn(clippy::unseparated_literal_suffix)] +#![warn(clippy::separated_literal_suffix)] #![allow(dead_code)] fn main() { diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index 99542e20f785f..365b240747352 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -1,25 +1,65 @@ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:12:15 + | +LL | let ok4 = 0xab_cd_i32; + | ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32` + | + = note: `-D clippy::separated-literal-suffix` implied by `-D warnings` + +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:13:15 + | +LL | let ok5 = 0xAB_CD_u32; + | ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32` + +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:14:15 + | +LL | let ok5 = 0xAB_CD_isize; + | ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize` + error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:14:17 + --> $DIR/literals.rs:15:17 | LL | let fail1 = 0xabCD; | ^^^^^^ | = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings` +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:16:17 + | +LL | let fail2 = 0xabCD_u32; + | ^^^^^^^^^^ help: remove the underscore: `0xabCDu32` + error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:15:17 + --> $DIR/literals.rs:16:17 | LL | let fail2 = 0xabCD_u32; | ^^^^^^^^^^ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:17:17 + | +LL | let fail2 = 0xabCD_isize; + | ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize` + error: inconsistent casing in hexadecimal literal - --> $DIR/literals.rs:16:17 + --> $DIR/literals.rs:17:17 | LL | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ +error: integer type suffix should be separated by an underscore + --> $DIR/literals.rs:18:27 + | +LL | let fail_multi_zero = 000_123usize; + | ^^^^^^^^^^^^ help: add an underscore: `000_123_usize` + | + = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` + error: this is a decimal constant - --> $DIR/literals.rs:17:27 + --> $DIR/literals.rs:18:27 | LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ @@ -34,8 +74,14 @@ help: if you mean to use an octal constant, use `0o` LL | let fail_multi_zero = 0o123usize; | ~~~~~~~~~~ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:21:16 + | +LL | let ok10 = 0_i64; + | ^^^^^ help: remove the underscore: `0i64` + error: this is a decimal constant - --> $DIR/literals.rs:21:17 + --> $DIR/literals.rs:22:17 | LL | let fail8 = 0123; | ^^^^ @@ -49,8 +95,14 @@ help: if you mean to use an octal constant, use `0o` LL | let fail8 = 0o123; | ~~~~~ +error: integer type suffix should not be separated by an underscore + --> $DIR/literals.rs:31:16 + | +LL | let ok17 = 0x123_4567_8901_usize; + | ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize` + error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:33:18 + --> $DIR/literals.rs:34:18 | LL | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` @@ -58,19 +110,19 @@ LL | let fail19 = 12_3456_21; = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:34:18 + --> $DIR/literals.rs:35:18 | LL | let fail22 = 3__4___23; | ^^^^^^^^^ help: consider: `3_423` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:35:18 + --> $DIR/literals.rs:36:18 | LL | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` error: digits of hex or binary literal not grouped by four - --> $DIR/literals.rs:37:18 + --> $DIR/literals.rs:38:18 | LL | let fail24 = 0xAB_ABC_AB; | ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB` @@ -78,10 +130,10 @@ LL | let fail24 = 0xAB_ABC_AB; = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings` error: digits of hex or binary literal not grouped by four - --> $DIR/literals.rs:38:18 + --> $DIR/literals.rs:39:18 | LL | let fail25 = 0b01_100_101; | ^^^^^^^^^^^^ help: consider: `0b0110_0101` -error: aborting due to 10 previous errors +error: aborting due to 18 previous errors From bb1cf729990e063a858bf31b54bd1d0e13dc4707 Mon Sep 17 00:00:00 2001 From: dswij Date: Mon, 4 Oct 2021 11:54:27 +0800 Subject: [PATCH 52/65] Update CHANGELOG to include `separated_literal_suffix` --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4424f506146..5a3705dcd6dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2972,6 +2972,7 @@ Released 2018-09-13 [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors [`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned +[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same From 7e5f99ab58afc53f208f31db2e1d664efe679ce2 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 21 Oct 2021 00:08:18 +0100 Subject: [PATCH 53/65] Fix manual_assert for `#![no_std]` and Rust 2021 --- clippy_lints/src/manual_assert.rs | 25 ++++---- clippy_lints/src/matches.rs | 24 ++++---- clippy_utils/src/higher.rs | 4 +- tests/ui/manual_assert.edition2018.fixed | 43 +++++++++++++ ...tderr => manual_assert.edition2018.stderr} | 14 ++--- tests/ui/manual_assert.edition2021.fixed | 43 +++++++++++++ tests/ui/manual_assert.edition2021.stderr | 60 +++++++++++++++++++ tests/ui/manual_assert.fixed | 5 +- tests/ui/manual_assert.rs | 5 +- ... => match_wild_err_arm.edition2018.stderr} | 8 +-- .../ui/match_wild_err_arm.edition2021.stderr | 35 +++++++++++ tests/ui/match_wild_err_arm.rs | 7 ++- 12 files changed, 230 insertions(+), 43 deletions(-) create mode 100644 tests/ui/manual_assert.edition2018.fixed rename tests/ui/{manual_assert.stderr => manual_assert.edition2018.stderr} (87%) create mode 100644 tests/ui/manual_assert.edition2021.fixed create mode 100644 tests/ui/manual_assert.edition2021.stderr rename tests/ui/{match_wild_err_arm.stderr => match_wild_err_arm.edition2018.stderr} (86%) create mode 100644 tests/ui/match_wild_err_arm.edition2021.stderr diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index c639be1bccba4..e55aa3f1850fe 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -54,23 +54,24 @@ impl LateLintPass<'_> for ManualAssert { if !cx.tcx.sess.source_map().is_multiline(cond.span); then { - let span = if let Some(panic_expn) = PanicExpn::parse(semi) { + let call = if_chain! { + if let ExprKind::Block(block, _) = semi.kind; + if let Some(init) = block.expr; + then { + init + } else { + semi + } + }; + let span = if let Some(panic_expn) = PanicExpn::parse(call) { match *panic_expn.format_args.value_args { [] => panic_expn.format_args.format_string_span, [.., last] => panic_expn.format_args.format_string_span.to(last.span), } + } else if let ExprKind::Call(_, [format_args]) = call.kind { + format_args.span } else { - if_chain! { - if let ExprKind::Block(block, _) = semi.kind; - if let Some(init) = block.expr; - if let ExprKind::Call(_, [format_args]) = init.kind; - - then { - format_args.span - } else { - return - } - } + return }; let mut applicability = Applicability::MachineApplicable; let sugg = snippet_with_applicability(cx, span, "..", &mut applicability); diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index f1289a36e7770..eb311983b2927 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -967,8 +967,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm } if_chain! { if matching_wild; - if let ExprKind::Block(block, _) = arm.body.kind; - if is_panic_block(block); + if is_panic_call(arm.body); then { // `Err(_)` or `Err(_e)` arm with `panic!` found span_lint_and_note(cx, @@ -1171,14 +1170,19 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) } // If the block contains only a `panic!` macro (as expression or statement) -fn is_panic_block(block: &Block<'_>) -> bool { - match (&block.expr, block.stmts.len(), block.stmts.first()) { - (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(), - (&None, 1, Some(stmt)) => { - is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none() - }, - _ => false, - } +fn is_panic_call(expr: &Expr<'_>) -> bool { + // Unwrap any wrapping blocks + let span = if let ExprKind::Block(block, _) = expr.kind { + match (&block.expr, block.stmts.len(), block.stmts.first()) { + (&Some(exp), 0, _) => exp.span, + (&None, 1, Some(stmt)) => stmt.span, + _ => return false, + } + } else { + expr.span + }; + + is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none() } fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>) diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 7cbd43e6266e9..c1a763def3d15 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -718,9 +718,7 @@ impl PanicExpn<'tcx> { /// Parses an expanded `panic!` invocation pub fn parse(expr: &'tcx Expr<'tcx>) -> Option { if_chain! { - if let ExprKind::Block(block, _) = expr.kind; - if let Some(init) = block.expr; - if let ExprKind::Call(_, [format_args]) = init.kind; + if let ExprKind::Call(_, [format_args]) = expr.kind; let expn_data = expr.span.ctxt().outer_expn_data(); if let Some(format_args) = FormatArgsExpn::parse(format_args); then { diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed new file mode 100644 index 0000000000000..11fe06c572471 --- /dev/null +++ b/tests/ui/manual_assert.edition2018.fixed @@ -0,0 +1,43 @@ +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 +// run-rustfix +#![warn(clippy::manual_assert)] + +fn main() { + let a = vec![1, 2, 3]; + let c = Some(2); + if !a.is_empty() + && a.len() == 3 + && c != None + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + { + panic!("qaqaq{:?}", a); + } + assert!(a.is_empty(), "qaqaq{:?}", a); + assert!(a.is_empty(), "qwqwq"); + if a.len() == 3 { + println!("qwq"); + println!("qwq"); + println!("qwq"); + } + if let Some(b) = c { + panic!("orz {}", b); + } + if a.len() == 3 { + panic!("qaqaq"); + } 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/manual_assert.stderr b/tests/ui/manual_assert.edition2018.stderr similarity index 87% rename from tests/ui/manual_assert.stderr rename to tests/ui/manual_assert.edition2018.stderr index a8e907d25db3b..03c03472f908f 100644 --- a/tests/ui/manual_assert.stderr +++ b/tests/ui/manual_assert.edition2018.stderr @@ -1,5 +1,5 @@ error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:21:5 + --> $DIR/manual_assert.rs:22:5 | LL | / if !a.is_empty() { LL | | panic!("qaqaq{:?}", a); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-assert` implied by `-D warnings` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:24:5 + --> $DIR/manual_assert.rs:25:5 | LL | / if !a.is_empty() { LL | | panic!("qwqwq"); @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:41:5 + --> $DIR/manual_assert.rs:42:5 | LL | / if b.is_empty() { LL | | panic!("panic1"); @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try: `assert!(!b.is_empty(), "panic1");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:44:5 + --> $DIR/manual_assert.rs:45:5 | LL | / if b.is_empty() && a.is_empty() { LL | | panic!("panic2"); @@ -33,7 +33,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:47:5 + --> $DIR/manual_assert.rs:48:5 | LL | / if a.is_empty() && !b.is_empty() { LL | | panic!("panic3"); @@ -41,7 +41,7 @@ LL | | } | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:50:5 + --> $DIR/manual_assert.rs:51:5 | LL | / if b.is_empty() || a.is_empty() { LL | | panic!("panic4"); @@ -49,7 +49,7 @@ LL | | } | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` error: only a `panic!` in `if`-then statement - --> $DIR/manual_assert.rs:53:5 + --> $DIR/manual_assert.rs:54:5 | LL | / if a.is_empty() || !b.is_empty() { LL | | panic!("panic5"); diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed new file mode 100644 index 0000000000000..11fe06c572471 --- /dev/null +++ b/tests/ui/manual_assert.edition2021.fixed @@ -0,0 +1,43 @@ +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 +// run-rustfix +#![warn(clippy::manual_assert)] + +fn main() { + let a = vec![1, 2, 3]; + let c = Some(2); + if !a.is_empty() + && a.len() == 3 + && c != None + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + && !a.is_empty() + && a.len() == 3 + { + panic!("qaqaq{:?}", a); + } + assert!(a.is_empty(), "qaqaq{:?}", a); + assert!(a.is_empty(), "qwqwq"); + if a.len() == 3 { + println!("qwq"); + println!("qwq"); + println!("qwq"); + } + if let Some(b) = c { + panic!("orz {}", b); + } + if a.len() == 3 { + panic!("qaqaq"); + } 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/manual_assert.edition2021.stderr b/tests/ui/manual_assert.edition2021.stderr new file mode 100644 index 0000000000000..03c03472f908f --- /dev/null +++ b/tests/ui/manual_assert.edition2021.stderr @@ -0,0 +1,60 @@ +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:22:5 + | +LL | / if !a.is_empty() { +LL | | panic!("qaqaq{:?}", a); +LL | | } + | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);` + | + = note: `-D clippy::manual-assert` implied by `-D warnings` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:25:5 + | +LL | / if !a.is_empty() { +LL | | panic!("qwqwq"); +LL | | } + | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");` + +error: only a `panic!` in `if`-then statement + --> $DIR/manual_assert.rs:42: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/manual_assert.rs:45: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/manual_assert.rs:48: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/manual_assert.rs:51: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/manual_assert.rs:54: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/manual_assert.fixed b/tests/ui/manual_assert.fixed index 8943bc80897e0..11fe06c572471 100644 --- a/tests/ui/manual_assert.fixed +++ b/tests/ui/manual_assert.fixed @@ -1,6 +1,7 @@ -// edition:2018 +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 // run-rustfix -//FIXME: This does not correctly match in edition 2021, see #7843 #![warn(clippy::manual_assert)] fn main() { diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 4c474777e8dd6..8713426fc8886 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -1,6 +1,7 @@ -// edition:2018 +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 // run-rustfix -//FIXME: This does not correctly match in edition 2021, see #7843 #![warn(clippy::manual_assert)] fn main() { diff --git a/tests/ui/match_wild_err_arm.stderr b/tests/ui/match_wild_err_arm.edition2018.stderr similarity index 86% rename from tests/ui/match_wild_err_arm.stderr rename to tests/ui/match_wild_err_arm.edition2018.stderr index d5ec722d5691b..2a4012039ba97 100644 --- a/tests/ui/match_wild_err_arm.stderr +++ b/tests/ui/match_wild_err_arm.edition2018.stderr @@ -1,5 +1,5 @@ error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:13:9 + --> $DIR/match_wild_err_arm.rs:14:9 | LL | Err(_) => panic!("err"), | ^^^^^^ @@ -8,7 +8,7 @@ LL | Err(_) => panic!("err"), = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:19:9 + --> $DIR/match_wild_err_arm.rs:20:9 | LL | Err(_) => panic!(), | ^^^^^^ @@ -16,7 +16,7 @@ LL | Err(_) => panic!(), = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors - --> $DIR/match_wild_err_arm.rs:25:9 + --> $DIR/match_wild_err_arm.rs:26:9 | LL | Err(_) => { | ^^^^^^ @@ -24,7 +24,7 @@ LL | Err(_) => { = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_e)` matches all errors - --> $DIR/match_wild_err_arm.rs:33:9 + --> $DIR/match_wild_err_arm.rs:34:9 | LL | Err(_e) => panic!(), | ^^^^^^^ diff --git a/tests/ui/match_wild_err_arm.edition2021.stderr b/tests/ui/match_wild_err_arm.edition2021.stderr new file mode 100644 index 0000000000000..2a4012039ba97 --- /dev/null +++ b/tests/ui/match_wild_err_arm.edition2021.stderr @@ -0,0 +1,35 @@ +error: `Err(_)` matches all errors + --> $DIR/match_wild_err_arm.rs:14:9 + | +LL | Err(_) => panic!("err"), + | ^^^^^^ + | + = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: `Err(_)` matches all errors + --> $DIR/match_wild_err_arm.rs:20:9 + | +LL | Err(_) => panic!(), + | ^^^^^^ + | + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: `Err(_)` matches all errors + --> $DIR/match_wild_err_arm.rs:26:9 + | +LL | Err(_) => { + | ^^^^^^ + | + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: `Err(_e)` matches all errors + --> $DIR/match_wild_err_arm.rs:34:9 + | +LL | Err(_e) => panic!(), + | ^^^^^^^ + | + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + +error: aborting due to 4 previous errors + diff --git a/tests/ui/match_wild_err_arm.rs b/tests/ui/match_wild_err_arm.rs index 010cb7e03015e..0a86144b95d5b 100644 --- a/tests/ui/match_wild_err_arm.rs +++ b/tests/ui/match_wild_err_arm.rs @@ -1,12 +1,13 @@ -//edition:2015 -//FIXME: The lint only triggers once on edition 2021, so I'm leaving this at 2015 for now. - +// revisions: edition2018 edition2021 +// [edition2018] edition:2018 +// [edition2021] edition:2021 #![feature(exclusive_range_pattern)] #![allow(clippy::match_same_arms)] #![warn(clippy::match_wild_err_arm)] fn match_wild_err_arm() { let x: Result = Ok(3); + match x { Ok(3) => println!("ok"), Ok(_) => println!("ok"), From 14e0390fdffe87fb8beac8b9ed6a6edf43b57fbd Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sun, 24 Oct 2021 22:19:59 +0100 Subject: [PATCH 54/65] Account for revisions in missing-test-files --- tests/missing-test-files.rs | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index bd342e390f52f..7d6edc2b1e095 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -1,7 +1,10 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::assertions_on_constants)] +#![feature(path_file_prefix)] +use std::cmp::Ordering; +use std::ffi::OsStr; use std::fs::{self, DirEntry}; use std::path::Path; @@ -21,29 +24,39 @@ fn test_missing_tests() { } } -/* -Test for missing files. - -Since rs files are alphabetically before stderr/stdout, we can sort by the full name -and iter in that order. If we've seen the file stem for the first time and it's not -a rust file, it means the rust file has to be missing. -*/ +// Test for missing files. fn explore_directory(dir: &Path) -> Vec { let mut missing_files: Vec = Vec::new(); let mut current_file = String::new(); let mut files: Vec = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect(); - files.sort_by_key(std::fs::DirEntry::path); + files.sort_by(|x, y| { + match x.path().file_prefix().cmp(&y.path().file_prefix()) { + Ordering::Equal => (), + ord => return ord, + } + // Sort rs files before the others if they share the same prefix. So when we see + // the file prefix for the first time and it's not a rust file, it means the rust + // file has to be missing. + match ( + x.path().extension().and_then(OsStr::to_str), + y.path().extension().and_then(OsStr::to_str), + ) { + (Some("rs"), _) => Ordering::Less, + (_, Some("rs")) => Ordering::Greater, + _ => Ordering::Equal, + } + }); for entry in &files { let path = entry.path(); if path.is_dir() { missing_files.extend(explore_directory(&path)); } else { - let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string(); + let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string(); if let Some(ext) = path.extension() { match ext.to_str().unwrap() { - "rs" => current_file = file_stem.clone(), + "rs" => current_file = file_prefix.clone(), "stderr" | "stdout" => { - if file_stem != current_file { + if file_prefix != current_file { missing_files.push(path.to_str().unwrap().to_string()); } }, From 5edb02adad4bb05eb6c243ff02d4c23da51f4e82 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Mon, 1 Nov 2021 19:16:37 -0400 Subject: [PATCH 55/65] Fix #7903 --- clippy_utils/src/higher.rs | 20 ++++++++--- tests/ui/format_args.fixed | 12 +++++++ tests/ui/format_args.rs | 12 +++++++ tests/ui/format_args.stderr | 60 +++++++++++++++++++++---------- tests/ui/format_args_unfixable.rs | 1 + 5 files changed, 82 insertions(+), 23 deletions(-) diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index 7cbd43e6266e9..17ee6e0b56848 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -1,14 +1,14 @@ -//! This module contains functions that retrieves specifiec elements. +//! This module contains functions that retrieve specific elements. #![deny(clippy::missing_docs_in_private_items)] use crate::ty::is_type_diagnostic_item; -use crate::{is_expn_of, last_path_segment, match_def_path, paths}; +use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, 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, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp, + Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp, }; use rustc_lint::LateContext; use rustc_span::{sym, symbol, ExpnKind, Span, Symbol}; @@ -513,6 +513,8 @@ pub struct FormatArgsExpn<'tcx> { pub format_string_parts: &'tcx [Expr<'tcx>], /// Symbols corresponding to [`Self::format_string_parts`] pub format_string_symbols: Vec, + /// Match arm patterns, the `arg0`, etc. from the next field `args` + pub arg_names: &'tcx [Pat<'tcx>], /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)` pub args: &'tcx [Expr<'tcx>], /// The final argument passed to `Arguments::new_v1_formatted`, if applicable @@ -557,6 +559,7 @@ impl FormatArgsExpn<'tcx> { _ => None, }) .collect(); + if let PatKind::Tuple(arg_names, None) = arm.pat.kind; if let ExprKind::Array(args) = arm.body.kind; then { Some(FormatArgsExpn { @@ -564,6 +567,7 @@ impl FormatArgsExpn<'tcx> { value_args, format_string_parts, format_string_symbols, + arg_names, args, fmt_expr, }) @@ -587,9 +591,15 @@ impl FormatArgsExpn<'tcx> { 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; + if let Ok(i) = usize::try_from(position); + let arg = &self.args[i]; + if let ExprKind::Call(_, [arg_name, _]) = arg.kind; + if let Some(j) = self + .arg_names + .iter() + .position(|pat| path_to_local_id(arg_name, pat.hir_id)); then { - let i = usize::try_from(position).unwrap(); - Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) }) + Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) }) } else { None } diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index 8376566c4d62d..69b5e1c722e03 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -5,6 +5,7 @@ #![allow(unused_variables)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] +#![allow(clippy::print_literal)] #![warn(clippy::to_string_in_format_args)] use std::io::{stdout, Write}; @@ -97,9 +98,20 @@ fn main() { println!("{}", Z(1)); println!("{}", **x); println!("{}", ***x_ref); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{bar}", foo = "foo", bar = "bar"); + println!("{foo}{bar}", foo = "foo", bar = "bar"); + println!("{foo}{bar}", bar = "bar", foo = "foo"); + println!("{foo}{bar}", bar = "bar", foo = "foo"); + // negative tests println!("error: something failed at {}", Somewhere.to_string()); + // The next two tests are negative because caching the string might be faster than calling `::fmt` twice. println!("{} and again {0}", x.to_string()); + println!("{foo}{foo}", foo = "foo".to_string()); my_macro!(); println!("error: something failed at {}", my_other_macro!()); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{foo:?}", foo = "foo".to_string()); } diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index 164cc07066dc3..3a434c5bf002a 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -5,6 +5,7 @@ #![allow(unused_variables)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] +#![allow(clippy::print_literal)] #![warn(clippy::to_string_in_format_args)] use std::io::{stdout, Write}; @@ -97,9 +98,20 @@ fn main() { println!("{}", Z(1).to_string()); println!("{}", x.to_string()); println!("{}", x_ref.to_string()); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); + println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); + println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); + println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); + // negative tests println!("error: something failed at {}", Somewhere.to_string()); + // The next two tests are negative because caching the string might be faster than calling `::fmt` twice. println!("{} and again {0}", x.to_string()); + println!("{foo}{foo}", foo = "foo".to_string()); my_macro!(); println!("error: something failed at {}", my_other_macro!()); + // https://github.com/rust-lang/rust-clippy/issues/7903 + println!("{foo}{foo:?}", foo = "foo".to_string()); } diff --git a/tests/ui/format_args.stderr b/tests/ui/format_args.stderr index 9cfc97edeafb8..c0cbca507958d 100644 --- a/tests/ui/format_args.stderr +++ b/tests/ui/format_args.stderr @@ -1,5 +1,5 @@ error: `to_string` applied to a type that implements `Display` in `format!` args - --> $DIR/format_args.rs:75:72 + --> $DIR/format_args.rs:76:72 | LL | let _ = format!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this @@ -7,100 +7,124 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_ = 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 + --> $DIR/format_args.rs:80: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 + --> $DIR/format_args.rs:85: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 + --> $DIR/format_args.rs:87: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 + --> $DIR/format_args.rs:88: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 + --> $DIR/format_args.rs:89: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 + --> $DIR/format_args.rs:90: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 + --> $DIR/format_args.rs:91: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 + --> $DIR/format_args.rs:92: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 + --> $DIR/format_args.rs:93: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 + --> $DIR/format_args.rs:94: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 + --> $DIR/format_args.rs:95: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 + --> $DIR/format_args.rs:96: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 + --> $DIR/format_args.rs:97: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 + --> $DIR/format_args.rs:98: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 + --> $DIR/format_args.rs:99: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 + --> $DIR/format_args.rs:100:20 | LL | println!("{}", x_ref.to_string()); | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref` -error: aborting due to 17 previous errors +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:102:39 + | +LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:103:52 + | +LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:104:39 + | +LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); + | ^^^^^^^^^^^^ help: remove this + +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/format_args.rs:105:52 + | +LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); + | ^^^^^^^^^^^^ help: remove this + +error: aborting due to 21 previous errors diff --git a/tests/ui/format_args_unfixable.rs b/tests/ui/format_args_unfixable.rs index a8c06c2bde664..b24ddf7321e40 100644 --- a/tests/ui/format_args_unfixable.rs +++ b/tests/ui/format_args_unfixable.rs @@ -51,6 +51,7 @@ fn main() { assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); panic!("error: {}", format!("something failed at {}", Location::caller())); + // negative tests 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())); From ec456de2a32dcfd6b891548a0adfd93c6c46c790 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Tue, 2 Nov 2021 09:09:22 +0900 Subject: [PATCH 56/65] Small fixes for missing backticks in doc --- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index a62eb0699891b..cbe1c5d44d513 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// expression). /// /// ### Why is this bad? - /// Using the dedicated functions of the Option type is clearer and + /// Using the dedicated functions of the `Option` type is clearer and /// more concise than an `if let` expression. /// /// ### Known problems diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index a4680ae137b32..6447e3fa2ca08 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -13,7 +13,7 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for functions of type Result that contain `expect()` or `unwrap()` + /// Checks for functions of type `Result` that contain `expect()` or `unwrap()` /// /// ### Why is this bad? /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. From 3f84010688290e60465aa5eb936f45ffab454431 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 30 Oct 2021 12:02:20 +0200 Subject: [PATCH 57/65] Examine lifetimes in `OpaqueDef` bounds as well Fix #7893. --- clippy_lints/src/lifetimes.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index e5e6f8d25cc11..cb0b96e0652e5 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -378,11 +378,15 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(item, _) => { + TyKind::OpaqueDef(item, bounds) => { let map = self.cx.tcx.hir(); let item = map.item(item); walk_item(self, item); walk_ty(self, ty); + self.lts.extend(bounds.iter().filter_map(|bound| match bound { + GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)), + _ => None, + })); }, TyKind::BareFn(&BareFnTy { decl, .. }) => { let mut sub_visitor = RefVisitor::new(self.cx); From 9bcf966e35ad0ecff687c8a617ec6ba12dec2437 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 30 Oct 2021 12:11:45 +0200 Subject: [PATCH 58/65] Add test case for `clippy::needless_lifetimes` in async context Edition needs to be set to 2018 due to the use of `async`. --- tests/ui/needless_lifetimes.rs | 5 ++++ tests/ui/needless_lifetimes.stderr | 44 +++++++++++++++--------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 1d77382bf2cd1..b07c4a2381031 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -27,6 +27,11 @@ fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x } +// No error; multiple input refs +async fn func<'a>(args: &[&'a str]) -> Option<&'a str> { + args.get(0).cloned() +} + // No error; static involved. fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 33a6de1618d12..4114e6f1832fc 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -19,133 +19,133 @@ LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:45:1 + --> $DIR/needless_lifetimes.rs:50:1 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:50:1 + --> $DIR/needless_lifetimes.rs:55:1 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:62:1 + --> $DIR/needless_lifetimes.rs:67:1 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:86:1 + --> $DIR/needless_lifetimes.rs:91:1 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:116:5 + --> $DIR/needless_lifetimes.rs:121:5 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:125:5 + --> $DIR/needless_lifetimes.rs:130:5 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:144:1 + --> $DIR/needless_lifetimes.rs:149:1 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:174:1 + --> $DIR/needless_lifetimes.rs:179:1 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:180:1 + --> $DIR/needless_lifetimes.rs:185:1 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:199:1 + --> $DIR/needless_lifetimes.rs:204:1 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:207:1 + --> $DIR/needless_lifetimes.rs:212:1 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:243:1 + --> $DIR/needless_lifetimes.rs:248:1 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:250:9 + --> $DIR/needless_lifetimes.rs:255:9 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:254:9 + --> $DIR/needless_lifetimes.rs:259:9 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:267:9 + --> $DIR/needless_lifetimes.rs:272:9 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:296:5 + --> $DIR/needless_lifetimes.rs:301:5 | LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:299:5 + --> $DIR/needless_lifetimes.rs:304:5 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:308:5 + --> $DIR/needless_lifetimes.rs:313:5 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:320:5 + --> $DIR/needless_lifetimes.rs:325:5 | LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:335:5 + --> $DIR/needless_lifetimes.rs:340:5 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:348:5 + --> $DIR/needless_lifetimes.rs:353:5 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:351:5 + --> $DIR/needless_lifetimes.rs:356:5 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From db9e012927f485038d700fa67fd899401ceab1d5 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 2 Nov 2021 14:19:31 +0100 Subject: [PATCH 59/65] Update clippy dependencies * semver = "0.11" -> "1.0" * cargo_metadata = "0.12" -> "0.14" --- Cargo.toml | 4 ++-- clippy_lints/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed7fb1440139f..d475aaa3ee067 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,12 +22,12 @@ path = "src/driver.rs" [dependencies] clippy_lints = { version = "0.1", path = "clippy_lints" } -semver = "0.11" +semver = "1.0" rustc_tools_util = { version = "0.2", path = "rustc_tools_util" } tempfile = { version = "3.2", optional = true } [dev-dependencies] -cargo_metadata = "0.12" +cargo_metadata = "0.14" compiletest_rs = { version = "0.7", features = ["tmp"] } tester = "0.9" regex = "1.5" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index aaf9ac83d4900..281480b8d9491 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["clippy", "lint", "plugin"] edition = "2021" [dependencies] -cargo_metadata = "0.12" +cargo_metadata = "0.14" clippy_utils = { path = "../clippy_utils" } if_chain = "1.0" itertools = "0.10" @@ -21,7 +21,7 @@ serde_json = { version = "1.0", optional = true } toml = "0.5" unicode-normalization = "0.1" unicode-script = { version = "0.5", default-features = false } -semver = "0.11" +semver = "1.0" rustc-semver = "1.1" # NOTE: cargo requires serde feat in its url dep # see From a68c13563a975d93e657020f75146aca8851ae8e Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 2 Nov 2021 17:04:39 +0100 Subject: [PATCH 60/65] Use .cargo/config.toml instead of .cargo/config `.cargo/config.toml` is the preferred form for the local configuration file. This is emphasized in _The Cargo Book_ with the following note: > Note: Cargo also reads config files without the `.toml` extension, such > as `.cargo/config`. Support for the `.toml` extension was added in version > 1.39 and is the preferred form. Moreover, this helps with toml-aware text editors as they will recognize the file extension. --- .cargo/{config => config.toml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .cargo/{config => config.toml} (100%) diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml From 7f8198acad74c5a1596b28e51a08c2f5413840a3 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 2 Nov 2021 14:44:21 +0100 Subject: [PATCH 61/65] Advise to put a :: prefix inside the ticks --- clippy_lints/src/doc.rs | 14 +++++-- tests/ui/doc/doc.rs | 4 +- tests/ui/doc/doc.stderr | 82 +++++++++++++++++++++++++---------------- 3 files changed, 64 insertions(+), 36 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index ec67adf3f8766..44f7ee3b89a4a 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -689,10 +689,18 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str for word in text.split(|c: char| c.is_whitespace() || c == '\'') { // Trim punctuation as in `some comment (see foo::bar).` // ^^ - // Or even as in `_foo bar_` which is emphasized. - let word = word.trim_matches(|c: char| !c.is_alphanumeric()); + // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. + let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); - if valid_idents.contains(word) { + // Remove leading or trailing single `:` which may be part of a sentence. + if word.starts_with(':') && !word.starts_with("::") { + word = word.trim_start_matches(':'); + } + if word.ends_with(':') && !word.ends_with("::") { + word = word.trim_end_matches(':'); + } + + if valid_idents.contains(word) || word.chars().all(|c| c == ':') { continue; } diff --git a/tests/ui/doc/doc.rs b/tests/ui/doc/doc.rs index 342208e52b8e9..e40bb42bee284 100644 --- a/tests/ui/doc/doc.rs +++ b/tests/ui/doc/doc.rs @@ -8,7 +8,9 @@ /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun /// which should be reported only once despite being __doubly bad__. -/// Here be ::a::global:path. +/// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. +/// Import an item from ::awesome::global::blob:: (Intended postfix) +/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) /// That's not code ~NotInCodeBlock~. /// be_sure_we_got_to_the_end_of_it fn foo_bar() { diff --git a/tests/ui/doc/doc.stderr b/tests/ui/doc/doc.stderr index 7eab8a85f093d..3022e0bfc75aa 100644 --- a/tests/ui/doc/doc.stderr +++ b/tests/ui/doc/doc.stderr @@ -18,173 +18,191 @@ error: you should put `Foo::some_fun` between ticks in the documentation LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun | ^^^^^^^^^^^^^ -error: you should put `a::global:path` between ticks in the documentation - --> $DIR/doc.rs:11:15 +error: you should put `::a::global:path` between ticks in the documentation + --> $DIR/doc.rs:11:13 | -LL | /// Here be ::a::global:path. - | ^^^^^^^^^^^^^^ +LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. + | ^^^^^^^^^^^^^^^^ + +error: you should put `::another::global::path` between ticks in the documentation + --> $DIR/doc.rs:11:36 + | +LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: you should put `::awesome::global::blob::` between ticks in the documentation + --> $DIR/doc.rs:12:25 + | +LL | /// Import an item from ::awesome::global::blob:: (Intended postfix) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: you should put `::Cat` between ticks in the documentation + --> $DIR/doc.rs:13:31 + | +LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) + | ^^^^^ error: you should put `NotInCodeBlock` between ticks in the documentation - --> $DIR/doc.rs:12:22 + --> $DIR/doc.rs:14:22 | LL | /// That's not code ~NotInCodeBlock~. | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:13:5 + --> $DIR/doc.rs:15:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:27:5 + --> $DIR/doc.rs:29:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:34:5 + --> $DIR/doc.rs:36:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:48:5 + --> $DIR/doc.rs:50:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:71:5 + --> $DIR/doc.rs:73:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:75:22 + --> $DIR/doc.rs:77:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:78:21 + --> $DIR/doc.rs:80:21 | LL | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:88:5 + --> $DIR/doc.rs:90:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:96:8 + --> $DIR/doc.rs:98:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:99:7 + --> $DIR/doc.rs:101:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:101:22 + --> $DIR/doc.rs:103:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:102:5 + --> $DIR/doc.rs:104:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:109:5 + --> $DIR/doc.rs:111:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:122:5 + --> $DIR/doc.rs:124:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:133:43 + --> $DIR/doc.rs:135:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:138:5 + --> $DIR/doc.rs:140:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:139:1 + --> $DIR/doc.rs:141:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:144:43 + --> $DIR/doc.rs:146:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:149:5 + --> $DIR/doc.rs:151:5 | LL | And BarQuz too. | ^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:150:1 + --> $DIR/doc.rs:152:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:161:5 + --> $DIR/doc.rs:163:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:188:13 + --> $DIR/doc.rs:190:13 | LL | /// Not ok: http://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:189:13 + --> $DIR/doc.rs:191:13 | LL | /// Not ok: https://www.unicode.org | ^^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:190:13 + --> $DIR/doc.rs:192:13 | LL | /// Not ok: http://www.unicode.org/ | ^^^^^^^^^^^^^^^^^^^^^^ error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:191:13 + --> $DIR/doc.rs:193:13 | LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:194:22 + --> $DIR/doc.rs:196:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 31 previous errors +error: aborting due to 34 previous errors From 0db8c52291ee515b086d8826ac9beec3668aeb68 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sat, 30 Oct 2021 20:11:06 -0400 Subject: [PATCH 62/65] Add suggestion to missing backticks error --- clippy_lints/src/doc.rs | 25 ++-- tests/ui/doc/doc.fixed | 215 +++++++++++++++++++++++++++ tests/ui/doc/doc.rs | 15 +- tests/ui/doc/doc.stderr | 206 ++++++++++++------------- tests/ui/doc/issue_1832.rs | 9 ++ tests/ui/doc/issue_902.rs | 7 + tests/ui/doc/unbalanced_ticks.stderr | 12 +- 7 files changed, 344 insertions(+), 145 deletions(-) create mode 100644 tests/ui/doc/doc.fixed create mode 100644 tests/ui/doc/issue_1832.rs create mode 100644 tests/ui/doc/issue_902.rs diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 44f7ee3b89a4a..87ad5178ff088 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -1,6 +1,6 @@ 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::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg}; +use clippy_utils::source::{first_line_of_span, snippet_with_applicability}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty}; use if_chain::if_chain; @@ -10,7 +10,7 @@ use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; -use rustc_errors::Handler; +use rustc_errors::{Applicability, Handler}; use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{AnonConst, Expr, ExprKind, QPath}; @@ -48,7 +48,7 @@ declare_clippy_lint! { /// content are not linted. /// /// In addition, when writing documentation comments, including `[]` brackets - /// inside a link text would trip the parser. Therfore, documenting link with + /// inside a link text would trip the parser. Therefore, documenting link with /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec /// would fail. /// @@ -755,17 +755,22 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { } } - // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343) + // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) if has_underscore(word) && has_hyphen(word) { return; } if has_underscore(word) || word.contains("::") || is_camel_case(word) { - span_lint( + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_sugg( cx, DOC_MARKDOWN, span, - &format!("you should put `{}` between ticks in the documentation", word), + "item in documentation is missing backticks", + "try", + format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)), + applicability, ); } } @@ -804,9 +809,9 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option) - || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result) + let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) + || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) { self.panic_span = Some(expr.span); } diff --git a/tests/ui/doc/doc.fixed b/tests/ui/doc/doc.fixed new file mode 100644 index 0000000000000..747801b40ee10 --- /dev/null +++ b/tests/ui/doc/doc.fixed @@ -0,0 +1,215 @@ +// run-rustfix +//! This file tests for the `DOC_MARKDOWN` lint. + +#![allow(dead_code, incomplete_features)] +#![warn(clippy::doc_markdown)] +#![feature(custom_inner_attributes, generic_const_exprs, const_option)] +#![rustfmt::skip] + +/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there) +/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun` +/// which should be reported only once despite being __doubly bad__. +/// Here be `::a::global:path`, and _`::another::global::path`_. :: is not a path though. +/// Import an item from `::awesome::global::blob::` (Intended postfix) +/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted) +/// That's not code ~`NotInCodeBlock`~. +/// `be_sure_we_got_to_the_end_of_it` +fn foo_bar() { +} + +/// That one tests multiline ticks. +/// ```rust +/// foo_bar FOO_BAR +/// _foo bar_ +/// ``` +/// +/// ~~~rust +/// foo_bar FOO_BAR +/// _foo bar_ +/// ~~~ +/// `be_sure_we_got_to_the_end_of_it` +fn multiline_codeblock() { +} + +/// This _is a test for +/// multiline +/// emphasis_. +/// `be_sure_we_got_to_the_end_of_it` +fn test_emphasis() { +} + +/// This tests units. See also #835. +/// kiB MiB GiB TiB PiB EiB +/// kib Mib Gib Tib Pib Eib +/// kB MB GB TB PB EB +/// kb Mb Gb Tb Pb Eb +/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB +/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib +/// 32kB 32MB 32GB 32TB 32PB 32EB +/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb +/// NaN +/// `be_sure_we_got_to_the_end_of_it` +fn test_units() { +} + +/// This tests allowed identifiers. +/// KiB MiB GiB TiB PiB EiB +/// DirectX +/// ECMAScript +/// GPLv2 GPLv3 +/// GitHub GitLab +/// IPv4 IPv6 +/// ClojureScript CoffeeScript JavaScript PureScript TypeScript +/// NaN NaNs +/// OAuth GraphQL +/// OCaml +/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS +/// WebGL +/// TensorFlow +/// TrueType +/// iOS macOS FreeBSD +/// TeX LaTeX BibTeX BibLaTeX +/// MinGW +/// CamelCase (see also #2395) +/// `be_sure_we_got_to_the_end_of_it` +fn test_allowed() { +} + +/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823. +/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues) +/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link]. +/// It can also be [`inline_link2`]. +/// +/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example +/// [inline_link]: https://foobar +/// [inline_link2]: https://foobar +/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and +/// `multiline_ticks` functions. +/// +/// expression of the type `_ m c` (where `` +/// is one of {`&`, '|'} and `` is one of {`!=`, `>=`, `>` , +/// `be_sure_we_got_to_the_end_of_it` +fn main() { + foo_bar(); + multiline_codeblock(); + test_emphasis(); + test_units(); +} + +/// ## `CamelCaseThing` +/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897. +/// +/// # `CamelCaseThing` +/// +/// Not a title #897 `CamelCaseThing` +/// `be_sure_we_got_to_the_end_of_it` +fn issue897() { +} + +/// I am confused by brackets? (`x_y`) +/// I am confused by brackets? (foo `x_y`) +/// I am confused by brackets? (`x_y` foo) +/// `be_sure_we_got_to_the_end_of_it` +fn issue900() { +} + +/// Diesel queries also have a similar problem to [Iterator][iterator], where +/// /// More talking +/// returning them from a function requires exposing the implementation of that +/// function. The [`helper_types`][helper_types] module exists to help with this, +/// but you might want to hide the return type or have it conditionally change. +/// Boxing can achieve both. +/// +/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html +/// [helper_types]: ../helper_types/index.html +/// `be_sure_we_got_to_the_end_of_it` +fn issue883() { +} + +/// `foo_bar +/// baz_quz` +/// [foo +/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html) +fn multiline() { +} + +/** E.g., serialization of an empty list: `FooBar` +``` +That's in a code block: `PackedNode` +``` + +And `BarQuz` too. +`be_sure_we_got_to_the_end_of_it` +*/ +fn issue1073() { +} + +/** E.g., serialization of an empty list: `FooBar` +``` +That's in a code block: PackedNode +``` + +And `BarQuz` too. +`be_sure_we_got_to_the_end_of_it` +*/ +fn issue1073_alt() { +} + +/// Tests more than three quotes: +/// ```` +/// DoNotWarn +/// ``` +/// StillDont +/// ```` +/// `be_sure_we_got_to_the_end_of_it` +fn four_quotes() { +} + +#[cfg_attr(feature = "a", doc = " ```")] +#[cfg_attr(not(feature = "a"), doc = " ```ignore")] +/// fn main() { +/// let s = "localhost:10000".to_string(); +/// println!("{}", s); +/// } +/// ``` +fn issue_1469() {} + +/** + * This is a doc comment that should not be a list + *This would also be an error under a strict common mark interpretation + */ +fn issue_1920() {} + +/// An iterator over `mycrate::Collection`'s values. +/// It should not lint a `'static` lifetime in ticks. +fn issue_2210() {} + +/// This should not cause the lint to trigger: +/// #REQ-data-family.lint_partof_exists +fn issue_2343() {} + +/// This should not cause an ICE: +/// __|_ _|__||_| +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()]: { + arr: [T; N.checked_next_power_of_two().unwrap()], + n: usize, +} + +impl S +where [(); N.checked_next_power_of_two().unwrap()]: { + fn new() -> Self { + Self { + arr: [T::default(); N.checked_next_power_of_two().unwrap()], + n: 0, + } + } +} diff --git a/tests/ui/doc/doc.rs b/tests/ui/doc/doc.rs index e40bb42bee284..f3cf966157a63 100644 --- a/tests/ui/doc/doc.rs +++ b/tests/ui/doc/doc.rs @@ -1,3 +1,4 @@ +// run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] @@ -164,12 +165,6 @@ fn issue1073_alt() { fn four_quotes() { } -/// See [NIST SP 800-56A, revision 2]. -/// -/// [NIST SP 800-56A, revision 2]: -/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419 -fn issue_902_comment() {} - #[cfg_attr(feature = "a", doc = " ```")] #[cfg_attr(not(feature = "a"), doc = " ```ignore")] /// fn main() { @@ -185,14 +180,6 @@ fn issue_1469() {} */ fn issue_1920() {} -/// Ok: -/// -/// Not ok: http://www.unicode.org -/// Not ok: https://www.unicode.org -/// Not ok: http://www.unicode.org/ -/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels -fn issue_1832() {} - /// An iterator over mycrate::Collection's values. /// It should not lint a `'static` lifetime in ticks. fn issue_2210() {} diff --git a/tests/ui/doc/doc.stderr b/tests/ui/doc/doc.stderr index 3022e0bfc75aa..8a9e1d70a164e 100644 --- a/tests/ui/doc/doc.stderr +++ b/tests/ui/doc/doc.stderr @@ -1,208 +1,184 @@ -error: you should put `foo_bar` between ticks in the documentation - --> $DIR/doc.rs:8:9 +error: item in documentation is missing backticks + --> $DIR/doc.rs:9:9 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) - | ^^^^^^^ + | ^^^^^^^ help: try: ``foo_bar`` | = note: `-D clippy::doc-markdown` implied by `-D warnings` -error: you should put `foo::bar` between ticks in the documentation - --> $DIR/doc.rs:8:51 +error: item in documentation is missing backticks + --> $DIR/doc.rs:9:51 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) - | ^^^^^^^^ + | ^^^^^^^^ help: try: ``foo::bar`` -error: you should put `Foo::some_fun` between ticks in the documentation - --> $DIR/doc.rs:9:83 +error: item in documentation is missing backticks + --> $DIR/doc.rs:10:83 | LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: try: ``Foo::some_fun`` -error: you should put `::a::global:path` between ticks in the documentation - --> $DIR/doc.rs:11:13 +error: item in documentation is missing backticks + --> $DIR/doc.rs:12:13 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path`` -error: you should put `::another::global::path` between ticks in the documentation - --> $DIR/doc.rs:11:36 +error: item in documentation is missing backticks + --> $DIR/doc.rs:12:36 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path`` -error: you should put `::awesome::global::blob::` between ticks in the documentation - --> $DIR/doc.rs:12:25 +error: item in documentation is missing backticks + --> $DIR/doc.rs:13:25 | LL | /// Import an item from ::awesome::global::blob:: (Intended postfix) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::`` -error: you should put `::Cat` between ticks in the documentation - --> $DIR/doc.rs:13:31 +error: item in documentation is missing backticks + --> $DIR/doc.rs:14:31 | LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) - | ^^^^^ + | ^^^^^ help: try: ``::Cat`` -error: you should put `NotInCodeBlock` between ticks in the documentation - --> $DIR/doc.rs:14:22 +error: item in documentation is missing backticks + --> $DIR/doc.rs:15:22 | LL | /// That's not code ~NotInCodeBlock~. - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:15:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:16:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:29:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:30:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:36:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:37:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:50:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:51:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:73:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:74:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `link_with_underscores` between ticks in the documentation - --> $DIR/doc.rs:77:22 +error: item in documentation is missing backticks + --> $DIR/doc.rs:78:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores`` -error: you should put `inline_link2` between ticks in the documentation - --> $DIR/doc.rs:80:21 +error: item in documentation is missing backticks + --> $DIR/doc.rs:81:21 | LL | /// It can also be [inline_link2]. - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ help: try: ``inline_link2`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:90:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:91:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:98:8 +error: item in documentation is missing backticks + --> $DIR/doc.rs:99:8 | LL | /// ## CamelCaseThing - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` -error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:101:7 +error: item in documentation is missing backticks + --> $DIR/doc.rs:102:7 | LL | /// # CamelCaseThing - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` -error: you should put `CamelCaseThing` between ticks in the documentation - --> $DIR/doc.rs:103:22 +error: item in documentation is missing backticks + --> $DIR/doc.rs:104:22 | LL | /// Not a title #897 CamelCaseThing - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:104:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:105:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:111:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:112:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:124:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:125:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:135:43 +error: item in documentation is missing backticks + --> $DIR/doc.rs:136:43 | LL | /** E.g., serialization of an empty list: FooBar - | ^^^^^^ + | ^^^^^^ help: try: ``FooBar`` -error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:140:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:141:5 | LL | And BarQuz too. - | ^^^^^^ + | ^^^^^^ help: try: ``BarQuz`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:141:1 +error: item in documentation is missing backticks + --> $DIR/doc.rs:142:1 | LL | be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `FooBar` between ticks in the documentation - --> $DIR/doc.rs:146:43 +error: item in documentation is missing backticks + --> $DIR/doc.rs:147:43 | LL | /** E.g., serialization of an empty list: FooBar - | ^^^^^^ + | ^^^^^^ help: try: ``FooBar`` -error: you should put `BarQuz` between ticks in the documentation - --> $DIR/doc.rs:151:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:152:5 | LL | And BarQuz too. - | ^^^^^^ + | ^^^^^^ help: try: ``BarQuz`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:152:1 +error: item in documentation is missing backticks + --> $DIR/doc.rs:153:1 | LL | be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation - --> $DIR/doc.rs:163:5 +error: item in documentation is missing backticks + --> $DIR/doc.rs:164:5 | LL | /// be_sure_we_got_to_the_end_of_it - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:190:13 - | -LL | /// Not ok: http://www.unicode.org - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:191:13 - | -LL | /// Not ok: https://www.unicode.org - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:192:13 - | -LL | /// Not ok: http://www.unicode.org/ - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> $DIR/doc.rs:193:13 - | -LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you should put `mycrate::Collection` between ticks in the documentation - --> $DIR/doc.rs:196:22 +error: item in documentation is missing backticks + --> $DIR/doc.rs:183:22 | LL | /// An iterator over mycrate::Collection's values. - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection`` -error: aborting due to 34 previous errors +error: aborting due to 30 previous errors diff --git a/tests/ui/doc/issue_1832.rs b/tests/ui/doc/issue_1832.rs new file mode 100644 index 0000000000000..10586f16d466a --- /dev/null +++ b/tests/ui/doc/issue_1832.rs @@ -0,0 +1,9 @@ +/// Ok: +/// +/// Not ok: http://www.unicode.org +/// Not ok: https://www.unicode.org +/// Not ok: http://www.unicode.org/ +/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels +fn issue_1832() {} + +fn main() {} diff --git a/tests/ui/doc/issue_902.rs b/tests/ui/doc/issue_902.rs new file mode 100644 index 0000000000000..4b0c835dd3f07 --- /dev/null +++ b/tests/ui/doc/issue_902.rs @@ -0,0 +1,7 @@ +/// See [NIST SP 800-56A, revision 2]. +/// +/// [NIST SP 800-56A, revision 2]: +/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419 +fn issue_902_comment() {} + +fn main() {} diff --git a/tests/ui/doc/unbalanced_ticks.stderr b/tests/ui/doc/unbalanced_ticks.stderr index 45ca34e2a8c8b..9670e5c24fb3e 100644 --- a/tests/ui/doc/unbalanced_ticks.stderr +++ b/tests/ui/doc/unbalanced_ticks.stderr @@ -18,11 +18,11 @@ LL | /// This paragraph has `unbalanced_tick marks and should stop_linting. | = help: a backtick may be missing a pair -error: you should put `should_be` between ticks in the documentation +error: item in documentation is missing backticks --> $DIR/unbalanced_ticks.rs:15:32 | LL | /// This paragraph is fine and should_be linted normally. - | ^^^^^^^^^ + | ^^^^^^^^^ help: try: ``should_be`` error: backticks are unbalanced --> $DIR/unbalanced_ticks.rs:17:1 @@ -32,11 +32,11 @@ LL | /// Double unbalanced backtick from ``here to here` should lint. | = help: a backtick may be missing a pair -error: you should put `not_fine` between ticks in the documentation +error: item in documentation is missing backticks --> $DIR/unbalanced_ticks.rs:30:8 | LL | /// ## not_fine - | ^^^^^^^^ + | ^^^^^^^^ help: try: ``not_fine`` error: backticks are unbalanced --> $DIR/unbalanced_ticks.rs:32:1 @@ -54,11 +54,11 @@ LL | /// - This `item has unbalanced tick marks | = help: a backtick may be missing a pair -error: you should put `backticks_here` between ticks in the documentation +error: item in documentation is missing backticks --> $DIR/unbalanced_ticks.rs:35:23 | LL | /// - This item needs backticks_here - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: try: ``backticks_here`` error: aborting due to 8 previous errors From 3732d117da0b69adf4c2eb546e8b07b89409006b Mon Sep 17 00:00:00 2001 From: Serial Date: Tue, 2 Nov 2021 17:04:35 -0400 Subject: [PATCH 63/65] Specify fixable doc tests --- tests/ui/doc/{doc.fixed => doc-fixable.fixed} | 0 tests/ui/doc/{doc.rs => doc-fixable.rs} | 0 .../ui/doc/{doc.stderr => doc-fixable.stderr} | 60 +++++++++---------- 3 files changed, 30 insertions(+), 30 deletions(-) rename tests/ui/doc/{doc.fixed => doc-fixable.fixed} (100%) rename tests/ui/doc/{doc.rs => doc-fixable.rs} (100%) rename tests/ui/doc/{doc.stderr => doc-fixable.stderr} (85%) diff --git a/tests/ui/doc/doc.fixed b/tests/ui/doc/doc-fixable.fixed similarity index 100% rename from tests/ui/doc/doc.fixed rename to tests/ui/doc/doc-fixable.fixed diff --git a/tests/ui/doc/doc.rs b/tests/ui/doc/doc-fixable.rs similarity index 100% rename from tests/ui/doc/doc.rs rename to tests/ui/doc/doc-fixable.rs diff --git a/tests/ui/doc/doc.stderr b/tests/ui/doc/doc-fixable.stderr similarity index 85% rename from tests/ui/doc/doc.stderr rename to tests/ui/doc/doc-fixable.stderr index 8a9e1d70a164e..31132f86edbc4 100644 --- a/tests/ui/doc/doc.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -1,5 +1,5 @@ error: item in documentation is missing backticks - --> $DIR/doc.rs:9:9 + --> $DIR/doc-fixable.rs:9:9 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^ help: try: ``foo_bar`` @@ -7,175 +7,175 @@ LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot t = note: `-D clippy::doc-markdown` implied by `-D warnings` error: item in documentation is missing backticks - --> $DIR/doc.rs:9:51 + --> $DIR/doc-fixable.rs:9:51 | LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) | ^^^^^^^^ help: try: ``foo::bar`` error: item in documentation is missing backticks - --> $DIR/doc.rs:10:83 + --> $DIR/doc-fixable.rs:10:83 | LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun | ^^^^^^^^^^^^^ help: try: ``Foo::some_fun`` error: item in documentation is missing backticks - --> $DIR/doc.rs:12:13 + --> $DIR/doc-fixable.rs:12:13 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. | ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path`` error: item in documentation is missing backticks - --> $DIR/doc.rs:12:36 + --> $DIR/doc-fixable.rs:12:36 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path`` error: item in documentation is missing backticks - --> $DIR/doc.rs:13:25 + --> $DIR/doc-fixable.rs:13:25 | LL | /// Import an item from ::awesome::global::blob:: (Intended postfix) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::`` error: item in documentation is missing backticks - --> $DIR/doc.rs:14:31 + --> $DIR/doc-fixable.rs:14:31 | LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) | ^^^^^ help: try: ``::Cat`` error: item in documentation is missing backticks - --> $DIR/doc.rs:15:22 + --> $DIR/doc-fixable.rs:15:22 | LL | /// That's not code ~NotInCodeBlock~. | ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock`` error: item in documentation is missing backticks - --> $DIR/doc.rs:16:5 + --> $DIR/doc-fixable.rs:16:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:30:5 + --> $DIR/doc-fixable.rs:30:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:37:5 + --> $DIR/doc-fixable.rs:37:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:51:5 + --> $DIR/doc-fixable.rs:51:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:74:5 + --> $DIR/doc-fixable.rs:74:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:78:22 + --> $DIR/doc-fixable.rs:78:22 | LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823. | ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores`` error: item in documentation is missing backticks - --> $DIR/doc.rs:81:21 + --> $DIR/doc-fixable.rs:81:21 | LL | /// It can also be [inline_link2]. | ^^^^^^^^^^^^ help: try: ``inline_link2`` error: item in documentation is missing backticks - --> $DIR/doc.rs:91:5 + --> $DIR/doc-fixable.rs:91:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:99:8 + --> $DIR/doc-fixable.rs:99:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` error: item in documentation is missing backticks - --> $DIR/doc.rs:102:7 + --> $DIR/doc-fixable.rs:102:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` error: item in documentation is missing backticks - --> $DIR/doc.rs:104:22 + --> $DIR/doc-fixable.rs:104:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing`` error: item in documentation is missing backticks - --> $DIR/doc.rs:105:5 + --> $DIR/doc-fixable.rs:105:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:112:5 + --> $DIR/doc-fixable.rs:112:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:125:5 + --> $DIR/doc-fixable.rs:125:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:136:43 + --> $DIR/doc-fixable.rs:136:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ help: try: ``FooBar`` error: item in documentation is missing backticks - --> $DIR/doc.rs:141:5 + --> $DIR/doc-fixable.rs:141:5 | LL | And BarQuz too. | ^^^^^^ help: try: ``BarQuz`` error: item in documentation is missing backticks - --> $DIR/doc.rs:142:1 + --> $DIR/doc-fixable.rs:142:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:147:43 + --> $DIR/doc-fixable.rs:147:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ help: try: ``FooBar`` error: item in documentation is missing backticks - --> $DIR/doc.rs:152:5 + --> $DIR/doc-fixable.rs:152:5 | LL | And BarQuz too. | ^^^^^^ help: try: ``BarQuz`` error: item in documentation is missing backticks - --> $DIR/doc.rs:153:1 + --> $DIR/doc-fixable.rs:153:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:164:5 + --> $DIR/doc-fixable.rs:164:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it`` error: item in documentation is missing backticks - --> $DIR/doc.rs:183:22 + --> $DIR/doc-fixable.rs:183:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection`` From df9f5e4b22383fda0eac689aa27bed7633e2b5f5 Mon Sep 17 00:00:00 2001 From: lyj Date: Thu, 4 Nov 2021 11:57:14 +0800 Subject: [PATCH 64/65] Update diagnostics.rs --- clippy_utils/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 9302e5c21faa4..d47b002ad7aca 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -72,7 +72,7 @@ pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into( cx: &'a T, From c7f54624b24637f140b0de06fb6dfae149f288c3 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 4 Nov 2021 12:03:53 +0000 Subject: [PATCH 65/65] Bump nightly version -> 2021-11-04 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 67eaf286004f9..09554c08987b1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-10-21" +channel = "nightly-2021-11-04" components = ["llvm-tools-preview", "rustc-dev", "rust-src"]