From 51a044cc702d842c28748fb448d063511cfc1ab0 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 22 Mar 2020 12:37:01 +0100 Subject: [PATCH] Fix diff parser: Invalid dedents meant that sometimes the wrong parents were chosen, fixes davidhalter/jedi#1499 --- parso/python/diff.py | 11 ++++++++++- test/test_diff_parser.py | 30 ++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/parso/python/diff.py b/parso/python/diff.py index 2dcf027..f6c26a0 100644 --- a/parso/python/diff.py +++ b/parso/python/diff.py @@ -281,10 +281,19 @@ class DiffParser(object): else: p_children = line_stmt.parent.children index = p_children.index(line_stmt) + p_children = p_children[index:] + # There might be a random dedent where we have to stop copying. + # Invalid indents are ok, because the parser handled that + # properly before. An invalid dedent can happen, because a few + # lines above there was an invalid indent. + indentation = line_stmt.start_pos[1] + for i, c in enumerate(p_children): + if c.start_pos[1] < indentation: + p_children = p_children[:i] from_ = self._nodes_tree.parsed_until_line + 1 copied_nodes = self._nodes_tree.copy_nodes( - p_children[index:], + p_children, until_line_old, line_offset ) diff --git a/test/test_diff_parser.py b/test/test_diff_parser.py index d7e6b89..624d9ea 100644 --- a/test/test_diff_parser.py +++ b/test/test_diff_parser.py @@ -845,8 +845,8 @@ def test_indentation_issues(differ): differ.initialize(code1) differ.parse(code2, parsers=2, copies=2, expect_error_leaves=True) - differ.parse(code1, copies=2) - differ.parse(code3, parsers=2, copies=1) + differ.parse(code1, copies=2, parsers=1) + differ.parse(code3, parsers=1, copies=1) differ.parse(code1, parsers=1, copies=2) @@ -1305,3 +1305,29 @@ def test_async_copy(differ): differ.initialize(code1) differ.parse(code2, copies=1, parsers=1) differ.parse(code1, copies=1, parsers=1, expect_error_leaves=True) + + +def test_parent_on_decorator(differ): + code1 = dedent('''\ + class AClass: + @decorator() + def b_test(self): + print("Hello") + print("world") + + def a_test(self): + pass''') + code2 = dedent('''\ + class AClass: + @decorator() + def b_test(self): + print("Hello") + print("world") + + def a_test(self): + pass''') + differ.initialize(code1) + module_node = differ.parse(code2, copies=2, parsers=1) + cls = module_node.children[0] + cls_suite = cls.children[-1] + assert len(cls_suite.children) == 3