[Python-checkins] GH-93662: Make sure that column offsets are correct in multi-line method calls. (GH-93673)

markshannon webhook-mailer at python.org
Tue Jun 14 06:08:47 EDT 2022


https://github.com/python/cpython/commit/2bf74753c14e5360e04930b478703f4e2618f4a3
commit: 2bf74753c14e5360e04930b478703f4e2618f4a3
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2022-06-14T11:08:12+01:00
summary:

GH-93662: Make sure that column offsets are correct in multi-line method calls. (GH-93673)

files:
A Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst
M Lib/test/test_code.py
M Python/compile.c

diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
index 1bb138e7f3243..a6857dc4f8412 100644
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -574,6 +574,15 @@ def positions_from_location_table(code):
         for _ in range(length):
             yield (line, end_line, col, end_col)
 
+def dedup(lst, prev=object()):
+    for item in lst:
+        if item != prev:
+            yield item
+            prev = item
+
+def lines_from_postions(positions):
+    return dedup(l for (l, _, _, _) in positions)
+
 def misshappen():
     """
 
@@ -606,6 +615,13 @@ def misshappen():
 
         ) else p
 
+def bug93662():
+    example_report_generation_message= (
+            """
+            """
+    ).strip()
+    raise ValueError()
+
 
 class CodeLocationTest(unittest.TestCase):
 
@@ -616,10 +632,23 @@ def check_positions(self, func):
             self.assertEqual(l1, l2)
         self.assertEqual(len(pos1), len(pos2))
 
-
     def test_positions(self):
         self.check_positions(parse_location_table)
         self.check_positions(misshappen)
+        self.check_positions(bug93662)
+
+    def check_lines(self, func):
+        co = func.__code__
+        lines1 = list(dedup(l for (_, _, l) in co.co_lines()))
+        lines2 = list(lines_from_postions(positions_from_location_table(co)))
+        for l1, l2 in zip(lines1, lines2):
+            self.assertEqual(l1, l2)
+        self.assertEqual(len(lines1), len(lines2))
+
+    def test_lines(self):
+        self.check_lines(parse_location_table)
+        self.check_lines(misshappen)
+        self.check_lines(bug93662)
 
 
 if check_impl_detail(cpython=True) and ctypes is not None:
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst
new file mode 100644
index 0000000000000..e444a00cf7ecc
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-10-10-31-18.gh-issue-93662.-7RSC1.rst	
@@ -0,0 +1,2 @@
+Make sure that the end column offsets are correct in multi-line method
+calls. Previously, the end column could precede the column offset.
diff --git a/Python/compile.c b/Python/compile.c
index b922e0145451e..93aafa78f8558 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -4801,6 +4801,16 @@ is_import_originated(struct compiler *c, expr_ty e)
     return flags & DEF_IMPORT;
 }
 
+static void
+update_location_to_match_attr(struct compiler *c, expr_ty meth)
+{
+    if (meth->lineno != meth->end_lineno) {
+        // Make start location match attribute
+        c->u->u_lineno = meth->end_lineno;
+        c->u->u_col_offset = meth->end_col_offset - (int)PyUnicode_GetLength(meth->v.Attribute.attr)-1;
+    }
+}
+
 // Return 1 if the method call was optimized, -1 if not, and 0 on error.
 static int
 maybe_optimize_method_call(struct compiler *c, expr_ty e)
@@ -4842,8 +4852,8 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
     }
     /* Alright, we can optimize the code. */
     VISIT(c, expr, meth->v.Attribute.value);
-    int old_lineno = c->u->u_lineno;
-    c->u->u_lineno = meth->end_lineno;
+    SET_LOC(c, meth);
+    update_location_to_match_attr(c, meth);
     ADDOP_NAME(c, LOAD_METHOD, meth->v.Attribute.attr, names);
     VISIT_SEQ(c, expr, e->v.Call.args);
 
@@ -4853,8 +4863,9 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
             return 0;
         };
     }
+    SET_LOC(c, e);
+    update_location_to_match_attr(c, meth);
     ADDOP_I(c, CALL, argsl + kwdsl);
-    c->u->u_lineno = old_lineno;
     return 1;
 }
 
@@ -7673,6 +7684,7 @@ write_location_info_short_form(struct assembler* a, int length, int column, int
     int column_low_bits = column & 7;
     int column_group = column >> 3;
     assert(column < 80);
+    assert(end_column >= column);
     assert(end_column - column < 16);
     write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length);
     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)
         }
     }
     else if (i->i_end_lineno == i->i_lineno) {
-        if (line_delta == 0 && column < 80 && end_column - column < 16) {
+        if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) {
             write_location_info_short_form(a, isize, column, end_column);
             return 1;
         }



More information about the Python-checkins mailing list