diff --git a/CHANGELOG.md b/CHANGELOG.md index 1650aa77..f269f11d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - #623, #819, #863 Support MatchOr, MatchSequence, MatchStar (@jheld, @lieryan) - #870 Add default implementation for is_dir() (@lieryan) - #872 Fix unicode handling in patchedast (@lieryan) +- #862 Recognize type alias statements as assignments in rename refactoring (@TanbirRamim) # Release 1.14.0 diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 95bd1569..e07f69f3 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -371,6 +371,12 @@ def _Assign(self, node): self.visit(child_node) _ExpressionVisitor(self.scope_visitor).visit(node.value) + def _TypeAlias(self, node): + # the alias value is not recorded as an assigned value: a type + # alias is a distinct TypeAliasType object whose value is evaluated + # lazily, so substituting the value for the alias name is unsafe + self.visit(node.name) + def _assigned(self, name, assignment=None): self.scope_visitor._assigned(name, assignment) @@ -451,6 +457,9 @@ def _Assign(self, node): def _AnnAssign(self, node): _AnnAssignVisitor(self).visit(node) + def _TypeAlias(self, node): + _AssignVisitor(self).visit(node) + def _AugAssign(self, node): pass diff --git a/ropetest/refactor/inlinetest.py b/ropetest/refactor/inlinetest.py index 585214b4..79d807aa 100644 --- a/ropetest/refactor/inlinetest.py +++ b/ropetest/refactor/inlinetest.py @@ -42,6 +42,37 @@ def test_empty_case(self): refactored = self._inline(code, code.index("a_var") + 1) self.assertEqual("", refactored) + @testutils.only_for_versions_higher("3.12") + def test_inlining_type_alias_is_refused(self): + code = dedent("""\ + type an_alias = int + value = an_alias.__value__ + """) + with self.assertRaises(rope.base.exceptions.RefactoringError): + self._inline(code, code.index("an_alias") + 1) + + @testutils.only_for_versions_higher("3.12") + def test_inlining_lazily_evaluated_type_alias_is_refused(self): + code = dedent("""\ + type an_alias = Later + def a_func(param: an_alias): + pass + class Later: + pass + """) + with self.assertRaises(rope.base.exceptions.RefactoringError): + self._inline(code, code.index("an_alias") + 1) + + @testutils.only_for_versions_higher("3.12") + def test_inlining_generic_type_alias(self): + code = dedent("""\ + type an_alias[T] = list[T] + def a_func(param: an_alias[int]): + pass + """) + with self.assertRaises(rope.base.exceptions.RefactoringError): + self._inline(code, code.index("an_alias") + 1) + def test_long_definition(self): code = dedent("""\ a_var = 10 + (10 + 10) diff --git a/ropetest/refactor/renametest.py b/ropetest/refactor/renametest.py index 9303fb15..764750ee 100644 --- a/ropetest/refactor/renametest.py +++ b/ropetest/refactor/renametest.py @@ -242,6 +242,74 @@ def test_renaming_inline_assignment(self): refactored, ) + @testutils.only_for_versions_higher("3.12") + def test_renaming_type_alias(self): + code = dedent("""\ + type old_name = int + x: old_name = 1 + """) + refactored = self._local_rename(code, code.index("old_name") + 1, "new_name") + self.assertEqual( + dedent("""\ + type new_name = int + x: new_name = 1 + """), + refactored, + ) + + @testutils.only_for_versions_higher("3.12") + def test_renaming_type_alias_from_its_usage(self): + code = dedent("""\ + type old_name = int + def a_func(param: old_name) -> old_name: + pass + """) + offset = code.rindex("old_name") + 1 + refactored = self._local_rename(code, offset, "new_name") + self.assertEqual( + dedent("""\ + type new_name = int + def a_func(param: new_name) -> new_name: + pass + """), + refactored, + ) + + @testutils.only_for_versions_higher("3.12") + def test_renaming_type_alias_in_function_scope(self): + code = dedent("""\ + old_name = 1 + def a_func(): + type old_name = int + x: old_name = 1 + """) + offset = code.index("old_name", code.index("type")) + 1 + refactored = self._local_rename(code, offset, "new_name") + self.assertEqual( + dedent("""\ + old_name = 1 + def a_func(): + type new_name = int + x: new_name = 1 + """), + refactored, + ) + + @testutils.only_for_versions_higher("3.12") + def test_renaming_generic_type_alias(self): + code = dedent("""\ + type OldAlias[T] = list[T] + x: OldAlias[int] = [] + """) + refactored = self._local_rename(code, code.index("OldAlias") + 1, "NewAlias") + self.assertEqual( + dedent("""\ + type NewAlias[T] = list[T] + x: NewAlias[int] = [] + """), + refactored, + ) + def test_renaming_arguments_for_normal_args_changing_calls(self): code = dedent("""\ def a_func(p1=None, p2=None):