8000 GH-94036: Fix more attribute location quirks (GH-95028) · python/cpython@900bfc5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 900bfc5

Browse files
authored
GH-94036: Fix more attribute location quirks (GH-95028)
1 parent 34d11f1 commit 900bfc5

File tree

3 files changed

+85
-20
lines changed

3 files changed

+85
-20
lines changed

Lib/test/test_compile.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,66 @@ def f():
12401240
end_column=7,
12411241
)
12421242

1243+
def test_attribute_augassign(self):
1244+
source = "(\n lhs \n . \n rhs \n ) += 42"
1245+
code = compile(source, "<test>", "exec")
1246+
self.assertOpcodeSourcePositionIs(
1247+
code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
1248+
)
1249+
self.assertOpcodeSourcePositionIs(
1250+
code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8
1251+
)
1252+
1253+
def test_attribute_del(self):
1254+
source = "del (\n lhs \n . \n rhs \n )"
1255+
code = compile(source, "<test>", "exec")
1256+
self.assertOpcodeSourcePositionIs(
1257+
code, "DELETE_ATTR", line=4, end_line=4, column=5, end_column=8
1258+
)
1259+
1260+
def test_attribute_load(self):
1261+
source = "(\n lhs \n . \n rhs \n )"
1262+
code = compile(source, "<test>", "exec")
1263+
self.assertOpcodeSourcePositionIs(
1264+
code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
1265+
)
1266+
1267+
def test_attribute_store(self):
1268+
source = "(\n lhs \n . \n rhs \n ) = 42"
1269+
code = compile(source, "<test>", "exec")
1270+
self.assertOpcodeSourcePositionIs(
1271+
code, "STORE_ATTR", line=4, end_line=4, column=5, end_column=8
1272+
)
1273+
1274+
def test_method_call(self):
1275+
source = "(\n lhs \n . \n rhs \n )()"
1276+
code = compile(source, "<test>", "exec")
1277+
self.assertOpcodeSourcePositionIs(
1278+
code, "LOAD_ATTR", line=4, end_line=4, column=5, end_column=8
1279+
)
1280+
self.assertOpcodeSourcePositionIs(
1281+
code, "CALL", line=4, end_line=5, column=5, end_column=10
1282+
)
1283+
1284+
def test_weird_attribute_position_regressions(self):
1285+
def f():
1286+
(bar.
1287+
baz)
1288+
(bar.
1289+
baz(
1290+
))
1291+
files().setdefault(
1292+
0
1293+
).setdefault(
1294+
0
1295+
)
1296+
for line, end_line, column, end_column in f.__code__.co_positions():
1297+
self.assertIsNotNone(line)
1298+
self.assertIsNotNone(end_line)
1299+
self.assertIsNotNone(column)
1300+
self.assertIsNotNone(end_column)
1301+
self.assertLessEqual((line, column), (end_line, end_column))
1302+
12431303

12441304
class TestExpressionStackSize(unittest.TestCase):
12451305
# These tests check that the computed stack size for a code object
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix incorrect source location info for some multi-line attribute accesses
2+
and method calls.

Python/compile.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4729,19 +4729,29 @@ is_import_originated(struct compiler *c, expr_ty e)
47294729
return flags & DEF_IMPORT;
47304730
}
47314731

