Skip to content

Commit 121a047

Browse files
committed
Move linting of assert macros from early to late pass
1 parent a3e0446 commit 121a047

File tree

6 files changed

+179
-134
lines changed

6 files changed

+179
-134
lines changed

clippy_lints/src/eq_op.rs

+32-41
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
use crate::utils::ast_utils::eq_expr;
21
use crate::utils::{
3-
eq_expr_value, implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then,
2+
eq_expr_value, implements_trait, in_macro, is_copy, is_expn_of, multispan_sugg, snippet, span_lint,
3+
span_lint_and_then,
44
};
55
use if_chain::if_chain;
6-
use rustc_ast::{ast, token};
76
use rustc_errors::Applicability;
8-
use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind};
9-
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
10-
use rustc_middle::lint::in_external_macro;
11-
use rustc_parse::parser;
7+
use rustc_hir::{BinOp, BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
8+
use rustc_lint::{LateContext, LateLintPass};
129
use rustc_session::{declare_lint_pass, declare_tool_lint};
1310

1411
declare_clippy_lint! {
@@ -63,44 +60,38 @@ declare_clippy_lint! {
6360

6461
declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
6562

66-
impl EarlyLintPass for EqOp {
67-
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
68-
let macro_list = [
69-
sym!(assert_eq),
70-
sym!(assert_ne),
71-
sym!(debug_assert_eq),
72-
sym!(debug_assert_ne),
73-
];
74-
if_chain! {
75-
if !in_external_macro(cx.sess, mac.span());
76-
if mac.path.segments.len() == 1;
77-
let macro_name = mac.path.segments[0].ident.name;
78-
if macro_list.contains(&macro_name);
79-
let tokens = mac.args.inner_tokens();
80-
let mut parser = parser::Parser::new(
81-
&cx.sess.parse_sess, tokens, false, None);
82-
if let Ok(left) = parser.parse_expr();
83-
if parser.eat(&token::Comma);
84-
if let Ok(right) = parser.parse_expr();
85-
let left_expr = left.into_inner();
86-
let right_expr = right.into_inner();
87-
if eq_expr(&left_expr, &right_expr);
88-
89-
then {
90-
span_lint(
91-
cx,
92-
EQ_OP,
93-
left_expr.span.to(right_expr.span),
94-
&format!("identical args used in this `{}!` macro call", macro_name),
95-
);
96-
}
97-
}
98-
}
99-
}
63+
const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_eq", "debug_assert_ne"];
10064

10165
impl<'tcx> LateLintPass<'tcx> for EqOp {
10266
#[allow(clippy::similar_names, clippy::too_many_lines)]
10367
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
68+
if let ExprKind::Block(ref block, _) = e.kind {
69+
for stmt in block.stmts {
70+
for amn in &ASSERT_MACRO_NAMES {
71+
if_chain! {
72+
if is_expn_of(stmt.span, amn).is_some();
73+
if let StmtKind::Semi(ref matchexpr) = stmt.kind;
74+
if let ExprKind::Block(ref matchblock, _) = matchexpr.kind;
75+
if let Some(ref matchheader) = matchblock.expr;
76+
if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind;
77+
if let ExprKind::Tup(ref conditions) = headerexpr.kind;
78+
if conditions.len() == 2;
79+
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref lhs) = conditions[0].kind;
80+
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref rhs) = conditions[1].kind;
81+
if eq_expr_value(cx, lhs, rhs);
82+
83+
then {
84+
span_lint(
85+
cx,
86+
EQ_OP,
87+
lhs.span.to(rhs.span),
88+
&format!("identical args used in this `{}!` macro call", amn),
89+
);
90+
}
91+
}
92+
}
93+
}
94+
}
10495
if let ExprKind::Binary(op, ref left, ref right) = e.kind {
10596
if e.span.from_expansion() {
10697
return;

clippy_lints/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
348348
store.register_pre_expansion_pass(|| box write::Write::default());
349349
store.register_pre_expansion_pass(|| box attrs::EarlyAttributes);
350350
store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro);
351-
store.register_pre_expansion_pass(|| box eq_op::EqOp);
352351
}
353352

354353
#[doc(hidden)]
@@ -911,7 +910,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
911910
let vec_box_size_threshold = conf.vec_box_size_threshold;
912911
store.register_late_pass(move || box types::Types::new(vec_box_size_threshold));
913912
store.register_late_pass(|| box booleans::NonminimalBool);
914-
store.register_early_pass(|| box eq_op::EqOp);
915913
store.register_late_pass(|| box eq_op::EqOp);
916914
store.register_late_pass(|| box enum_clike::UnportableVariant);
917915
store.register_late_pass(|| box float_literal::FloatLiteral);

tests/ui/eq_op.rs

+53
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ fn main() {
6060
const B: u32 = 10;
6161
const C: u32 = A / B; // ok, different named constants
6262
const D: u32 = A / A;
63+
64+
check_assert_identical_args();
6365
}
6466

6567
#[rustfmt::skip]
@@ -85,3 +87,54 @@ fn check_ignore_macro() {
8587
// checks if the lint ignores macros with `!` operator
8688
!bool_macro!(1) && !bool_macro!("");
8789
}
90+
91+
macro_rules! assert_in_macro_def {
92+
() => {
93+
let a = 42;
94+
assert_eq!(a, a);
95+
assert_ne!(a, a);
96+
debug_assert_eq!(a, a);
97+
debug_assert_ne!(a, a);
98+
};
99+
}
100+
101+
// lint identical args in assert-like macro invocations (see #3574)
102+
fn check_assert_identical_args() {
103+
// lint also in macro definition
104+
assert_in_macro_def!();
105+
106+
let a = 1;
107+
let b = 2;
108+
109+
// lint identical args in `assert_eq!`
110+
assert_eq!(a, a);
111+
assert_eq!(a + 1, a + 1);
112+
// ok
113+
assert_eq!(a, b);
114+
assert_eq!(a, a + 1);
115+
assert_eq!(a + 1, b + 1);
116+
117+
// lint identical args in `assert_ne!`
118+
assert_ne!(a, a);
119+
assert_ne!(a + 1, a + 1);
120+
// ok
121+
assert_ne!(a, b);
122+
assert_ne!(a, a + 1);
123+
assert_ne!(a + 1, b + 1);
124+
125+
// lint identical args in `debug_assert_eq!`
126+
debug_assert_eq!(a, a);
127+
debug_assert_eq!(a + 1, a + 1);
128+
// ok
129+
debug_assert_eq!(a, b);
130+
debug_assert_eq!(a, a + 1);
131+
debug_assert_eq!(a + 1, b + 1);
132+
133+
// lint identical args in `debug_assert_ne!`
134+
debug_assert_ne!(a, a);
135+
debug_assert_ne!(a + 1, a + 1);
136+
// ok
137+
debug_assert_ne!(a, b);
138+
debug_assert_ne!(a, a + 1);
139+
debug_assert_ne!(a + 1, b + 1);
140+
}

tests/ui/eq_op.stderr

+94-1
Original file line numberDiff line numberDiff line change
@@ -162,5 +162,98 @@ error: equal expressions as operands to `/`
162162
LL | const D: u32 = A / A;
163163
| ^^^^^
164164

165-
error: aborting due to 27 previous errors
165+
error: identical args used in this `assert_eq!` macro call
166+
--> $DIR/eq_op.rs:94:20
167+
|
168+
LL | assert_eq!(a, a);
169+
| ^^^^
170+
...
171+
LL | assert_in_macro_def!();
172+
| ----------------------- in this macro invocation
173+
|
174+
= note: `#[deny(clippy::eq_op)]` on by default
175+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
176+
177+
error: identical args used in this `assert_ne!` macro call
178+
--> $DIR/eq_op.rs:95:20
179+
|
180+
LL | assert_ne!(a, a);
181+
| ^^^^
182+
...
183+
LL | assert_in_macro_def!();
184+
| ----------------------- in this macro invocation
185+
|
186+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
187+
188+
error: identical args used in this `assert_eq!` macro call
189+
--> $DIR/eq_op.rs:110:16
190+
|
191+
LL | assert_eq!(a, a);
192+
| ^^^^
193+
194+
error: identical args used in this `assert_eq!` macro call
195+
--> $DIR/eq_op.rs:111:16
196+
|
197+
LL | assert_eq!(a + 1, a + 1);
198+
| ^^^^^^^^^^^^
199+
200+
error: identical args used in this `assert_ne!` macro call
201+
--> $DIR/eq_op.rs:118:16
202+
|
203+
LL | assert_ne!(a, a);
204+
| ^^^^
205+
206+
error: identical args used in this `assert_ne!` macro call
207+
--> $DIR/eq_op.rs:119:16
208+
|
209+
LL | assert_ne!(a + 1, a + 1);
210+
| ^^^^^^^^^^^^
211+
212+
error: identical args used in this `debug_assert_eq!` macro call
213+
--> $DIR/eq_op.rs:96:26
214+
|
215+
LL | debug_assert_eq!(a, a);
216+
| ^^^^
217+
...
218+
LL | assert_in_macro_def!();
219+
| ----------------------- in this macro invocation
220+
|
221+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
222+
223+
error: identical args used in this `debug_assert_ne!` macro call
224+
--> $DIR/eq_op.rs:97:26
225+
|
226+
LL | debug_assert_ne!(a, a);
227+
| ^^^^
228+
...
229+
LL | assert_in_macro_def!();
230+
| ----------------------- in this macro invocation
231+
|
232+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
233+
234+
error: identical args used in this `debug_assert_eq!` macro call
235+
--> $DIR/eq_op.rs:126:22
236+
|
237+
LL | debug_assert_eq!(a, a);
238+
| ^^^^
239+
240+
error: identical args used in this `debug_assert_eq!` macro call
241+
--> $DIR/eq_op.rs:127:22
242+
|
243+
LL | debug_assert_eq!(a + 1, a + 1);
244+
| ^^^^^^^^^^^^
245+
246+
error: identical args used in this `debug_assert_ne!` macro call
247+
--> $DIR/eq_op.rs:134:22
248+
|
249+
LL | debug_assert_ne!(a, a);
250+
| ^^^^
251+
252+
error: identical args used in this `debug_assert_ne!` macro call
253+
--> $DIR/eq_op.rs:135:22
254+
|
255+
LL | debug_assert_ne!(a + 1, a + 1);
256+
| ^^^^^^^^^^^^
257+
258+
error: aborting due to 39 previous errors
166259

tests/ui/eq_op_early.rs

-38
This file was deleted.

tests/ui/eq_op_early.stderr

-52
This file was deleted.

0 commit comments

Comments
 (0)