diff options
Diffstat (limited to 'pylint')
-rw-r--r-- | pylint/checkers/variables.py | 35 |
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, |