Skip to content

Commit b6d1710

Browse files
Changed NodeNG.tolineno to use end_lineno when it is available (#1351)
Co-authored-by: Daniël van Noord <[email protected]>
1 parent 0acb961 commit b6d1710

File tree

6 files changed

+34
-10
lines changed

6 files changed

+34
-10
lines changed

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ Release date: TBA
3434

3535
Closes #1330
3636

37+
* Use the ``end_lineno`` attribute for the ``NodeNG.tolineno`` property
38+
when it is available.
39+
40+
Closes #1350
41+
3742
* Add ``is_dataclass`` attribute to ``ClassDef`` nodes.
3843

3944
* Use ``sysconfig`` instead of ``distutils`` to determine the location of

astroid/nodes/node_ng.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ def fromlineno(self) -> Optional[int]:
445445
@decorators.cachedproperty
446446
def tolineno(self) -> Optional[int]:
447447
"""The last line that this node appears on in the source code."""
448+
if self.end_lineno is not None:
449+
return self.end_lineno
448450
if not self._astroid_fields:
449451
# can't have children
450452
last_child = None

astroid/rebuilder.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,11 +2197,21 @@ def visit_starred(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred:
21972197
def visit_tryexcept(self, node: "ast.Try", parent: NodeNG) -> nodes.TryExcept:
21982198
"""visit a TryExcept node by returning a fresh instance of it"""
21992199
if sys.version_info >= (3, 8):
2200+
# TryExcept excludes the 'finally' but that will be included in the
2201+
# end_lineno from 'node'. Therefore, we check all non 'finally'
2202+
# children to find the correct end_lineno and column.
2203+
end_lineno = node.end_lineno
2204+
end_col_offset = node.end_col_offset
2205+
all_children: List["ast.AST"] = [*node.body, *node.handlers, *node.orelse]
2206+
for child in reversed(all_children):
2207+
end_lineno = child.end_lineno
2208+
end_col_offset = child.end_col_offset
2209+
break
22002210
newnode = nodes.TryExcept(
22012211
lineno=node.lineno,
22022212
col_offset=node.col_offset,
2203-
end_lineno=node.end_lineno,
2204-
end_col_offset=node.end_col_offset,
2213+
end_lineno=end_lineno,
2214+
end_col_offset=end_col_offset,
22052215
parent=parent,
22062216
)
22072217
else:

tests/unittest_builder.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,14 @@ def test_callfunc_lineno(self) -> None:
7676
strarg = callfunc.args[0]
7777
self.assertIsInstance(strarg, nodes.Const)
7878
if hasattr(sys, "pypy_version_info"):
79-
lineno = 4
79+
self.assertEqual(strarg.fromlineno, 4)
80+
self.assertEqual(strarg.tolineno, 4)
8081
else:
81-
lineno = 5 if not PY38_PLUS else 4
82-
self.assertEqual(strarg.fromlineno, lineno)
83-
self.assertEqual(strarg.tolineno, lineno)
82+
if not PY38_PLUS:
83+
self.assertEqual(strarg.fromlineno, 5)
84+
else:
85+
self.assertEqual(strarg.fromlineno, 4)
86+
self.assertEqual(strarg.tolineno, 5)
8487
namearg = callfunc.args[1]
8588
self.assertIsInstance(namearg, nodes.Name)
8689
self.assertEqual(namearg.fromlineno, 5)

tests/unittest_nodes_lineno.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ def test_end_lineno_try() -> None:
784784
assert (t3.lineno, t3.col_offset) == (10, 0)
785785
assert (t3.end_lineno, t3.end_col_offset) == (17, 8)
786786
assert (t3.body[0].lineno, t3.body[0].col_offset) == (10, 0)
787-
assert (t3.body[0].end_lineno, t3.body[0].end_col_offset) == (17, 8)
787+
assert (t3.body[0].end_lineno, t3.body[0].end_col_offset) == (15, 8)
788788
assert (t3.finalbody[0].lineno, t3.finalbody[0].col_offset) == (17, 4)
789789
assert (t3.finalbody[0].end_lineno, t3.finalbody[0].end_col_offset) == (17, 8)
790790

tests/unittest_scoped_nodes.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,15 +1092,19 @@ def g1(x):
10921092
print(x)
10931093
10941094
@f(a=2,
1095-
b=3)
1095+
b=3,
1096+
)
10961097
def g2():
10971098
pass
10981099
"""
10991100
astroid = builder.parse(data)
11001101
self.assertEqual(astroid["g1"].fromlineno, 4)
11011102
self.assertEqual(astroid["g1"].tolineno, 5)
1102-
self.assertEqual(astroid["g2"].fromlineno, 9)
1103-
self.assertEqual(astroid["g2"].tolineno, 10)
1103+
if not PY38_PLUS:
1104+
self.assertEqual(astroid["g2"].fromlineno, 9)
1105+
else:
1106+
self.assertEqual(astroid["g2"].fromlineno, 10)
1107+
self.assertEqual(astroid["g2"].tolineno, 11)
11041108

11051109
def test_metaclass_error(self) -> None:
11061110
astroid = builder.parse(

0 commit comments

Comments
 (0)