Skip to content

Commit

Permalink
Fix implicit_return suggestion for async functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarcho committed Apr 2, 2021
1 parent 55ab1be commit 267834e
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 19 deletions.
11 changes: 10 additions & 1 deletion clippy_lints/src/implicit_return.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -216,6 +217,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);
}
}
38 changes: 36 additions & 2 deletions clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{
def, Arm, BindingAnnotation, Block, Body, Constness, CrateItem, Expr, ExprKind, FieldDef, FnDecl, ForeignItem,
GenericArgs, GenericParam, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Local,
GenericArgs, GenericParam, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Lifetime, Local,
MacroDef, MatchSource, Node, Param, Pat, PatKind, Path, PathSegment, QPath, Stmt, TraitItem, TraitItemKind,
TraitRef, TyKind, Variant, Visibility,
};
Expand Down Expand Up @@ -1222,6 +1222,40 @@ pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
)
}

/// 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 attribute with the given name, if any
pub fn attr_by_name<'a>(attrs: &'a [Attribute], name: &'_ str) -> Option<&'a Attribute> {
attrs
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/implicit_return.fixed
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// edition:2018
// run-rustfix

#![warn(clippy::implicit_return)]
Expand Down Expand Up @@ -122,4 +123,9 @@ fn divergent_test() -> bool {
diverge()
}

// issue #6940
async fn foo() -> bool {
return true
}

fn main() {}
6 changes: 6 additions & 0 deletions tests/ui/implicit_return.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// edition:2018
// run-rustfix

#![warn(clippy::implicit_return)]
Expand Down Expand Up @@ -122,4 +123,9 @@ fn divergent_test() -> bool {
diverge()
}

// issue #6940
async fn foo() -> bool {
true
}

fn main() {}
38 changes: 22 additions & 16 deletions tests/ui/implicit_return.stderr
Original file line number Diff line number Diff line change
@@ -1,91 +1,91 @@
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`
|
= 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);
Expand All @@ -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

0 comments on commit 267834e

Please sign in to comment.