зеркало из https://github.com/github/codeql.git
Merge pull request #18030 from github/tausbn/python-fix-match-literal-pruning
Python: Fix pruning of literals in `match` pattern
This commit is contained in:
Коммит
d4ec8f650a
|
@ -196,6 +196,25 @@ class SkippedVisitor(ASTVisitor):
|
||||||
if isinstance(node.value, ast.Name):
|
if isinstance(node.value, ast.Name):
|
||||||
self.nodes.add(node.value)
|
self.nodes.add(node.value)
|
||||||
|
|
||||||
|
class NotBooleanTestVisitor(ASTVisitor):
|
||||||
|
"""Visitor that checks if a test is not a boolean test."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.nodes = set()
|
||||||
|
|
||||||
|
def visit_MatchLiteralPattern(self, node):
|
||||||
|
# MatchLiteralPatterns _look_ like boolean tests, but are not.
|
||||||
|
# Thus, without this check, we would interpret
|
||||||
|
#
|
||||||
|
# match x:
|
||||||
|
# case False:
|
||||||
|
# pass
|
||||||
|
#
|
||||||
|
# (and similarly for True) as if it was a boolean test. This would cause the true edge
|
||||||
|
# (leading to pass) to be pruned later on.
|
||||||
|
if isinstance(node.literal, ast.Name) and node.literal.id in ('True', 'False'):
|
||||||
|
self.nodes.add(node.literal)
|
||||||
|
|
||||||
class NonlocalVisitor(ASTVisitor):
|
class NonlocalVisitor(ASTVisitor):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.names = set()
|
self.names = set()
|
||||||
|
@ -306,6 +325,8 @@ def effective_constants_definitions(bool_const_defns, graph, branching_edges):
|
||||||
def do_pruning(tree, graph):
|
def do_pruning(tree, graph):
|
||||||
v = BoolConstVisitor()
|
v = BoolConstVisitor()
|
||||||
v.visit(tree)
|
v.visit(tree)
|
||||||
|
not_boolean_test = NotBooleanTestVisitor()
|
||||||
|
not_boolean_test.visit(tree)
|
||||||
nonlocals = NonlocalVisitor()
|
nonlocals = NonlocalVisitor()
|
||||||
nonlocals.visit(tree)
|
nonlocals.visit(tree)
|
||||||
global_vars = GlobalVisitor()
|
global_vars = GlobalVisitor()
|
||||||
|
@ -353,6 +374,8 @@ def do_pruning(tree, graph):
|
||||||
b = const_value(pred.node)
|
b = const_value(pred.node)
|
||||||
if b is None:
|
if b is None:
|
||||||
continue
|
continue
|
||||||
|
if pred.node in not_boolean_test.nodes:
|
||||||
|
continue
|
||||||
if b.contradicts(val):
|
if b.contradicts(val):
|
||||||
to_be_removed.add((pred, succ))
|
to_be_removed.add((pred, succ))
|
||||||
if not to_be_removed:
|
if not to_be_removed:
|
||||||
|
|
|
@ -4,5 +4,3 @@
|
||||||
| test.py:21:5:21:38 | For | This statement is unreachable. |
|
| test.py:21:5:21:38 | For | This statement is unreachable. |
|
||||||
| test.py:28:9:28:21 | ExprStmt | This statement is unreachable. |
|
| test.py:28:9:28:21 | ExprStmt | This statement is unreachable. |
|
||||||
| test.py:84:5:84:21 | ExceptStmt | This statement is unreachable. |
|
| test.py:84:5:84:21 | ExceptStmt | This statement is unreachable. |
|
||||||
| test.py:144:13:144:16 | Pass | This statement is unreachable. |
|
|
||||||
| test.py:147:9:148:16 | Case | This statement is unreachable. |
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче