Skip to content

Commit

Permalink
Improve unreachable code analysis (#302)
Browse files Browse the repository at this point in the history
Fixes #270 and catches additional unreachable code.

---------

Co-authored-by: Jendrik Seipp <[email protected]>
  • Loading branch information
kreathon and jendrikseipp authored Nov 24, 2024
1 parent 9f44d4c commit 609f5f2
Show file tree
Hide file tree
Showing 7 changed files with 964 additions and 558 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# next (unreleased)

* Improve reachability analysis (kreathon, #270, #302).
* Add type hints for `get_unused_code` and the fields of the `Item` class (John Doknjas, #361).

# 2.13 (2024-10-02)
Expand Down
8 changes: 8 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ def check_unreachable(v, lineno, size, name):
assert item.name == name


def check_multiple_unreachable(v, checks):
assert len(v.unreachable_code) == len(checks)
for item, (lineno, size, name) in zip(v.unreachable_code, checks):
assert item.first_lineno == lineno
assert item.size == size
assert item.name == name


@pytest.fixture
def v():
return core.Vulture(verbose=True)
145 changes: 0 additions & 145 deletions tests/test_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from vulture import utils

from . import check_unreachable
from . import v

assert v # Silence pyflakes
Expand Down Expand Up @@ -73,147 +72,3 @@ def test_errors():
condition = ast.parse(condition, mode="eval").body
assert not utils.condition_is_always_false(condition)
assert not utils.condition_is_always_true(condition)


def test_while(v):
v.scan(
"""\
while False:
pass
"""
)
check_unreachable(v, 1, 2, "while")


def test_while_nested(v):
v.scan(
"""\
while True:
while False:
pass
"""
)
check_unreachable(v, 2, 2, "while")


def test_if_false(v):
v.scan(
"""\
if False:
pass
"""
)
check_unreachable(v, 1, 2, "if")


def test_elif_false(v):
v.scan(
"""\
if bar():
pass
elif False:
print("Unreachable")
"""
)
check_unreachable(v, 3, 2, "if")


def test_nested_if_statements_false(v):
v.scan(
"""\
if foo():
if bar():
pass
elif False:
print("Unreachable")
pass
elif something():
print("Reachable")
else:
pass
else:
pass
"""
)
check_unreachable(v, 4, 3, "if")


def test_if_false_same_line(v):
v.scan(
"""\
if False: a = 1
else: c = 3
"""
)
check_unreachable(v, 1, 1, "if")


def test_if_true(v):
v.scan(
"""\
if True:
a = 1
b = 2
else:
c = 3
d = 3
"""
)
# For simplicity, we don't report the "else" line as dead code.
check_unreachable(v, 5, 2, "else")


def test_if_true_same_line(v):
v.scan(
"""\
if True:
a = 1
b = 2
else: c = 3
d = 3
"""
)
check_unreachable(v, 4, 1, "else")


def test_nested_if_statements_true(v):
v.scan(
"""\
if foo():
if bar():
pass
elif True:
if something():
pass
else:
pass
elif something_else():
print("foo")
else:
print("bar")
else:
pass
"""
)
check_unreachable(v, 9, 4, "else")


def test_redundant_if(v):
v.scan(
"""\
if [5]:
pass
"""
)
print(v.unreachable_code[0].size)
check_unreachable(v, 1, 2, "if")


def test_if_exp_true(v):
v.scan("foo if True else bar")
check_unreachable(v, 1, 1, "ternary")


def test_if_exp_false(v):
v.scan("foo if False else bar")
check_unreachable(v, 1, 1, "ternary")
Loading

0 comments on commit 609f5f2

Please sign in to comment.