]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/implicit_return.rs
Merge commit '0e87918536b9833bbc6c683d1f9d51ee2bf03ef1' into clippyup
[rust.git] / clippy_lints / src / implicit_return.rs
index 166f371e14602ef0c22aa62135f69b4d81a478bd..6863645a92dbeabbbc882296bdc08f6d5361f0ff 100644 (file)
@@ -1,17 +1,13 @@
-use crate::utils::{
-    match_def_path,
-    paths::{BEGIN_PANIC, BEGIN_PANIC_FMT},
-    snippet_opt, span_lint_and_then,
-};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::match_panic_def_id;
+use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
-use rustc::{
-    declare_lint_pass,
-    hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, StmtKind},
-    lint::{LateContext, LateLintPass, LintArray, LintPass},
-};
 use rustc_errors::Applicability;
-use rustc_session::declare_tool_lint;
-use syntax::source_map::Span;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, MatchSource, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for missing return statements at the end of a block.
 static LINT_BREAK: &str = "change `break` to `return` as shown";
 static LINT_RETURN: &str = "add `return` as shown";
 
-fn lint(cx: &LateContext<'_, '_>, outer_span: Span, inner_span: Span, msg: &str) {
+fn lint(cx: &LateContext<'_>, outer_span: Span, inner_span: Span, msg: &str) {
     let outer_span = outer_span.source_callsite();
     let inner_span = inner_span.source_callsite();
 
-    span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing return statement", |db| {
+    span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing `return` statement", |diag| {
         if let Some(snippet) = snippet_opt(cx, inner_span) {
-            db.span_suggestion(
+            diag.span_suggestion(
                 outer_span,
                 msg,
                 format!("return {}", snippet),
@@ -62,7 +58,7 @@ fn lint(cx: &LateContext<'_, '_>, outer_span: Span, inner_span: Span, msg: &str)
     });
 }
 
-fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
+fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) {
     match expr.kind {
         // loops could be using `break` instead of `return`
         ExprKind::Block(block, ..) | ExprKind::Loop(block, ..) => {
@@ -74,8 +70,7 @@ fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
                 if_chain! {
                     if let StmtKind::Semi(expr, ..) = &stmt.kind;
                     // make sure it's a break, otherwise we want to skip
-                    if let ExprKind::Break(.., break_expr) = &expr.kind;
-                    if let Some(break_expr) = break_expr;
+                    if let ExprKind::Break(.., Some(break_expr)) = &expr.kind;
                     then {
                             lint(cx, expr.span, break_expr.span, LINT_BREAK);
                     }
@@ -88,6 +83,13 @@ fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
                 lint(cx, expr.span, break_expr.span, LINT_BREAK);
             }
         },
+        ExprKind::If(.., if_expr, else_expr) => {
+            expr_match(cx, if_expr);
+
+            if let Some(else_expr) = else_expr {
+                expr_match(cx, else_expr);
+            }
+        },
         ExprKind::Match(.., arms, source) => {
             let check_all_arms = match source {
                 MatchSource::IfLetDesugar {
@@ -101,7 +103,7 @@ fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
                     expr_match(cx, &arm.body);
                 }
             } else {
-                expr_match(cx, &arms.first().expect("if let doesn't have a single arm").body);
+                expr_match(cx, &arms.first().expect("`if let` doesn't have a single arm").body);
             }
         },
         // skip if it already has a return statement
@@ -110,9 +112,8 @@ fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
         ExprKind::Call(expr, ..) => {
             if_chain! {
                 if let ExprKind::Path(qpath) = &expr.kind;
-                if let Some(path_def_id) = cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id();
-                if match_def_path(cx, path_def_id, &BEGIN_PANIC) ||
-                    match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT);
+                if let Some(path_def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id();
+                if match_panic_def_id(cx, path_def_id);
                 then { }
                 else {
                     lint(cx, expr.span, expr.span, LINT_RETURN)
@@ -124,23 +125,23 @@ fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
     }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
+impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
     fn check_fn(
         &mut self,
-        cx: &LateContext<'a, 'tcx>,
+        cx: &LateContext<'tcx>,
         _: FnKind<'tcx>,
-        _: &'tcx FnDecl,
+        _: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
         _: HirId,
     ) {
-        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
-        let mir = cx.tcx.optimized_mir(def_id);
-
-        // checking return type through MIR, HIR is not able to determine inferred closure return types
-        // make sure it's not a macro
-        if !mir.return_ty().is_unit() && !span.from_expansion() {
-            expr_match(cx, &body.value);
+        if span.from_expansion() {
+            return;
+        }
+        let body = cx.tcx.hir().body(body.id());
+        if cx.typeck_results().expr_ty(&body.value).is_unit() {
+            return;
         }
+        expr_match(cx, &body.value);
     }
 }