Skip to content

Commit 21f103a

Browse files
committed
Auto merge of #9379 - royrustdev:multi_assignments, r=llogiq
new lint This fixes #6576 If you added a new lint, here's a checklist for things that will be checked during review or continuous integration. - \[x] Followed [lint naming conventions][lint_naming] - \[x] Added passing UI tests (including committed `.stderr` file) - \[x] `cargo test` passes locally - \[x] Executed `cargo dev update_lints` - \[x] Added lint documentation - \[x] Run `cargo dev fmt` --- changelog: add [`multi_assignments`] lint
2 parents 79a439a + fb7dffe commit 21f103a

8 files changed

+120
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3897,6 +3897,7 @@ Released 2018-09-13
38973897
[`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
38983898
[`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
38993899
[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
3900+
[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
39003901
[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
39013902
[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
39023903
[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate

clippy_lints/src/lib.register_all.rs

+1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
232232
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
233233
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
234234
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
235+
LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
235236
LintId::of(mut_key::MUTABLE_KEY_TYPE),
236237
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
237238
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),

clippy_lints/src/lib.register_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ store.register_lints(&[
398398
mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
399399
module_style::MOD_MODULE_FILES,
400400
module_style::SELF_NAMED_MODULE_FILES,
401+
multi_assignments::MULTI_ASSIGNMENTS,
401402
mut_key::MUTABLE_KEY_TYPE,
402403
mut_mut::MUT_MUT,
403404
mut_reference::UNNECESSARY_MUT_PASSED,

clippy_lints/src/lib.register_suspicious.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
2424
LintId::of(loops::MUT_RANGE_BOUND),
2525
LintId::of(methods::NO_EFFECT_REPLACE),
2626
LintId::of(methods::SUSPICIOUS_MAP),
27+
LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
2728
LintId::of(mut_key::MUTABLE_KEY_TYPE),
2829
LintId::of(octal_escapes::OCTAL_ESCAPES),
2930
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ mod missing_enforced_import_rename;
289289
mod missing_inline;
290290
mod mixed_read_write_in_expression;
291291
mod module_style;
292+
mod multi_assignments;
292293
mod mut_key;
293294
mod mut_mut;
294295
mod mut_reference;
@@ -896,6 +897,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
896897
store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone));
897898
store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew));
898899
store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable));
900+
store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
899901
// add lints here, do not remove this comment, it's used in `new_lint`
900902
}
901903

clippy_lints/src/multi_assignments.rs

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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+
}

tests/ui/multi_assignments.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![warn(clippy::multi_assignments)]
2+
fn main() {
3+
let (mut a, mut b, mut c, mut d) = ((), (), (), ());
4+
a = b = c;
5+
a = b = c = d;
6+
a = b = { c };
7+
a = { b = c };
8+
a = (b = c);
9+
}

tests/ui/multi_assignments.stderr

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: assignments don't nest intuitively
2+
--> $DIR/multi_assignments.rs:4:5
3+
|
4+
LL | a = b = c;
5+
| ^^^^^^^^^
6+
|
7+
= note: `-D clippy::multi-assignments` implied by `-D warnings`
8+
9+
error: assignments don't nest intuitively
10+
--> $DIR/multi_assignments.rs:5:5
11+
|
12+
LL | a = b = c = d;
13+
| ^^^^^^^^^^^^^
14+
15+
error: assignments don't nest intuitively
16+
--> $DIR/multi_assignments.rs:5:9
17+
|
18+
LL | a = b = c = d;
19+
| ^^^^^^^^^
20+
21+
error: assignments don't nest intuitively
22+
--> $DIR/multi_assignments.rs:6:5
23+
|
24+
LL | a = b = { c };
25+
| ^^^^^^^^^^^^^
26+
27+
error: assignments don't nest intuitively
28+
--> $DIR/multi_assignments.rs:7:5
29+
|
30+
LL | a = { b = c };
31+
| ^^^^^^^^^^^^^
32+
33+
error: assignments don't nest intuitively
34+
--> $DIR/multi_assignments.rs:8:5
35+
|
36+
LL | a = (b = c);
37+
| ^^^^^^^^^^^
38+
39+
error: aborting due to 6 previous errors
40+

0 commit comments

Comments
 (0)