From 39114d5732615e34b551cae4ebcdf7dc366e0320 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 22 Oct 2024 08:18:25 -0400 Subject: [PATCH] refactor: change impossible branches to asserts in parser.py --- CHANGES.rst | 3 +++ coverage/parser.py | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index e9fca2bf8..c8cd28a0b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -27,6 +27,9 @@ Unreleased statements changed how they traced. This affected whether people saw the fix for `issue 1880`_. +- refactor: some code unreachable code paths in parser.py were changed to + asserts. If you encounter any of these, please let me know! + .. start-releases diff --git a/coverage/parser.py b/coverage/parser.py index c68fb4eaf..0ce94d039 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -296,7 +296,7 @@ def _analyze_ast(self) -> None: """ assert self._ast_root is not None - aaa = AstArcAnalyzer(self._ast_root, self.raw_statements, self._multiline) + aaa = AstArcAnalyzer(self.filename, self._ast_root, self.raw_statements, self._multiline) aaa.analyze() self._with_jump_fixers = aaa.with_jump_fixers() @@ -337,9 +337,7 @@ def exit_counts(self) -> dict[TLineNo, int]: """ exit_counts: dict[TLineNo, int] = collections.defaultdict(int) for l1, l2 in self.arcs(): - if l1 < 0: - # Don't ever report -1 as a line number - continue + assert l1 > 0, f"{l1=} should be greater than zero in {self.filename}" if l1 in self.excluded: # Don't report excluded lines as line numbers. continue @@ -437,15 +435,15 @@ def _line_numbers(self) -> Iterable[TLineNo]: byte_num = 0 for byte_incr, line_incr in zip(byte_increments, line_increments): if byte_incr: - if line_num != last_line_num: - yield line_num - last_line_num = line_num + assert line_num != last_line_num, f"Oops, {byte_incr = }, {line_incr = }" + yield line_num + last_line_num = line_num byte_num += byte_incr if line_incr >= 0x80: line_incr -= 0x100 line_num += line_incr - if line_num != last_line_num: - yield line_num + assert line_num != last_line_num + yield line_num def _find_statements(self) -> Iterable[TLineNo]: """Find the statements in `self.code`. @@ -643,10 +641,12 @@ class AstArcAnalyzer: def __init__( self, + filename: str, root_node: ast.AST, statements: set[TLineNo], multiline: dict[TLineNo, TLineNo], ) -> None: + self.filename = filename self.root_node = root_node # TODO: I think this is happening in too many places. self.statements = {multiline.get(l, l) for l in statements} @@ -1076,9 +1076,9 @@ def _handle_decorated(self, node: ast.FunctionDef) -> set[ArcStart]: # in `self.statements`. For some constructs, `line_for_node` is # not what we'd think of as the first line in the statement, so map # it to the first one. - if node.body: - body_start = self.line_for_node(node.body[0]) - body_start = self.multiline.get(body_start, body_start) + assert node.body, f"Oops: {node.body = } in {self.filename}@{node.lineno}" + body_start = self.line_for_node(node.body[0]) + body_start = self.multiline.get(body_start, body_start) # The body is handled in collect_arcs. assert last is not None return {ArcStart(last)}