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