Skip to content

Commit 5e91211

Browse files
Add in_boolean_test to Context (#4072)
1 parent df77595 commit 5e91211

3 files changed

Lines changed: 54 additions & 2 deletions

File tree

crates/ruff/src/checkers/ast/mod.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
164176
impl<'a, 'b> Visitor<'b> for Checker<'a>
165177
where
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) {

crates/ruff_python_semantic/src/analyze/typing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::context::Context;
1010

1111
#[derive(Copy, Clone)]
1212
pub enum Callable {
13+
Bool,
1314
Cast,
1415
NewType,
1516
TypeVar,

crates/ruff_python_semantic/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub struct Context<'a> {
4848
pub in_deferred_type_definition: bool,
4949
pub in_exception_handler: bool,
5050
pub in_f_string: bool,
51+
pub in_boolean_test: bool,
5152
pub in_literal: bool,
5253
pub in_subscript: bool,
5354
pub in_type_checking_block: bool,
@@ -88,6 +89,7 @@ impl<'a> Context<'a> {
8889
in_deferred_type_definition: false,
8990
in_exception_handler: false,
9091
in_f_string: false,
92+
in_boolean_test: false,
9193
in_literal: false,
9294
in_subscript: false,
9395
in_type_checking_block: false,

0 commit comments

Comments
 (0)