]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/semicolon_if_nothing_returned.rs
Auto merge of #6914 - camsteffen:source-utils, r=Manishearth
[rust.git] / clippy_lints / src / semicolon_if_nothing_returned.rs
1 use crate::utils::{in_macro, span_lint_and_sugg, sugg};
2 use clippy_utils::source::snippet_with_macro_callsite;
3 use if_chain::if_chain;
4 use rustc_errors::Applicability;
5 use rustc_hir::{Block, ExprKind};
6 use rustc_lint::{LateContext, LateLintPass};
7 use rustc_session::{declare_lint_pass, declare_tool_lint};
8
9 declare_clippy_lint! {
10     /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()`
11     /// but is not followed by a semicolon.
12     ///
13     /// **Why is this bad?** The semicolon might be optional but when
14     /// extending the block with new code, it doesn't require a change in previous last line.
15     ///
16     /// **Known problems:** None.
17     ///
18     /// **Example:**
19     ///
20     /// ```rust
21     /// fn main() {
22     ///     println!("Hello world")
23     /// }
24     /// ```
25     /// Use instead:
26     /// ```rust
27     /// fn main() {
28     ///     println!("Hello world");
29     /// }
30     /// ```
31     pub SEMICOLON_IF_NOTHING_RETURNED,
32     restriction,
33     "add a semicolon if nothing is returned"
34 }
35
36 declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]);
37
38 impl LateLintPass<'_> for SemicolonIfNothingReturned {
39     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
40         if_chain! {
41             if !in_macro(block.span);
42             if let Some(expr) = block.expr;
43             let t_expr = cx.typeck_results().expr_ty(expr);
44             if t_expr.is_unit();
45             if let snippet = snippet_with_macro_callsite(cx, expr.span, "}");
46             if !snippet.ends_with('}');
47             then {
48                 // filter out the desugared `for` loop
49                 if let ExprKind::DropTemps(..) = &expr.kind {
50                     return;
51                 }
52
53                 let sugg = sugg::Sugg::hir_with_macro_callsite(cx, &expr, "..");
54                 let suggestion = format!("{0};", sugg);
55                 span_lint_and_sugg(
56                     cx,
57                     SEMICOLON_IF_NOTHING_RETURNED,
58                     expr.span.source_callsite(),
59                     "consider adding a `;` to the last statement for consistent formatting",
60                     "add a `;` here",
61                     suggestion,
62                     Applicability::MaybeIncorrect,
63                 );
64             }
65         }
66     }
67 }