Skip to content

Commit 483f3d0

Browse files
markshannoniritkatriel
authored andcommitted
pythonGH-93662: Make sure that column offsets are correct in multi-line method calls. (pythonGH-93673)
1 parent 6e28032 commit 483f3d0

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

Lib/test/test_code.py

+30-1
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,15 @@ def positions_from_location_table(code):
574574
for _ in range(length):
575575
yield (line, end_line, col, end_col)
576576

577+
def dedup(lst, prev=object()):
578+
for item in lst:
579+
if item != prev:
580+
yield item
581+
prev = item
582+
583+
def lines_from_postions(positions):
584+
return dedup(l for (l, _, _, _) in positions)
585+
577586
def misshappen():
578587
"""
579588
@@ -606,6 +615,13 @@ def misshappen():
606615

607616
) else p
608617

618+
def bug93662():
619+
example_report_generation_message= (
620+
"""
621+
"""
622+
).strip()
623+
raise ValueError()
624+
609625

610626
class CodeLocationTest(unittest.TestCase):
611627

@@ -616,10 +632,23 @@ def check_positions(self, func):
616632
self.assertEqual(l1, l2)
617633
self.assertEqual(len(pos1), len(pos2))
618634

619-
620635
def test_positions(self):
621636
self.check_positions(parse_location_table)
622637
self.check_positions(misshappen)
638+
self.check_positions(bug93662)
639+
640+
def check_lines(self, func):
641+
co = func.__code__
642+
lines1 = list(dedup(l for (_, _, l) in co.co_lines()))
643+
lines2 = list(lines_from_postions(positions_from_location_table(co)))
644+
for l1, l2 in zip(lines1, lines2):
645+
self.assertEqual(l1, l2)
646+
self.assertEqual(len(lines1), len(lines2))
647+
648+
def test_lines(self):
649+
self.check_lines(parse_location_table)
650+
self.check_lines(misshappen)
651+
self.check_lines(bug93662)
623652

624653

625654
if check_impl_detail(cpython=True) and ctypes is not None:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Make sure that the end column offsets are correct in multi-line method
2+
calls. Previously, the end column could precede the column offset.

Python/compile.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -4780,6 +4780,16 @@ is_import_originated(struct compiler *c, expr_ty e)
47804780
return flags & DEF_IMPORT;
47814781
}
47824782

4783+
static void
4784+
update_location_to_match_attr(struct compiler *c, expr_ty meth)
4785+
{
4786+
if (meth->lineno != meth->end_lineno) {
4787+
// Make start location match attribute
4788+
c->u->u_lineno = meth->end_lineno;
4789+
c->u->u_col_offset = meth->end_col_offset - (int)PyUnicode_GetLength(meth->v.Attribute.attr)-1;
4790+
}
4791+
}
4792+
47834793
// Return 1 if the method call was optimized, -1 if not, and 0 on error.
47844794
static int
47854795
maybe_optimize_method_call(struct compiler *c, expr_ty e)
@@ -4821,8 +4831,8 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
48214831
}
48224832
/* Alright, we can optimize the code. */
48234833
VISIT(c, expr, meth->v.Attribute.value);
4824-
int old_lineno = c->u->u_lineno;
4825-
c->u->u_lineno = meth->end_lineno;
4834+
SET_LOC(c, meth);
4835+
update_location_to_match_attr(c, meth);
48264836
ADDOP_NAME(c, LOAD_METHOD, meth->v.Attribute.attr, names);
48274837
VISIT_SEQ(c, expr, e->v.Call.args);
48284838

@@ -4832,9 +4842,10 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
48324842
return 0;
48334843
};
48344844
}
4845+
SET_LOC(c, e);
4846+
update_location_to_match_attr(c, meth);
48354847
ADDOP_I(c, PRECALL, argsl + kwdsl);
48364848
ADDOP_I(c, CALL, argsl + kwdsl);
4837-
c->u->u_lineno = old_lineno;
48384849
return 1;
48394850
}
48404851

@@ -7508,6 +7519,7 @@ write_location_info_short_form(struct assembler* a, int length, int column, int
75087519
int column_low_bits = column & 7;
75097520
int column_group = column >> 3;
75107521
assert(column < 80);
7522+
assert(end_column >= column);
75117523
assert(end_column - column < 16);
75127524
write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length);
75137525
write_location_byte(a, (column_low_bits << 4) | (end_column - column));
@@ -7579,7 +7591,7 @@ write_location_info_entry(struct assembler* a, struct instr* i, int isize)
75797591
}
75807592
}
75817593
else if (i->i_end_lineno == i->i_lineno) {
7582-
if (line_delta == 0 && column < 80 && end_column - column < 16) {
7594+
if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) {
75837595
write_location_info_short_form(a, isize, column, end_column);
75847596
return 1;
75857597
}

0 commit comments

Comments
 (0)