diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2016-01-09 17:34:32 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2016-01-09 17:34:32 -0500 |
commit | f6d343cf2259491ce9556758c5398e0db76d804c (patch) | |
tree | 1849e804fda55277f0ed201be3924e0927f0037f | |
parent | f2beb9c5e97fd887fe0b848812432bf467f30582 (diff) | |
download | python-coveragepy-git-f6d343cf2259491ce9556758c5398e0db76d804c.tar.gz |
Properly skip lines that are optimized away
-rw-r--r-- | coverage/parser.py | 21 | ||||
-rw-r--r-- | tests/test_arcs.py | 2 |
2 files changed, 13 insertions, 10 deletions
diff --git a/coverage/parser.py b/coverage/parser.py index 4f15743a..501b76c4 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -75,7 +75,8 @@ class PythonParser(object): # Internal detail, used by lab/parser.py. self.show_tokens = False - # A dict mapping line numbers to (lo,hi) for multi-line statements. + # A dict mapping line numbers to lexical statement starts for + # multi-line statements. self._multiline = {} # Lazily-created ByteParser and arc data. @@ -200,11 +201,7 @@ class PythonParser(object): def first_line(self, line): """Return the first line number of the statement including `line`.""" - first_line = self._multiline.get(line) - if first_line: - return first_line - else: - return line + return self._multiline.get(line, line) def first_lines(self, lines): """Map the line numbers in `lines` to the correct first line of the @@ -257,7 +254,7 @@ class PythonParser(object): """ if self._all_arcs is None: - aaa = AstArcAnalyzer(self.text, self.raw_statements) + aaa = AstArcAnalyzer(self.text, self.raw_statements, self._multiline) arcs = aaa.collect_arcs() self._all_arcs = set() @@ -328,12 +325,15 @@ class AstArcAnalyzer(object): """Analyze source text with an AST to find executable code paths.""" @contract(text='unicode', statements=set) - def __init__(self, text, statements): + def __init__(self, text, statements, multiline): self.root_node = ast.parse(neuter_encoding_declaration(text)) - self.statements = statements + # TODO: I think this is happening in too many places. + self.statements = set(multiline.get(l, l) for l in statements) + self.multiline = multiline if int(os.environ.get("COVERAGE_ASTDUMP", 0)): # pragma: debugging # Dump the AST so that failing tests have helpful output. + print(self.statements) ast_dump(self.root_node) self.arcs = None @@ -419,6 +419,9 @@ class AstArcAnalyzer(object): prev_lines = set([from_line]) for body_node in body: lineno = self.line_for_node(body_node) + first_line = self.multiline.get(lineno, lineno) + if first_line not in self.statements: + continue for prev_lineno in prev_lines: self.arcs.add((prev_lineno, lineno)) prev_lines = self.add_arcs(body_node) diff --git a/tests/test_arcs.py b/tests/test_arcs.py index c8814779..27b8c50b 100644 --- a/tests/test_arcs.py +++ b/tests/test_arcs.py @@ -956,7 +956,6 @@ class MiscArcTest(CoverageTest): ) def test_optimized_away_lines(self): - self.skip("TODO: fix this test") self.check_coverage("""\ a = 1 if len([2]): @@ -968,6 +967,7 @@ class MiscArcTest(CoverageTest): """, lines=[1, 2, 3, 7], arcz=".1 12 23 27 37 7.", + arcz_missing="27", ) |