Skip to content

Commit f95b2ee

Browse files
committed
Assert macro args extractor as a common function in higher
1 parent 71c29b5 commit f95b2ee

File tree

3 files changed

+69
-63
lines changed

3 files changed

+69
-63
lines changed

clippy_lints/src/eq_op.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::utils::{
2-
eq_expr_value, implements_trait, in_macro, is_copy, is_expn_of, multispan_sugg, snippet, span_lint,
2+
eq_expr_value, higher, implements_trait, in_macro, is_copy, is_expn_of, multispan_sugg, snippet, span_lint,
33
span_lint_and_then,
44
};
55
use if_chain::if_chain;
@@ -71,13 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
7171
if_chain! {
7272
if is_expn_of(stmt.span, amn).is_some();
7373
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;
74+
if let Some(macro_args) = higher::extract_assert_macro_args(matchexpr);
75+
if macro_args.len() == 2;
76+
let (lhs, rhs) = (macro_args[0], macro_args[1]);
8177
if eq_expr_value(cx, lhs, rhs);
8278

8379
then {

clippy_lints/src/mutable_debug_assertion.rs

+11-55
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::utils::{is_direct_expn_of, span_lint};
2-
use if_chain::if_chain;
1+
use crate::utils::{higher, is_direct_expn_of, span_lint};
32
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
4-
use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability, StmtKind, UnOp};
3+
use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability};
54
use rustc_lint::{LateContext, LateLintPass};
65
use rustc_middle::hir::map::Map;
76
use rustc_middle::ty;
@@ -39,66 +38,23 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
3938
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
4039
for dmn in &DEBUG_MACRO_NAMES {
4140
if is_direct_expn_of(e.span, dmn).is_some() {
42-
if let Some(span) = extract_call(cx, e) {
43-
span_lint(
44-
cx,
45-
DEBUG_ASSERT_WITH_MUT_CALL,
46-
span,
47-
&format!("do not call a function with mutable arguments inside of `{}!`", dmn),
48-
);
49-
}
50-
}
51-
}
52-
}
53-
}
54-
55-
//HACK(hellow554): remove this when #4694 is implemented
56-
fn extract_call<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<Span> {
57-
if_chain! {
58-
if let ExprKind::Block(ref block, _) = e.kind;
59-
if block.stmts.len() == 1;
60-
if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind;
61-
then {
62-
// debug_assert
63-
if_chain! {
64-
if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind;
65-
if let ExprKind::DropTemps(ref droptmp) = ifclause.kind;
66-
if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind;
67-
then {
68-
let mut visitor = MutArgVisitor::new(cx);
69-
visitor.visit_expr(condition);
70-
return visitor.expr_span();
71-
}
72-
}
73-
74-
// debug_assert_{eq,ne}
75-
if_chain! {
76-
if let ExprKind::Block(ref matchblock, _) = matchexpr.kind;
77-
if let Some(ref matchheader) = matchblock.expr;
78-
if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind;
79-
if let ExprKind::Tup(ref conditions) = headerexpr.kind;
80-
if conditions.len() == 2;
81-
then {
82-
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref lhs) = conditions[0].kind {
41+
if let Some(macro_args) = higher::extract_assert_macro_args(e) {
42+
for arg in macro_args {
8343
let mut visitor = MutArgVisitor::new(cx);
84-
visitor.visit_expr(lhs);
44+
visitor.visit_expr(arg);
8545
if let Some(span) = visitor.expr_span() {
86-
return Some(span);
87-
}
88-
}
89-
if let ExprKind::AddrOf(BorrowKind::Ref, _, ref rhs) = conditions[1].kind {
90-
let mut visitor = MutArgVisitor::new(cx);
91-
visitor.visit_expr(rhs);
92-
if let Some(span) = visitor.expr_span() {
93-
return Some(span);
46+
span_lint(
47+
cx,
48+
DEBUG_ASSERT_WITH_MUT_CALL,
49+
span,
50+
&format!("do not call a function with mutable arguments inside of `{}!`", dmn),
51+
);
9452
}
9553
}
9654
}
9755
}
9856
}
9957
}
100-
101-
None
10258
}
10359

10460
struct MutArgVisitor<'a, 'tcx> {

clippy_lints/src/utils/higher.rs

+54
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::utils::{is_expn_of, match_def_path, paths};
77
use if_chain::if_chain;
88
use rustc_ast::ast;
99
use rustc_hir as hir;
10+
use rustc_hir::{BorrowKind, Expr, ExprKind, StmtKind, UnOp};
1011
use rustc_lint::LateContext;
1112

1213
/// Converts a hir binary operator to the corresponding `ast` type.
@@ -241,3 +242,56 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve
241242

242243
None
243244
}
245+
246+
/// Extract args from an assert-like macro.
247+
/// Currently working with:
248+
/// - `assert!`, `assert_eq!` and `assert_ne!`
249+
/// - `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!`
250+
/// For example:
251+
/// `assert!(expr)` will return Some([expr])
252+
/// `debug_assert_eq!(a, b)` will return Some([a, b])
253+
pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx Expr<'tcx>>> {
254+
/// Try to lint a block that contains a match, for example if two args are compared
255+
fn report_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
256+
if_chain! {
257+
if let ExprKind::Match(ref headerexpr, _, _) = &matchblock_expr.kind;
258+
if let ExprKind::Tup(ref conditions) = headerexpr.kind;
259+
if conditions.len() == 2;
260+
if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = conditions[0].kind;
261+
if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = conditions[1].kind;
262+
then {
263+
return Some(vec![lhs, rhs]);
264+
}
265+
}
266+
None
267+
}
268+
269+
if let ExprKind::Block(ref block, _) = e.kind {
270+
if block.stmts.len() == 1 {
271+
if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind {
272+
// macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
273+
if_chain! {
274+
if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind;
275+
if let ExprKind::DropTemps(ref droptmp) = ifclause.kind;
276+
if let ExprKind::Unary(UnOp::UnNot, condition) = droptmp.kind;
277+
then {
278+
return Some(vec![condition]);
279+
}
280+
}
281+
282+
// debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
283+
if_chain! {
284+
if let ExprKind::Block(ref matchblock,_) = matchexpr.kind;
285+
if let Some(ref matchblock_expr) = matchblock.expr;
286+
then {
287+
return report_matchblock(matchblock_expr);
288+
}
289+
}
290+
}
291+
} else if let Some(matchblock_expr) = block.expr {
292+
// macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
293+
return report_matchblock(&matchblock_expr);
294+
}
295+
}
296+
None
297+
}

0 commit comments

Comments
 (0)