From d2140d4e9d860fc0fff5c4d1e0eecea919dd87ef Mon Sep 17 00:00:00 2001 From: Isaac Hwang Date: Mon, 7 Aug 2023 12:23:03 -0700 Subject: [PATCH] Add Rename related constructs Summary: # Context: We want to set up Rename Symbols into few steps: 1. Enable textDocument/rename 2. Create constructs for Rename request/params/response/etc 3. Add logic to wrap references into rename response (test by hooking up references from Glean) 4. Add alternative methods to finding local references 5. Merge references from both local and global. These stack of diffs will address 1~3. # This Diff: Step 2: Create dataclasses to represent rename related data and add a new Rename method DaemonQueriers. Reviewed By: NgaiJustin Differential Revision: D47958509 fbshipit-source-id: 26041679f5a7609ae8747a0ee30217c69620a075 --- client/commands/daemon_querier.py | 48 +++++++++++++++++++++++++++ client/commands/tests/server_setup.py | 15 +++++++++ client/language_server/protocol.py | 26 ++++++++++++++- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/client/commands/daemon_querier.py b/client/commands/daemon_querier.py index c9bacb3364c..f0fa6a962c8 100644 --- a/client/commands/daemon_querier.py +++ b/client/commands/daemon_querier.py @@ -195,6 +195,15 @@ async def get_call_hierarchy_from_item( ) -> Union[daemon_query.DaemonQueryFailure, List[lsp.CallHierarchyItem]]: raise NotImplementedError() + @abc.abstractmethod + async def get_rename( + self, + path: Path, + position: lsp.PyrePosition, + new_text: str, + ) -> Union[daemon_query.DaemonQueryFailure, Optional[lsp.WorkspaceEdit]]: + raise NotImplementedError() + @abc.abstractmethod async def handle_file_opened( self, @@ -408,6 +417,16 @@ async def get_call_hierarchy_from_item( "Call hierarchy (from item) is not supported in the pyre persistent client. Please use code-navigation. " ) + async def get_rename( + self, + path: Path, + position: lsp.PyrePosition, + new_text: str, + ) -> Union[daemon_query.DaemonQueryFailure, Optional[lsp.WorkspaceEdit]]: + return daemon_query.DaemonQueryFailure( + "Rename is not supported in the pyre persistent client. Please use code-navigation. " + ) + async def handle_file_opened( self, path: Path, @@ -569,6 +588,19 @@ async def get_call_hierarchy_from_item( else failure ) + async def get_rename( + self, + path: Path, + position: lsp.PyrePosition, + new_text: str, + ) -> Union[daemon_query.DaemonQueryFailure, Optional[lsp.WorkspaceEdit]]: + failure = self.get_query_failure(str(path)) + return ( + await self.base_querier.get_rename(path, position, new_text) + if failure is None + else failure + ) + async def get_type_coverage( self, path: Path, @@ -749,6 +781,14 @@ async def get_call_hierarchy_from_item( ) -> Union[daemon_query.DaemonQueryFailure, List[lsp.CallHierarchyItem]]: return [] + async def get_rename( + self, + path: Path, + position: lsp.PyrePosition, + new_text: str, + ) -> Union[daemon_query.DaemonQueryFailure, Optional[lsp.WorkspaceEdit]]: + return None + async def handle_file_opened( self, path: Path, @@ -875,6 +915,14 @@ async def get_call_hierarchy_from_item( path, call_hierarchy_item, relation_direction ) + async def get_rename( + self, + path: Path, + position: lsp.PyrePosition, + new_text: str, + ) -> Union[daemon_query.DaemonQueryFailure, Optional[lsp.WorkspaceEdit]]: + return None + async def handle_file_opened( self, path: Path, diff --git a/client/commands/tests/server_setup.py b/client/commands/tests/server_setup.py index 983a6b899ab..e6ebe9d64de 100644 --- a/client/commands/tests/server_setup.py +++ b/client/commands/tests/server_setup.py @@ -139,6 +139,7 @@ def __init__( mock_completion_response: Optional[List[lsp.CompletionItem]] = None, mock_call_hierarchy_response: Optional[List[lsp.CallHierarchyItem]] = None, mock_references_response: Optional[List[lsp.LspLocation]] = None, + mock_rename_response: Optional[lsp.WorkspaceEdit] = None, ) -> None: self.requests: List[object] = [] self.mock_type_errors = mock_type_errors @@ -148,6 +149,7 @@ def __init__( self.mock_completion_response = mock_completion_response self.mock_call_hierarchy_response = mock_call_hierarchy_response self.mock_references_response = mock_references_response + self.mock_rename_response = mock_rename_response async def get_type_errors( self, @@ -238,6 +240,19 @@ async def get_call_hierarchy_from_item( else: return self.mock_call_hierarchy_response + async def get_rename( + self, + path: Path, + position: lsp.PyrePosition, + new_text: str, + ) -> Union[daemon_query.DaemonQueryFailure, Optional[lsp.WorkspaceEdit]]: + if self.mock_rename_response is None: + raise ValueError( + "You need to set the get rename response in the mock querier" + ) + else: + return self.mock_rename_response + async def update_overlay( self, path: Path, diff --git a/client/language_server/protocol.py b/client/language_server/protocol.py index a161c1c08fa..010cde96b40 100644 --- a/client/language_server/protocol.py +++ b/client/language_server/protocol.py @@ -21,7 +21,7 @@ import urllib from dataclasses import field from pathlib import Path -from typing import Iterable, List, Optional, Type, TypeVar +from typing import Dict, Iterable, List, Optional, Type, TypeVar import dataclasses_json from pyre_extensions import override @@ -798,3 +798,27 @@ class CompletionItem(json_mixins.CamlCaseAndExcludeJsonMixin): @dataclasses.dataclass(frozen=True) class CompletionResponse(json_mixins.CamlCaseAndExcludeJsonMixin): completions: List[CompletionItem] + + +@dataclasses.dataclass(frozen=True) +class TextEdit(json_mixins.CamlCaseAndExcludeJsonMixin): + range: LspRange + new_text: str + + +@dataclasses.dataclass(frozen=True) +class WorkspaceEdit(json_mixins.CamlCaseAndExcludeJsonMixin): + changes: Optional[Dict[str, List[TextEdit]]] + + +@dataclasses.dataclass(frozen=True) +class RenameParameters(json_mixins.CamlCaseAndExcludeJsonMixin): + text_document: TextDocumentIdentifier + position: LspPosition + new_name: str + + @staticmethod + def from_json_rpc_parameters( + parameters: json_rpc.Parameters, + ) -> "RenameParameters": + return _parse_parameters(parameters, target=RenameParameters)