about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2021-04-02 17:53:14 -0400
committerJason Newcomb <jsnewcomb@pm.me>2021-04-22 09:36:32 -0400
commit74cf5f2fc6c121ae0eaaa709c9a303cd82fe9b30 (patch)
tree5403c9c05fb5f9ef0fb91197b73bd41b3e53faf2
parent22f8c13cf5650d6c9d6ee7b4f0e88bffba9076ca (diff)
downloadrust-74cf5f2fc6c121ae0eaaa709c9a303cd82fe9b30.tar.gz
rust-74cf5f2fc6c121ae0eaaa709c9a303cd82fe9b30.zip
Fix `implicit_return` suggestion for async functions
-rw-r--r--clippy_lints/src/implicit_return.rs11
-rw-r--r--clippy_utils/src/lib.rs40
-rw-r--r--tests/ui/implicit_return.fixed6
-rw-r--r--tests/ui/implicit_return.rs6
-rw-r--r--tests/ui/implicit_return.stderr38
5 files changed, 81 insertions, 20 deletions
diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs
index 251a7361871..39612dbf050 100644
--- a/clippy_lints/src/implicit_return.rs
+++ b/clippy_lints/src/implicit_return.rs
@@ -1,5 +1,6 @@
 use clippy_utils::{
     diagnostics::span_lint_and_sugg,
+    get_async_fn_body, is_async_fn,
     source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
     visitors::visit_break_exprs,
 };
@@ -219,6 +220,14 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
             return;
         }
 
-        lint_implicit_returns(cx, &body.value, body.value.span.ctxt(), None);
+        let expr = if is_async_fn(kind) {
+            match get_async_fn_body(cx.tcx, body) {
+                Some(e) => e,
+                None => return,
+            }
+        } else {
+            &body.value
+        };
+        lint_implicit_returns(cx, expr, expr.span.ctxt(), None);
     }
 }
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index b7017411927..6dc96e51a6b 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -60,12 +60,12 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_hir::intravisit::{self, walk_expr, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::LangItem::{ResultErr, ResultOk};
 use rustc_hir::{
     def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
-    ImplItem, ImplItemKind, Item, ItemKind, LangItem, Local, MatchSource, Node, Param, Pat, PatKind, Path, PathSegment,
-    QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
+    ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Node, Param, Pat, PatKind, Path,
+    PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::exports::Export;
@@ -1300,6 +1300,40 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
     (conds, blocks)
 }
 
+/// Checks if the given function kind is an async function.
+pub fn is_async_fn(kind: FnKind) -> bool {
+    matches!(kind, FnKind::ItemFn(_, _, header, _) if header.asyncness == IsAsync::Async)
+}
+
+/// Peels away all the compiler generated code surrounding the body of an async function,
+pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
+    if let ExprKind::Call(
+        _,
+        &[Expr {
+            kind: ExprKind::Closure(_, _, body, _, _),
+            ..
+        }],
+    ) = body.value.kind
+    {
+        if let ExprKind::Block(
+            Block {
+                stmts: [],
+                expr:
+                    Some(Expr {
+                        kind: ExprKind::DropTemps(expr),
+                        ..
+                    }),
+                ..
+            },
+            _,
+        ) = tcx.hir().body(body).value.kind
+        {
+            return Some(expr);
+        }
+    };
+    None
+}
+
 // Finds the `#[must_use]` attribute, if any
 pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
     attrs.iter().find(|a| a.has_name(sym::must_use))
diff --git a/tests/ui/implicit_return.fixed b/tests/ui/implicit_return.fixed
index c0fc4b926a0..7698b88a88c 100644
--- a/tests/ui/implicit_return.fixed
+++ b/tests/ui/implicit_return.fixed
@@ -1,3 +1,4 @@
+// edition:2018
 // run-rustfix
 
 #![warn(clippy::implicit_return)]
@@ -122,4 +123,9 @@ fn divergent_test() -> bool {
     diverge()
 }
 
+// issue #6940
+async fn foo() -> bool {
+    return true
+}
+
 fn main() {}
diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs
index 737ffd5ddce..45bbc2ec670 100644
--- a/tests/ui/implicit_return.rs
+++ b/tests/ui/implicit_return.rs
@@ -1,3 +1,4 @@
+// edition:2018
 // run-rustfix
 
 #![warn(clippy::implicit_return)]
@@ -122,4 +123,9 @@ fn divergent_test() -> bool {
     diverge()
 }
 
+// issue #6940
+async fn foo() -> bool {
+    true
+}
+
 fn main() {}
diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr
index 632e30cbdc6..16fe9ed444f 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:12:5
+  --> $DIR/implicit_return.rs:13: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:16:15
+  --> $DIR/implicit_return.rs:17:15
    |
 LL |     if true { true } else { false }
    |               ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:16:29
+  --> $DIR/implicit_return.rs:17:29
    |
 LL |     if true { true } else { false }
    |                             ^^^^^ help: add `return` as shown: `return false`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:22:17
+  --> $DIR/implicit_return.rs:23:17
    |
 LL |         true => false,
    |                 ^^^^^ help: add `return` as shown: `return false`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:23:20
+  --> $DIR/implicit_return.rs:24:20
    |
 LL |         false => { true },
    |                    ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:36:9
+  --> $DIR/implicit_return.rs:37:9
    |
 LL |         break true;
    |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:43:13
+  --> $DIR/implicit_return.rs:44:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:51:13
+  --> $DIR/implicit_return.rs:52:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:69:18
+  --> $DIR/implicit_return.rs:70:18
    |
 LL |     let _ = || { true };
    |                  ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:70:16
+  --> $DIR/implicit_return.rs:71:16
    |
 LL |     let _ = || true;
    |                ^^^^ help: add `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:78:5
+  --> $DIR/implicit_return.rs:79:5
    |
 LL |     format!("test {}", "test")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:87:5
+  --> $DIR/implicit_return.rs:88:5
    |
 LL |     m!(true, false)
    |     ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:93:13
+  --> $DIR/implicit_return.rs:94:13
    |
 LL |             break true;
    |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:98:17
+  --> $DIR/implicit_return.rs:99:17
    |
 LL |                 break 'outer false;
    |                 ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
 
 error: missing `return` statement
-  --> $DIR/implicit_return.rs:113:5
+  --> $DIR/implicit_return.rs:114:5
    |
 LL | /     loop {
 LL | |         m!(true);
@@ -99,5 +99,11 @@ LL |         m!(true);
 LL |     }
    |
 
-error: aborting due to 15 previous errors
+error: missing `return` statement
+  --> $DIR/implicit_return.rs:128:5
+   |
+LL |     true
+   |     ^^^^ help: add `return` as shown: `return true`
+
+error: aborting due to 16 previous errors