summaryrefslogtreecommitdiff
path: root/pylint
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2023-04-16 20:50:34 -0400
committerGitHub <noreply@github.com>2023-04-16 20:50:34 -0400
commitf45bf090a8e20c9fb09d61ed67d7f885ad354f85 (patch)
treedc3b4375c7599d252b2ac7aae7e2d7ef53748da7 /pylint
parent4a485e28f0a5118b37550123c79f1f6d0dec42a4 (diff)
downloadpylint-git-f45bf090a8e20c9fb09d61ed67d7f885ad354f85.tar.gz
Fix FP `used-before-assignment` for statements guarded under same test (#8581)
Diffstat (limited to 'pylint')
-rw-r--r--pylint/checkers/variables.py35
1 files changed, 35 insertions, 0 deletions
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index d82b5a8c8..8c9f6b6ae 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -811,6 +811,9 @@ scope_type : {self._atomic.scope_type}
continue
outer_if = all_if[-1]
+ if NamesConsumer._node_guarded_by_same_test(node, outer_if):
+ continue
+
# Name defined in the if/else control flow
if NamesConsumer._inferred_to_define_name_raise_or_return(name, outer_if):
continue
@@ -820,6 +823,38 @@ scope_type : {self._atomic.scope_type}
return uncertain_nodes
@staticmethod
+ def _node_guarded_by_same_test(node: nodes.NodeNG, other_if: nodes.If) -> bool:
+ """Identify if `node` is guarded by an equivalent test as `other_if`.
+
+ Two tests are equivalent if their string representations are identical
+ or if their inferred values consist only of constants and those constants
+ are identical, and the if test guarding `node` is not a Name.
+ """
+ other_if_test_as_string = other_if.test.as_string()
+ other_if_test_all_inferred = utils.infer_all(other_if.test)
+ for ancestor in node.node_ancestors():
+ if not isinstance(ancestor, nodes.If):
+ continue
+ if ancestor.test.as_string() == other_if_test_as_string:
+ return True
+ if isinstance(ancestor.test, nodes.Name):
+ continue
+ all_inferred = utils.infer_all(ancestor.test)
+ if len(all_inferred) == len(other_if_test_all_inferred):
+ if any(
+ not isinstance(test, nodes.Const)
+ for test in (*all_inferred, *other_if_test_all_inferred)
+ ):
+ continue
+ if {test.value for test in all_inferred} != {
+ test.value for test in other_if_test_all_inferred
+ }:
+ continue
+ return True
+
+ return False
+
+ @staticmethod
def _uncertain_nodes_in_except_blocks(
found_nodes: list[nodes.NodeNG],
node: nodes.NodeNG,