Skip to content

Commit

Permalink
Fix FP for used-before-assignment with assignment expressions in cont…
Browse files Browse the repository at this point in the history
…ainers (#8253) (#8262)

(cherry picked from commit a0b28f9)

Co-authored-by: Jacob Walls <jacobtylerwalls@gmail.com>
  • Loading branch information
github-actions[bot] and jacobtylerwalls committed Feb 11, 2023
1 parent 4aedc4f commit c2cd7c6
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 24 deletions.
4 changes: 4 additions & 0 deletions doc/whatsnew/fragments/8252.false_positive
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix false positive for ``used-before-assignment`` for named expressions
appearing after the first element in a list, tuple, or set.

Closes #8252
37 changes: 19 additions & 18 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@
astroid.nodes.node_classes.Dict,
)

NODES_WITH_VALUE_ATTR = (
nodes.Assign,
nodes.AnnAssign,
nodes.AugAssign,
nodes.Expr,
nodes.Return,
nodes.Match,
)


class VariableVisitConsumerAction(Enum):
"""Reported by _check_consumer() and its sub-methods to determine the
Expand Down Expand Up @@ -2128,17 +2137,7 @@ def _is_variable_violation(
# same line as the function definition
maybe_before_assign = False
elif (
isinstance(
defstmt,
(
nodes.Assign,
nodes.AnnAssign,
nodes.AugAssign,
nodes.Expr,
nodes.Return,
nodes.Match,
),
)
isinstance(defstmt, NODES_WITH_VALUE_ATTR)
and VariablesChecker._maybe_used_and_assigned_at_once(defstmt)
and frame is defframe
and defframe.parent_of(node)
Expand Down Expand Up @@ -2234,13 +2233,15 @@ def _maybe_used_and_assigned_at_once(defstmt: nodes.Statement) -> bool:
"""
if isinstance(defstmt, nodes.Match):
return any(case.guard for case in defstmt.cases)
if isinstance(defstmt.value, nodes.BaseContainer) and defstmt.value.elts:
# The assignment must happen as part of the first element
# e.g. "assert (x:= True), x"
# NOT "assert x, (x:= True)"
value = defstmt.value.elts[0]
else:
value = defstmt.value
if isinstance(defstmt, nodes.IfExp):
return True
if isinstance(defstmt.value, nodes.BaseContainer):
return any(
VariablesChecker._maybe_used_and_assigned_at_once(elt)
for elt in defstmt.value.elts
if isinstance(elt, NODES_WITH_VALUE_ATTR + (nodes.IfExp, nodes.Match))
)
value = defstmt.value
if isinstance(value, nodes.IfExp):
return True
if isinstance(value, nodes.Lambda) and isinstance(value.body, nodes.IfExp):
Expand Down
10 changes: 7 additions & 3 deletions tests/functional/u/undefined/undefined_variable_py38.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,13 @@ def expression_in_ternary_operator_inside_container_tuple():
return [(val3, val3) if (val3 := 'something') else 'anything']


def expression_in_ternary_operator_inside_container_wrong_position():
"""2-element list where named expression comes too late"""
return [val3, val3 if (val3 := 'something') else 'anything'] # [used-before-assignment]
def expression_in_ternary_operator_inside_container_later_position():
"""
Named expression follows unrelated item in container.
If 23 is replaced with `val3`, there is currently a false negative,
but the false positive here is more important and likely to occur."""
return [23, val3 if (val3 := 'something') else 'anything']


# Self-referencing
Expand Down
5 changes: 2 additions & 3 deletions tests/functional/u/undefined/undefined_variable_py38.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ undefined-variable:83:6:83:19::Undefined variable 'else_assign_1':INFERENCE
undefined-variable:106:6:106:19::Undefined variable 'else_assign_2':INFERENCE
used-before-assignment:141:10:141:16:type_annotation_used_improperly_after_comprehension:Using variable 'my_int' before assignment:HIGH
used-before-assignment:148:10:148:16:type_annotation_used_improperly_after_comprehension_2:Using variable 'my_int' before assignment:HIGH
used-before-assignment:178:12:178:16:expression_in_ternary_operator_inside_container_wrong_position:Using variable 'val3' before assignment:HIGH
used-before-assignment:182:9:182:10::Using variable 'z' before assignment:HIGH
used-before-assignment:189:6:189:19::Using variable 'NEVER_DEFINED' before assignment:CONTROL_FLOW
used-before-assignment:186:9:186:10::Using variable 'z' before assignment:HIGH
used-before-assignment:193:6:193:19::Using variable 'NEVER_DEFINED' before assignment:CONTROL_FLOW

0 comments on commit c2cd7c6

Please sign in to comment.