summaryrefslogtreecommitdiff
path: root/coverage/tracer.c
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2015-04-20 12:15:37 -0400
committerNed Batchelder <ned@nedbatchelder.com>2015-04-20 12:15:37 -0400
commitde4cfde7b1f7b3d3bee11a26b4c1bb3ae598259c (patch)
treeff4911093102a0888abc6563f6fca31ebfc62a2e /coverage/tracer.c
parentdd20fcfbcce90933099b10629424dc0cccafc5db (diff)
downloadpython-coveragepy-git-de4cfde7b1f7b3d3bee11a26b4c1bb3ae598259c.tar.gz
Fix branch coverage for yield statements. #308 #324
Turns out the "call" and "return" trace events are really "start frame" and "end frame". They happen not only when functions are entered and left, but when generators yield and resume. We aren't interested in arcs into and out of yield statements, so the trace functions look more closely to see what's really happening, and record an arc in human-friendly terms. Thanks for Mickie Betz for pushing on this bug, although her code is no longer here. :(
Diffstat (limited to 'coverage/tracer.c')
-rw-r--r--coverage/tracer.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/coverage/tracer.c b/coverage/tracer.c
index 43ecd188..d532dcce 100644
--- a/coverage/tracer.c
+++ b/coverage/tracer.c
@@ -3,6 +3,7 @@
#include "Python.h"
#include "structmember.h"
#include "frameobject.h"
+#include "opcode.h"
/* Compile-time debugging helpers */
#undef WHAT_LOG /* Define to log the WHAT params in the trace function. */
@@ -596,7 +597,11 @@ CTracer_handle_call(CTracer *self, PyFrameObject *frame)
SHOWLOG(self->pdata_stack->depth, frame->f_lineno, filename, "skipped");
}
- self->cur_entry.last_line = -1;
+ /* A call event is really a "start frame" event, and can happen for
+ * re-entering a generator also. f_lasti is -1 for a true call, and a
+ * real byte offset for a generator re-entry.
+ */
+ self->cur_entry.last_line = (frame->f_lasti < 0) ? -1 : frame->f_lineno;
ret = RET_OK;
@@ -685,9 +690,13 @@ CTracer_handle_return(CTracer *self, PyFrameObject *frame)
}
if (self->pdata_stack->depth >= 0) {
if (self->tracing_arcs && self->cur_entry.file_data) {
- int first = frame->f_code->co_firstlineno;
- if (CTracer_record_pair(self, self->cur_entry.last_line, -first) < 0) {
- goto error;
+ /* Need to distinguish between RETURN_VALUE and YIELD_VALUE. */
+ int bytecode = MyText_AS_STRING(frame->f_code->co_code)[frame->f_lasti];
+ if (bytecode != YIELD_VALUE) {
+ int first = frame->f_code->co_firstlineno;
+ if (CTracer_record_pair(self, self->cur_entry.last_line, -first) < 0) {
+ goto error;
+ }
}
}