@@ -161,6 +161,18 @@ macro_rules! visit_non_type_definition {
161161 } } ;
162162}
163163
164+ /// Visit an [`Expr`], and treat it as a boolean test. This is useful for detecting whether an
165+ /// expressions return value is significant, or whether the calling context only relies on
166+ /// its truthiness.
167+ macro_rules! visit_boolean_test {
168+ ( $self: ident, $expr: expr) => { {
169+ let prev_in_boolean_test = $self. ctx. in_boolean_test;
170+ $self. ctx. in_boolean_test = true ;
171+ $self. visit_expr( $expr) ;
172+ $self. ctx. in_boolean_test = prev_in_boolean_test;
173+ } } ;
174+ }
175+
164176impl < ' a , ' b > Visitor < ' b > for Checker < ' a >
165177where
166178 ' b : ' a ,
@@ -2154,8 +2166,19 @@ where
21542166 }
21552167 self . visit_expr ( target) ;
21562168 }
2169+ StmtKind :: Assert { test, msg } => {
2170+ visit_boolean_test ! ( self , test) ;
2171+ if let Some ( expr) = msg {
2172+ self . visit_expr ( expr) ;
2173+ }
2174+ }
2175+ StmtKind :: While { test, body, orelse } => {
2176+ visit_boolean_test ! ( self , test) ;
2177+ self . visit_body ( body) ;
2178+ self . visit_body ( orelse) ;
2179+ }
21572180 StmtKind :: If { test, body, orelse } => {
2158- self . visit_expr ( test) ;
2181+ visit_boolean_test ! ( self , test) ;
21592182
21602183 if flake8_type_checking:: helpers:: is_type_checking_block ( & self . ctx , test) {
21612184 if self . settings . rules . enabled ( Rule :: EmptyTypeCheckingBlock ) {
@@ -2242,6 +2265,11 @@ where
22422265
22432266 let prev_in_literal = self . ctx . in_literal ;
22442267 let prev_in_type_definition = self . ctx . in_type_definition ;
2268+ let prev_in_boolean_test = self . ctx . in_boolean_test ;
2269+
2270+ if !matches ! ( expr. node, ExprKind :: BoolOp { .. } ) {
2271+ self . ctx . in_boolean_test = false ;
2272+ }
22452273
22462274 // Pre-visit.
22472275 match & expr. node {
@@ -3582,6 +3610,11 @@ where
35823610 ( self . ctx . scope_stack . clone ( ) , self . ctx . parents . clone ( ) ) ,
35833611 ) ) ;
35843612 }
3613+ ExprKind :: IfExp { test, body, orelse } => {
3614+ visit_boolean_test ! ( self , test) ;
3615+ self . visit_expr ( body) ;
3616+ self . visit_expr ( orelse) ;
3617+ }
35853618 ExprKind :: Call {
35863619 func,
35873620 args,
@@ -3610,11 +3643,22 @@ where
36103643 . any ( |target| call_path. as_slice ( ) == [ "mypy_extensions" , target] )
36113644 {
36123645 Some ( Callable :: MypyExtension )
3646+ } else if call_path. as_slice ( ) == [ "" , "bool" ] {
3647+ Some ( Callable :: Bool )
36133648 } else {
36143649 None
36153650 }
36163651 } ) ;
36173652 match callable {
3653+ Some ( Callable :: Bool ) => {
3654+ self . visit_expr ( func) ;
3655+ if !args. is_empty ( ) {
3656+ visit_boolean_test ! ( self , & args[ 0 ] ) ;
3657+ }
3658+ for expr in args. iter ( ) . skip ( 1 ) {
3659+ self . visit_expr ( expr) ;
3660+ }
3661+ }
36183662 Some ( Callable :: Cast ) => {
36193663 self . visit_expr ( func) ;
36203664 if !args. is_empty ( ) {
@@ -3813,6 +3857,7 @@ where
38133857
38143858 self . ctx . in_type_definition = prev_in_type_definition;
38153859 self . ctx . in_literal = prev_in_literal;
3860+ self . ctx . in_boolean_test = prev_in_boolean_test;
38163861
38173862 self . ctx . pop_expr ( ) ;
38183863 }
@@ -3825,7 +3870,11 @@ where
38253870 & comprehension. iter ,
38263871 ) ;
38273872 }
3828- visitor:: walk_comprehension ( self , comprehension) ;
3873+ self . visit_expr ( & comprehension. iter ) ;
3874+ self . visit_expr ( & comprehension. target ) ;
3875+ for expr in & comprehension. ifs {
3876+ visit_boolean_test ! ( self , expr) ;
3877+ }
38293878 }
38303879
38313880 fn visit_excepthandler ( & mut self , excepthandler : & ' b Excepthandler ) {
0 commit comments