4732+
// If an attribute access spans multiple lines, update the current start
4733+
// location to point to the attribute name.
47324734
static void
4733-
update_location_to_match_attr(struct compiler *c, expr_ty meth)
4735+
update_start_location_to_match_attr(struct compiler *c, expr_ty attr)
47344736
{
4735-
if (meth->lineno != meth->end_lineno) {
4736-
// Make start location match attribute
4737-
c->u->u_loc.lineno = c->u->u_loc.end_lineno = meth->end_lineno;
4738-
int len = (int)PyUnicode_GET_LENGTH(meth->v.Attribute.attr);
4739-
if (len <= meth->end_col_offset) {
4740-
c->u->u_loc.col_offset = meth->end_col_offset - len;
4737+
assert(attr->kind == Attribute_kind);
4738+
struct location *loc = &c->u->u_loc;
4739+
if (loc->lineno != attr->end_lineno) {
4740+
loc->lineno = attr->end_lineno;
4741+
int len = (int)PyUnicode_GET_LENGTH(attr->v.Attribute.attr);
4742+
if (len <= attr->end_col_offset) {
4743+
loc->col_offset = attr->end_col_offset - len;
47414744
}
47424745
else {
47434746
// GH-94694: Somebody's compiling weird ASTs. Just drop the columns:
4744-
c->u->u_loc.col_offset = c->u->u_loc.end_col_offset = -1;
4747+
loc->col_offset = -1;
4748+
loc->end_col_offset = -1;
4749+
}
4750+
// Make sure the end position still follows the start position, even for
4751+
// weird ASTs:
4752+
loc->end_lineno = Py_MAX(loc->lineno, loc->end_lineno);
4753+
if (loc->lineno == loc->end_lineno) {
4754+
loc->end_col_offset = Py_MAX(loc->col_offset, loc->end_col_offset);
47454755
}
47464756
}
47474757
}
@@ -4788,7 +4798,7 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
47884798
/* Alright, we can optimize the code. */
47894799
VISIT(c, expr, meth->v.Attribute.value);
47904800
SET_LOC(c, meth);
4791-
update_location_to_match_attr(c, meth);
4801+
update_start_location_to_match_attr(c, meth);
47924802
ADDOP_NAME(c, LOAD_METHOD, meth->v.Attribute.attr, names);
47934803
VISIT_SEQ(c, expr, e->v.Call.args);
47944804

@@ -4799,7 +4809,7 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
47994809
};
48004810
}
48014811
SET_LOC(c, e);
4802-
update_location_to_match_attr(c, meth);
4812+
update_start_location_to_match_attr(c, meth);
48034813
ADDOP_I(c, CALL, argsl + kwdsl);
48044814
return 1;
48054815
}
@@ -5811,23 +5821,18 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
58115821
/* The following exprs can be assignment targets. */
58125822
case Attribute_kind:
58135823
VISIT(c, expr, e->v.Attribute.value);
5824+
update_start_location_to_match_attr(c, e);
58145825
switch (e->v.Attribute.ctx) {
58155826
case Load:
58165827
{
5817-
int old_lineno = c->u->u_loc.lineno;
5818-
c->u->u_loc.lineno = e->end_lineno;
58195828
ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names);
5820-
c->u->u_loc.lineno = old_lineno;
58215829
break;
58225830
}
58235831
case Store:
58245832
if (forbidden_name(c, e->v.Attribute.attr, e->v.Attribute.ctx)) {
58255833
return 0;
58265834
}
5827-
int old_lineno = c->u->u_loc.lineno;
5828-
c->u->u_loc.lineno = e->end_lineno;
58295835
ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names);
5830-
c->u->u_loc.lineno = old_lineno;
58315836
break;
58325837
case Del:
58335838
ADDOP_NAME(c, DELETE_ATTR, e->v.Attribute.attr, names);
@@ -5898,10 +5903,8 @@ compiler_augassign(struct compiler *c, stmt_ty s)
58985903
case Attribute_kind:
58995904
VISIT(c, expr, e->v.Attribute.value);
59005905
ADDOP_I(c, COPY, 1);
5901-
int old_lineno = c->u->u_loc.lineno;
5902-
c->u->u_loc.lineno = e->end_lineno;
5906+
update_start_location_to_match_attr(c, e);
59035907
ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names);
5904-
c->u->u_loc.lineno = old_lineno;
59055908
break;
59065909
case Subscript_kind:
59075910
VISIT(c, expr, e->v.Subscript.value);
@@ -5941,7 +5944,7 @@ compiler_augassign(struct compiler *c, stmt_ty s)
59415944

59425945
switch (e->kind) {
59435946
case Attribute_kind:
5944-
c->u->u_loc.< 564B span class="pl-c1 x">lineno = e->end_lineno;
5947+
update_start_location_to_match_attr(c, e);
59455948
ADDOP_I(c, SWAP, 2);
59465949
ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names);
59475950
break;

0 commit comments

Comments
 (0)
0