mirror of
https://github.com/python/cpython.git
synced 2025-08-30 05:35:08 +00:00
[3.11] GH-94694: Fix column offsets for multi-line method lookups (GH-94721)
(cherry picked from commit 264b3ddfd5
)
This commit is contained in:
parent
7b5737a51a
commit
e5c8ad3e15
4 changed files with 85 additions and 2 deletions
|
@ -1145,6 +1145,27 @@ f(
|
||||||
self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
|
self.assertOpcodeSourcePositionIs(compiled_code, 'BINARY_OP',
|
||||||
line=1, end_line=1, column=0, end_column=27, occurrence=4)
|
line=1, end_line=1, column=0, end_column=27, occurrence=4)
|
||||||
|
|
||||||
|
def test_multiline_assert_rewritten_as_method_call(self):
|
||||||
|
# GH-94694: Don't crash if pytest rewrites a multiline assert as a
|
||||||
|
# method call with the same location information:
|
||||||
|
tree = ast.parse("assert (\n42\n)")
|
||||||
|
old_node = tree.body[0]
|
||||||
|
new_node = ast.Expr(
|
||||||
|
ast.Call(
|
||||||
|
ast.Attribute(
|
||||||
|
ast.Name("spam", ast.Load()),
|
||||||
|
"eggs",
|
||||||
|
ast.Load(),
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ast.copy_location(new_node, old_node)
|
||||||
|
ast.fix_missing_locations(new_node)
|
||||||
|
tree.body[0] = new_node
|
||||||
|
compile(tree, "<test>", "exec")
|
||||||
|
|
||||||
|
|
||||||
class TestExpressionStackSize(unittest.TestCase):
|
class TestExpressionStackSize(unittest.TestCase):
|
||||||
# These tests check that the computed stack size for a code object
|
# These tests check that the computed stack size for a code object
|
||||||
|
|
|
@ -703,6 +703,57 @@ class TracebackErrorLocationCaretTests(unittest.TestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(result_lines, expected_error.splitlines())
|
self.assertEqual(result_lines, expected_error.splitlines())
|
||||||
|
|
||||||
|
def test_multiline_method_call_a(self):
|
||||||
|
def f():
|
||||||
|
(None
|
||||||
|
.method
|
||||||
|
)()
|
||||||
|
actual = self.get_exception(f)
|
||||||
|
expected = [
|
||||||
|
f"Traceback (most recent call last):",
|
||||||
|
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
|
||||||
|
f" callable()",
|
||||||
|
f" ^^^^^^^^^^",
|
||||||
|
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
|
||||||
|
f" .method",
|
||||||
|
f" ^^^^^^",
|
||||||
|
]
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_multiline_method_call_b(self):
|
||||||
|
def f():
|
||||||
|
(None.
|
||||||
|
method
|
||||||
|
)()
|
||||||
|
actual = self.get_exception(f)
|
||||||
|
expected = [
|
||||||
|
f"Traceback (most recent call last):",
|
||||||
|
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
|
||||||
|
f" callable()",
|
||||||
|
f" ^^^^^^^^^^",
|
||||||
|
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
|
||||||
|
f" method",
|
||||||
|
f" ^^^^^^",
|
||||||
|
]
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_multiline_method_call_c(self):
|
||||||
|
def f():
|
||||||
|
(None
|
||||||
|
. method
|
||||||
|
)()
|
||||||
|
actual = self.get_exception(f)
|
||||||
|
expected = [
|
||||||
|
f"Traceback (most recent call last):",
|
||||||
|
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
|
||||||
|
f" callable()",
|
||||||
|
f" ^^^^^^^^^^",
|
||||||
|
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
|
||||||
|
f" . method",
|
||||||
|
f" ^^^^^^",
|
||||||
|
]
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
@cpython_only
|
@cpython_only
|
||||||
@requires_debug_ranges()
|
@requires_debug_ranges()
|
||||||
class CPythonTracebackErrorCaretTests(TracebackErrorLocationCaretTests):
|
class CPythonTracebackErrorCaretTests(TracebackErrorLocationCaretTests):
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Fix an issue that could cause code with multi-line method lookups to have
|
||||||
|
misleading or incorrect column offset information. In some cases (when
|
||||||
|
compiling a hand-built AST) this could have resulted in a hard crash of the
|
||||||
|
interpreter.
|
|
@ -4788,8 +4788,15 @@ update_location_to_match_attr(struct compiler *c, expr_ty meth)
|
||||||
{
|
{
|
||||||
if (meth->lineno != meth->end_lineno) {
|
if (meth->lineno != meth->end_lineno) {
|
||||||
// Make start location match attribute
|
// Make start location match attribute
|
||||||
c->u->u_lineno = meth->end_lineno;
|
c->u->u_lineno = c->u->u_end_lineno = meth->end_lineno;
|
||||||
c->u->u_col_offset = meth->end_col_offset - (int)PyUnicode_GetLength(meth->v.Attribute.attr)-1;
|
int len = (int)PyUnicode_GET_LENGTH(meth->v.Attribute.attr);
|
||||||
|
if (len <= meth->end_col_offset) {
|
||||||
|
c->u->u_col_offset = meth->end_col_offset - len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// GH-94694: Somebody's compiling weird ASTs. Just drop the columns:
|
||||||
|
c->u->u_col_offset = c->u->u_end_col_offset = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue