summaryrefslogtreecommitdiff
path: root/coverage/parser.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2009-11-23 09:23:01 -0500
committerNed Batchelder <ned@nedbatchelder.com>2009-11-23 09:23:01 -0500
commite6505f52fca89539613df3bcd82b39624d14e22f (patch)
tree3ff8ff626f1e9f8c6cc43fd04990e516e8148517 /coverage/parser.py
parent7dd0e1ec7abda0f8f9609c10f988792b26a1768e (diff)
downloadpython-coveragepy-git-e6505f52fca89539613df3bcd82b39624d14e22f.tar.gz
ByteParser now recognizes synthetic 'return None' blocks and treats them correctly.
Diffstat (limited to 'coverage/parser.py')
-rw-r--r--coverage/parser.py27
1 files changed, 27 insertions, 0 deletions
diff --git a/coverage/parser.py b/coverage/parser.py
index 09050548..3e55ad6d 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -273,6 +273,8 @@ OP_BREAK_LOOP = _opcode('BREAK_LOOP')
OP_END_FINALLY = _opcode('END_FINALLY')
OP_COMPARE_OP = _opcode('COMPARE_OP')
COMPARE_EXCEPTION = 10 # just have to get this const from the code.
+OP_LOAD_CONST = _opcode('LOAD_CONST')
+OP_RETURN_VALUE = _opcode('RETURN_VALUE')
class ByteParser(object):
@@ -393,6 +395,9 @@ class ByteParser(object):
# is a count of how many ignores are left.
ignore_branch = 0
+ # We have to handle the last two bytecodes specially.
+ ult = penult = None
+
for bc in ByteCodes(self.code.co_code):
# Maybe have to start a new block
if bc.offset in bytes_lines_map:
@@ -445,8 +450,30 @@ class ByteParser(object):
# This is an except clause. We want to overlook the next
# branch, so that except's don't count as branches.
ignore_branch += 1
+
+ penult = ult
+ ult = bc
+
if chunks:
+ # The last two bytecodes could be a dummy "return None" that
+ # shouldn't be counted as real code. Every Python code object seems
+ # to end with a return, and a "return None" is inserted if there
+ # isn't an explicit return in the source.
+ if ult and penult:
+ if penult.op == OP_LOAD_CONST and ult.op == OP_RETURN_VALUE:
+ if self.code.co_consts[penult.arg] is None:
+ # This is "return None", but is it dummy? A real line
+ # would be a last chunk all by itself.
+ if chunks[-1].byte != penult.offset:
+ last_chunk = chunks[-1]
+ last_chunk.exits.remove(-1)
+ last_chunk.exits.add(penult.offset)
+ chunk = Chunk(penult.offset)
+ chunk.exits.add(-1)
+ chunks.append(chunk)
+
+ # Give all the chunks a length.
chunks[-1].length = bc.next_offset - chunks[-1].byte
for i in range(len(chunks)-1):
chunks[i].length = chunks[i+1].byte - chunks[i].byte