diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 39301b5344a..87329ee5e14 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -1073,7 +1073,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
store.register_early_pass(|| Box::new(visibility::Visibility));
- store.register_late_pass(|_| Box::new(tuple_array_conversions::TupleArrayConversions));
+ store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
// add lints here, do not remove this comment, it's used in `new_lint`
}
diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs
index 9640083f764..9d5e872bd78 100644
--- a/clippy_lints/src/tuple_array_conversions.rs
+++ b/clippy_lints/src/tuple_array_conversions.rs
@@ -1,13 +1,23 @@
-use clippy_utils::{diagnostics::span_lint_and_help, is_from_proc_macro, path_to_local};
-use rustc_hir::*;
+use clippy_utils::{
+ diagnostics::span_lint_and_help,
+ is_from_proc_macro,
+ msrvs::{self, Msrv},
+ path_to_local,
+};
+use itertools::Itertools;
+use rustc_hir::{Expr, ExprKind, Node, Pat};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::{lint::in_external_macro, ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use std::iter::once;
declare_clippy_lint! {
/// ### What it does
+ /// Checks for tuple<=>array conversions that are not done with `.into()`.
///
/// ### Why is this bad?
+ /// It's overly complex. `.into()` works for tuples<=>arrays with less than 13 elements and
+ /// conveys the intent a lot better, while also leaving less room for bugs!
///
/// ### Example
/// ```rust,ignore
@@ -22,16 +32,23 @@ declare_clippy_lint! {
#[clippy::version = "1.72.0"]
pub TUPLE_ARRAY_CONVERSIONS,
complexity,
- "default lint description"
+ "checks for tuple<=>array conversions that are not done with `.into()`"
+}
+impl_lint_pass!(TupleArrayConversions => [TUPLE_ARRAY_CONVERSIONS]);
+
+#[derive(Clone)]
+pub struct TupleArrayConversions {
+ pub msrv: Msrv,
}
-declare_lint_pass!(TupleArrayConversions => [TUPLE_ARRAY_CONVERSIONS]);
impl LateLintPass<'_> for TupleArrayConversions {
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if !in_external_macro(cx.sess(), expr.span) {
+ if !in_external_macro(cx.sess(), expr.span) && self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
_ = check_array(cx, expr) || check_tuple(cx, expr);
}
}
+
+ extract_msrv_attr!(LateContext);
}
fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
@@ -42,15 +59,22 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
return false;
}
- if let Some(locals) = path_to_locals(cx, elements)
- && locals.iter().all(|local| {
- matches!(
- local,
- Node::Pat(pat) if matches!(
- cx.typeck_results().pat_ty(backtrack_pat(cx, pat)).peel_refs().kind(),
- ty::Tuple(_),
- ),
- )
+ if let Some(locals) = path_to_locals(cx, &elements.iter().collect_vec())
+ && let [first, rest @ ..] = &*locals
+ && let Node::Pat(first_pat) = first
+ && let first_id = parent_pat(cx, first_pat).hir_id
+ && rest.iter().chain(once(first)).all(|local| {
+ if let Node::Pat(pat) = local
+ && let parent = parent_pat(cx, pat)
+ && parent.hir_id == first_id
+ {
+ return matches!(
+ cx.typeck_results().pat_ty(parent).peel_refs().kind(),
+ ty::Tuple(len) if len.len() == elements.len()
+ );
+ }
+
+ false
})
{
return emit_lint(cx, expr, ToType::Array);
@@ -66,15 +90,22 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
None
})
.collect::