From 4743ec19489702b0c09adf684f7d9d8a9bcfdb10 Mon Sep 17 00:00:00 2001
From: LeSeulArtichaut <leseulartichaut@gmail.com>
Date: Thu, 5 Aug 2021 15:38:57 +0200
Subject: [PATCH] Don't emit `too_many_lines` for closures

---
 clippy_lints/src/functions/mod.rs            |  2 +-
 clippy_lints/src/functions/too_many_lines.rs | 13 ++++++++--
 tests/ui-toml/functions_maxlines/test.rs     | 16 ++++++++++++
 tests/ui-toml/functions_maxlines/test.stderr | 26 +++++++++++++++++---
 4 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs
index ce23c0ce4a0..04fc5887e8e 100644
--- a/clippy_lints/src/functions/mod.rs
+++ b/clippy_lints/src/functions/mod.rs
@@ -251,7 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         hir_id: hir::HirId,
     ) {
         too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
-        too_many_lines::check_fn(cx, span, body, self.too_many_lines_threshold);
+        too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
     }
 
diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs
index a666fee1a4a..008ef661b55 100644
--- a/clippy_lints/src/functions/too_many_lines.rs
+++ b/clippy_lints/src/functions/too_many_lines.rs
@@ -1,4 +1,5 @@
 use rustc_hir as hir;
+use rustc_hir::intravisit::FnKind;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_span::Span;
@@ -8,8 +9,16 @@ use clippy_utils::source::snippet_opt;
 
 use super::TOO_MANY_LINES;
 
-pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'_>, too_many_lines_threshold: u64) {
-    if in_external_macro(cx.sess(), span) {
+pub(super) fn check_fn(
+    cx: &LateContext<'_>,
+    kind: FnKind<'tcx>,
+    span: Span,
+    body: &'tcx hir::Body<'_>,
+    too_many_lines_threshold: u64,
+) {
+    // Closures must be contained in a parent body, which will be checked for `too_many_lines`.
+    // Don't check closures for `too_many_lines` to avoid duplicated lints.
+    if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) {
         return;
     }
 
diff --git a/tests/ui-toml/functions_maxlines/test.rs b/tests/ui-toml/functions_maxlines/test.rs
index a47677a1f3a..33a3ef75136 100644
--- a/tests/ui-toml/functions_maxlines/test.rs
+++ b/tests/ui-toml/functions_maxlines/test.rs
@@ -1,3 +1,5 @@
+// edition:2018
+
 #![warn(clippy::too_many_lines)]
 
 // This function should be considered one line.
@@ -20,6 +22,20 @@ fn too_many_lines() {
     println!("This is bad.");
 }
 
+// This should only fail once (#7517).
+async fn async_too_many_lines() {
+    println!("This is bad.");
+    println!("This is bad.");
+}
+
+// This should fail only once, without failing on the closure.
+fn closure_too_many_lines() {
+    let _ = {
+        println!("This is bad.");
+        println!("This is bad.");
+    };
+}
+
 // This should be considered one line.
 #[rustfmt::skip]
 fn comment_starts_after_code() {
diff --git a/tests/ui-toml/functions_maxlines/test.stderr b/tests/ui-toml/functions_maxlines/test.stderr
index a27ce945ca5..7551cac9f50 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:18:1
+  --> $DIR/test.rs:20:1
    |
 LL | / fn too_many_lines() {
 LL | |     println!("This is bad.");
@@ -9,8 +9,28 @@ 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
+   |
+LL | / async fn async_too_many_lines() {
+LL | |     println!("This is bad.");
+LL | |     println!("This is bad.");
+LL | | }
+   | |_^
+
+error: this function has too many lines (4/1)
+  --> $DIR/test.rs:32:1
+   |
+LL | / fn closure_too_many_lines() {
+LL | |     let _ = {
+LL | |         println!("This is bad.");
+LL | |         println!("This is bad.");
+LL | |     };
+LL | | }
+   | |_^
+
 error: this function has too many lines (2/1)
-  --> $DIR/test.rs:38:1
+  --> $DIR/test.rs:54:1
    |
 LL | / fn comment_before_code() {
 LL | |     let _ = "test";
@@ -19,5 +39,5 @@ LL | |     the code but this line should still count. */ let _ = 5;
 LL | | }
    | |_^
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors