Skip to content

Commit 2bf7475

Browse files
authored
GH-93662: Make sure that column offsets are correct in multi-line method calls. (GH-93673)
1 parent 4caf5c2 commit 2bf7475

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

Lib/test/test_code.py

Lines changed: 30 additions & 1 deletion
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:
Lines changed: 2 additions & 0 deletions
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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4801,6 +4801,16 @@ is_import_originated(struct compiler *c, expr_ty e)
48014801
return flags & DEF_IMPORT;
48024802
}
48034803

4804+
static void
4805+
update_location_to_match_attr(struct compiler *c, expr_ty meth)
4806+
{
4807+
if (meth->lineno != meth->end_lineno) {
4808+
// Make start location match attribute
4809+
c->u->u_lineno = meth->end_lineno;
4810+
c->u->u_col_offset = meth->end_col_offset - (int)PyUnicode_GetLength(meth->v.Attribute.attr)-1;
4811+
}
4812+
}
4813+
48044814
// Return 1 if the method call was optimized, -1 if not, and 0 on error.
48054815
static int
48064816
maybe_optimize_method_call(struct compiler *c, expr_ty e)
@@ -4842,8 +4852,8 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
48424852
}
48434853
/* Alright, we can optimize the code. */
48444854
VISIT(c, expr, meth->v.Attribute.value);
4845-
int old_lineno = c->u->u_lineno;
4846-
c->u->u_lineno = meth->end_lineno;
4855+
SET_LOC(c, meth);
4856+
update_location_to_match_attr(c, meth);
48474857
ADDOP_NAME(c, LOAD_METHOD, meth->v.Attribute.attr, names);
48484858
VISIT_SEQ(c, expr, e->v.Call.args);
48494859

@@ -4853,8 +4863,9 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
48534863
return 0;
48544864
};
48554865
}
4866+
SET_LOC(c, e);
4867+
update_location_to_match_attr(c, meth);
48564868
ADDOP_I(c, CALL, argsl + kwdsl);
4857-
c->u->u_lineno = old_lineno;
48584869
return 1;
48594870
}
48604871

@@ -7673,6 +7684,7 @@ write_location_info_short_form(struct assembler* a, int length, int column, int
76737684
int column_low_bits = column & 7;
76747685
int column_group = column >> 3;
76757686
assert(column < 80);
7687+
assert(end_column >= column);
76767688
assert(end_column - column < 16);
76777689
write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length);
76787690
write_location_byte(a, (column_low_bits << 4) | (end_column - column));
@@ -7744,7 +7756,7 @@ write_location_info_entry(struct assembler* a, struct instr* i, int isize)
77447756
}
77457757
}
77467758
else if (i->i_end_lineno == i->i_lineno) {
7747-
if (line_delta == 0 && column < 80 && end_column - column < 16) {
7759+
if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) {
77487760
write_location_info_short_form(a, isize, column, end_column);
77497761
return 1;
77507762
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy