From bfcc8ba444180dfc12bb113d1d500b81c9e87956 Mon Sep 17 00:00:00 2001
From: Catherine <114838443+Centri3@users.noreply.github.com>
Date: Sat, 24 Jun 2023 07:40:09 -0500
Subject: [PATCH] New lint `tuple_array_conversions`
---
CHANGELOG.md | 1 +
clippy_lints/src/declared_lints.rs | 1 +
clippy_lints/src/lib.rs | 2 +
clippy_lints/src/tuple_array_conversions.rs | 187 ++++++++++++++++++++
tests/ui/tuple_array_conversions.rs | 43 +++++
tests/ui/tuple_array_conversions.stderr | 59 ++++++
6 files changed, 293 insertions(+)
create mode 100644 clippy_lints/src/tuple_array_conversions.rs
create mode 100644 tests/ui/tuple_array_conversions.rs
create mode 100644 tests/ui/tuple_array_conversions.stderr
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4debe304857..04917871c40 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5262,6 +5262,7 @@ Released 2018-09-13
[`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
[`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
+[`tuple_array_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions
[`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
[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 46f4082f0c7..316645e4066 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -624,6 +624,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO,
crate::transmute::USELESS_TRANSMUTE_INFO,
crate::transmute::WRONG_TRANSMUTE_INFO,
+ crate::tuple_array_conversions::TUPLE_ARRAY_CONVERSIONS_INFO,
crate::types::BORROWED_BOX_INFO,
crate::types::BOX_COLLECTION_INFO,
crate::types::LINKEDLIST_INFO,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 5ab28b5c70c..39301b5344a 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -311,6 +311,7 @@ mod to_digit_is_some;
mod trailing_empty_array;
mod trait_bounds;
mod transmute;
+mod tuple_array_conversions;
mod types;
mod undocumented_unsafe_blocks;
mod unicode;
@@ -1072,6 +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));
// 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
new file mode 100644
index 00000000000..9640083f764
--- /dev/null
+++ b/clippy_lints/src/tuple_array_conversions.rs
@@ -0,0 +1,187 @@
+use clippy_utils::{diagnostics::span_lint_and_help, is_from_proc_macro, path_to_local};
+use rustc_hir::*;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::{lint::in_external_macro, ty};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// ### Why is this bad?
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let t1 = &[(1, 2), (3, 4)];
+ /// let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect();
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// let t1 = &[(1, 2), (3, 4)];
+ /// let v1: Vec<[u32; 2]> = t1.iter().map(|&t| t.into()).collect();
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub TUPLE_ARRAY_CONVERSIONS,
+ complexity,
+ "default lint description"
+}
+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) {
+ _ = check_array(cx, expr) || check_tuple(cx, expr);
+ }
+ }
+}
+
+fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+ let ExprKind::Array(elements) = expr.kind else {
+ return false;
+ };
+ if !(1..=12).contains(&elements.len()) {
+ 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(_),
+ ),
+ )
+ })
+ {
+ return emit_lint(cx, expr, ToType::Array);
+ }
+
+ if let Some(elements) = elements
+ .iter()
+ .map(|expr| {
+ if let ExprKind::Field(path, _) = expr.kind {
+ return Some(path);
+ };
+
+ None
+ })
+ .collect::