@@ -3,7 +3,7 @@ use clippy_utils::macros::{find_assert_args, root_macro_call_first_node};
33use clippy_utils:: source:: snippet;
44use rustc_errors:: Applicability ;
55use rustc_hir:: intravisit:: Visitor ;
6- use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
6+ use rustc_hir:: { BinOpKind , Expr , ExprKind , UnOp } ;
77use rustc_lint:: { LateContext , LateLintPass } ;
88use rustc_session:: declare_lint_pass;
99use rustc_span:: sym;
@@ -40,6 +40,9 @@ declare_clippy_lint! {
4040
4141declare_lint_pass ! ( AssertMultiple => [ ASSERT_MULTIPLE ] ) ;
4242
43+ // This visiior is a convenient place to hold the session context, as well as the collection of
44+ // replacement strings and the type of assert to use.
45+
4346struct AssertVisitor < ' tcx , ' v > {
4447 cx : & ' v LateContext < ' tcx > ,
4548 suggests : Vec < String > ,
@@ -51,37 +54,47 @@ impl<'tcx> Visitor<'tcx> for AssertVisitor<'tcx, '_> {
5154 match e. kind {
5255 ExprKind :: Binary ( op, lhs, rhs) => match op. node {
5356 BinOpKind :: And => {
57+ // For And, turn each of the rhs and lhs expressions into their own assert.
5458 rustc_hir:: intravisit:: walk_expr ( self , lhs) ;
5559 rustc_hir:: intravisit:: walk_expr ( self , rhs) ;
5660 } ,
5761 BinOpKind :: Or => {
62+ // For Or, we cannot break the expression up.
5863 let tmpstr = format ! ( "{}!{};" , self . assert_string, snippet( self . cx, e. span, ".." ) ) ;
5964 self . suggests . push ( tmpstr) ;
6065 } ,
6166 _ => {
6267 if let Some ( x) = assert_from_op ( self , op. node , * lhs, * rhs) {
68+ // handle most of the binary operators here.
6369 self . suggests . push ( x) ;
6470 }
6571 } ,
6672 } ,
6773 ExprKind :: Call ( _call, _args) => {
74+ // split function calls into their own assert.
6875 let tmptxt = snippet ( self . cx , e. span , ".." ) ;
69- let tmpassrt = format ! ( "{}!({});" , self . assert_string, tmptxt. trim_end_matches ( ';' ) ) ;
76+ let tmpassrt = format ! ( "{}!({});" , self . assert_string, tmptxt) ;
7077 self . suggests . push ( tmpassrt) ;
7178 } ,
7279
7380 ExprKind :: MethodCall ( _path, expr, _args, span) => {
81+ // split method calls into their own assert as well.
7482 let calltext = snippet ( self . cx , expr. span , ".." ) ;
75-
7683 let tmptxt = format ! ( "{}.{};" , & * calltext, snippet( self . cx, span, ".." ) ) ;
7784 self . suggests . push ( tmptxt) ;
7885 } ,
7986 ExprKind :: Path ( qpath) => {
80- // this is a boolean variable
87+ // this is a statndalone boolean variable, not an expression.
8188 let name = snippet ( self . cx , qpath. span ( ) , "_" ) ;
8289 let tmptxt = format ! ( "{}!({name});" , self . assert_string) ;
8390 self . suggests . push ( tmptxt) ;
8491 } ,
92+ ExprKind :: Unary ( UnOp :: Not , expr) => {
93+ // A Not operator, just output the
94+ let exptext = snippet ( self . cx , expr. span , "_" ) ;
95+ let tmptxt = format ! ( "{}!(!{exptext});" , self . assert_string) ;
96+ self . suggests . push ( tmptxt) ;
97+ } ,
8598
8699 _ => { } ,
87100 }
@@ -99,6 +112,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertMultiple {
99112 && let Some ( ( condition, _) ) = find_assert_args ( cx, e, macro_call. expn )
100113 && matches ! ( condition. kind, ExprKind :: Binary ( binop, _lhs, _rhs) if binop. node == BinOpKind :: And )
101114 {
115+ // We only get here on assert/debug_assert macro calls whose arguments have an And expression
116+ // on the top of the tree.
102117 let mut am_visitor = AssertVisitor {
103118 cx,
104119 suggests : Vec :: new ( ) ,
@@ -122,6 +137,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertMultiple {
122137 }
123138}
124139
140+ // This function separates out a binary operation into a separate assert, using ..._eq or ..._ne if
141+ // applicable.
125142fn assert_from_op (
126143 visitor : & mut AssertVisitor < ' _ , ' _ > ,
127144 node : BinOpKind ,
0 commit comments