]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/multi_assignments.rs
Merge commit '1480cea393d0cee195e59949eabdfbcf1230f7f9' into clippyup
[rust.git] / src / tools / clippy / clippy_lints / src / multi_assignments.rs
1 use clippy_utils::diagnostics::span_lint;
2 use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind};
3 use rustc_lint::{EarlyContext, EarlyLintPass};
4 use rustc_session::{declare_lint_pass, declare_tool_lint};
5
6 declare_clippy_lint! {
7     /// ### What it does
8     /// Checks for nested assignments.
9     ///
10     /// ### Why is this bad?
11     /// While this is in most cases already a type mismatch,
12     /// the result of an assignment being `()` can throw off people coming from languages like python or C,
13     /// where such assignments return a copy of the assigned value.
14     ///
15     /// ### Example
16     /// ```rust
17     ///# let (a, b);
18     /// a = b = 42;
19     /// ```
20     /// Use instead:
21     /// ```rust
22     ///# let (a, b);
23     /// b = 42;
24     /// a = b;
25     /// ```
26     #[clippy::version = "1.65.0"]
27     pub MULTI_ASSIGNMENTS,
28     suspicious,
29     "instead of using `a = b = c;` use `a = c; b = c;`"
30 }
31
32 declare_lint_pass!(MultiAssignments => [MULTI_ASSIGNMENTS]);
33
34 fn strip_paren_blocks(expr: &Expr) -> &Expr {
35     match &expr.kind {
36         ExprKind::Paren(e) => strip_paren_blocks(e),
37         ExprKind::Block(b, _) => {
38             if let [
39                 Stmt {
40                     kind: StmtKind::Expr(e),
41                     ..
42                 },
43             ] = &b.stmts[..]
44             {
45                 strip_paren_blocks(e)
46             } else {
47                 expr
48             }
49         },
50         _ => expr,
51     }
52 }
53
54 impl EarlyLintPass for MultiAssignments {
55     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
56         if let ExprKind::Assign(target, source, _) = &expr.kind {
57             if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(target).kind {
58                 span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
59             };
60             if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(source).kind {
61                 span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
62             }
63         };
64     }
65 }