diff --git a/verilog/tools/ls/symbol-table-handler.cc b/verilog/tools/ls/symbol-table-handler.cc index 9150c8be19..f19160364e 100644 --- a/verilog/tools/ls/symbol-table-handler.cc +++ b/verilog/tools/ls/symbol-table-handler.cc @@ -223,6 +223,29 @@ void SymbolTableHandler::Prepare() { } } +std::optional +SymbolTableHandler::GetTokenInfoAtTextDocumentPosition( + const verible::lsp::TextDocumentPositionParams ¶ms, + const verilog::BufferTrackerContainer &parsed_buffers) { + const verilog::BufferTracker *tracker = + parsed_buffers.FindBufferTrackerOrNull(params.textDocument.uri); + if (!tracker) { + VLOG(1) << "Could not find buffer with URI " << params.textDocument.uri; + return {}; + } + std::shared_ptr parsedbuffer = tracker->current(); + if (!parsedbuffer) { + VLOG(1) << "Buffer not found among opened buffers: " + << params.textDocument.uri; + return {}; + } + const verible::LineColumn cursor{params.position.line, + params.position.character}; + const verible::TextStructureView &text = parsedbuffer->parser().Data(); + const verible::TokenInfo cursor_token = text.FindTokenAt(cursor); + return cursor_token; +} + absl::string_view SymbolTableHandler::GetTokenAtTextDocumentPosition( const verible::lsp::TextDocumentPositionParams ¶ms, const verilog::BufferTrackerContainer &parsed_buffers) { @@ -343,16 +366,26 @@ std::vector SymbolTableHandler::FindReferencesLocations( return locations; } -verible::lsp::Range SymbolTableHandler::FindRenameableRangeAtCursor( +std::optional +SymbolTableHandler::FindRenameableRangeAtCursor( const verible::lsp::PrepareRenameParams ¶ms, const verilog::BufferTrackerContainer &parsed_buffers) { Prepare(); if (files_dirty_) { BuildProjectSymbolTable(); } - verible::LineColumnRange symbol = - GetTokenRangeAtTextDocumentPosition(params, parsed_buffers); - return RangeFromLineColumn(symbol); + std::optional symbol = + GetTokenInfoAtTextDocumentPosition(params, parsed_buffers); + if (symbol.has_value()) { + verible::TokenInfo token = symbol.value(); + const SymbolTableNode &root = symbol_table_->Root(); + const SymbolTableNode *node = + ScanSymbolTreeForDefinition(&root, token.text()); + if (!node) return {}; + return RangeFromLineColumn( + GetTokenRangeAtTextDocumentPosition(params, parsed_buffers)); + } + return {}; } verible::lsp::WorkspaceEdit diff --git a/verilog/tools/ls/symbol-table-handler.h b/verilog/tools/ls/symbol-table-handler.h index 6a97e60334..630f02ce32 100644 --- a/verilog/tools/ls/symbol-table-handler.h +++ b/verilog/tools/ls/symbol-table-handler.h @@ -65,7 +65,7 @@ class SymbolTableHandler { const verible::lsp::ReferenceParams ¶ms, const verilog::BufferTrackerContainer &parsed_buffers); - verible::lsp::Range FindRenameableRangeAtCursor( + std::optional FindRenameableRangeAtCursor( const verible::lsp::PrepareRenameParams ¶ms, const verilog::BufferTrackerContainer &parsed_buffers); // Provide new parsed content for the given path. If "content" is nullptr, @@ -100,6 +100,10 @@ class SymbolTableHandler { const verible::lsp::TextDocumentPositionParams &document_cursor, const verilog::BufferTrackerContainer &parsed_buffers); + std::optional GetTokenInfoAtTextDocumentPosition( + const verible::lsp::TextDocumentPositionParams ¶ms, + const verilog::BufferTrackerContainer &parsed_buffers); + // Returns the Location of the symbol name in source file // pointed by the file_origin. // If given symbol name is not found, std::nullopt is returned. diff --git a/verilog/tools/ls/verilog-language-server.cc b/verilog/tools/ls/verilog-language-server.cc index 371504245d..d725de1928 100644 --- a/verilog/tools/ls/verilog-language-server.cc +++ b/verilog/tools/ls/verilog-language-server.cc @@ -141,9 +141,11 @@ void VerilogLanguageServer::SetRequestHandlers() { }); dispatcher_.AddRequestHandler( "textDocument/prepareRename", - [this](const verible::lsp::PrepareRenameParams &p) { - return symbol_table_handler_.FindRenameableRangeAtCursor( + [this](const verible::lsp::PrepareRenameParams &p) -> nlohmann::json { + auto range = symbol_table_handler_.FindRenameableRangeAtCursor( p, parsed_buffers_); + if (range.has_value()) return range.value(); + return nullptr; }); dispatcher_.AddRequestHandler( "textDocument/rename", [this](const verible::lsp::RenameParams &p) { diff --git a/verilog/tools/ls/verilog-language-server_test.cc b/verilog/tools/ls/verilog-language-server_test.cc index 9ab584d2fd..24efe8271c 100644 --- a/verilog/tools/ls/verilog-language-server_test.cc +++ b/verilog/tools/ls/verilog-language-server_test.cc @@ -1509,6 +1509,34 @@ TEST_F(VerilogLanguageServerSymbolTableTest, << "Invalid result for id: "; } +TEST_F(VerilogLanguageServerSymbolTableTest, PrepareRenameReturnsNull) { + // Create sample file and make sure diagnostics do not have errors + std::string file_uri = PathToLSPUri(absl::string_view(root_dir + "/fmt.sv")); + verible::lsp::PrepareRenameParams params; + params.position.line = 1; + params.position.character = 1; + params.textDocument.uri = file_uri; + + const std::string mini_module = + DidOpenRequest(file_uri, + "module fmt();\nfunction automatic " + "bar();\nbar();\nbar();\nendfunction;\nendmodule\n"); + ASSERT_OK(SendRequest(mini_module)); + + const json diagnostics = json::parse(GetResponse()); + EXPECT_EQ(diagnostics["method"], "textDocument/publishDiagnostics") + << "textDocument/publishDiagnostics not received"; + EXPECT_EQ(diagnostics["params"]["uri"], file_uri) + << "Diagnostics for invalid file"; + + EXPECT_EQ(diagnostics["params"]["diagnostics"].size(), 0) + << "The test file has errors"; + ASSERT_OK(SendRequest(PrepareRenameRequest(params))); + + const json response = json::parse(GetResponse()); + EXPECT_EQ(response["result"], nullptr) << "Invalid result for id: "; +} + TEST_F(VerilogLanguageServerSymbolTableTest, RenameTestSymbolSingleFile) { // Create sample file and make sure diagnostics do not have errors std::string file_uri = @@ -1537,7 +1565,6 @@ TEST_F(VerilogLanguageServerSymbolTableTest, RenameTestSymbolSingleFile) { ASSERT_OK(SendRequest(mini_module)); const json diagnostics = json::parse(GetResponse()); - std::cout << diagnostics << std::endl; EXPECT_EQ(diagnostics["method"], "textDocument/publishDiagnostics") << "textDocument/publishDiagnostics not received"; @@ -1611,7 +1638,6 @@ TEST_F(VerilogLanguageServerSymbolTableTest, RenameTestSymbolMultipleFiles) { ASSERT_OK(SendRequest(request)); const json response = json::parse(GetResponse()); - std::cout << response << std::endl; EXPECT_EQ(response["result"]["changes"].size(), 2) << "Invalid result size for id: "; EXPECT_EQ(response["result"]["changes"][top_uri].size(), 1) @@ -1647,8 +1673,7 @@ TEST_F(VerilogLanguageServerSymbolTableTest, RenameTestPackageDistinction) { const verible::file::testing::ScopedTestFile module_foo(root_dir, renamesv, "rename.sv"); - const std::string mini_module = - DidOpenRequest("file://" + module_foo.filename(), renamesv); + const std::string mini_module = DidOpenRequest(file_uri, renamesv); ASSERT_OK(SendRequest(mini_module)); const json diagnostics = json::parse(GetResponse());