#include #include "./references.hpp" #include "../../protocol/transform/facade.hpp" #include "../../service/document.hpp" #include "../../service/symbol.hpp" namespace lsp::provider::text_document { std::string References::GetMethod() const { return "textDocument/references"; } std::string References::GetProviderName() const { return "TextDocumentReferences"; } std::string References::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) { spdlog::debug("TextDocumentReferencesProvider: Providing response for method {}", request.method); if (!request.params.has_value()) { spdlog::warn("{}: Missing params in request", GetProviderName()); return BuildErrorResponseMessage(request, protocol::ErrorCodes::kInvalidParams, "Missing params"); } protocol::ReferenceParams params = transform::As(request.params.value()); auto locations = BuildReferencesResponse(params, context); protocol::ResponseMessage response; response.id = request.id; if (!locations.empty()) response.result = transform::LSPAny(locations); else response.result = transform::LSPAny(std::vector{}); std::optional json = transform::Serialize(response); if (!json.has_value()) return BuildErrorResponseMessage(request, protocol::ErrorCodes::kInternalError, "Failed to serialize response"); return json.value(); } std::vector References::BuildReferencesResponse(const protocol::ReferenceParams& params, ExecutionContext& context) { spdlog::trace("{}: Processing references request for URI='{}', Position=({}, {})", GetProviderName(), params.textDocument.uri, params.position.line, params.position.character); std::string identifier = GetIdentifierAtPosition( params.textDocument.uri, params.position, context); if (identifier.empty()) { spdlog::info("{}: No identifier at position", GetProviderName()); return {}; } spdlog::debug("{}: Looking for references of '{}'", GetProviderName(), identifier); auto locations = FindReferences(params.textDocument.uri, identifier, params.context.includeDeclaration, context); spdlog::info("{}: Found {} references", GetProviderName(), locations.size()); return locations; } std::vector References::FindReferences(const protocol::DocumentUri& uri, const std::string& identifier, bool include_declaration, ExecutionContext& context) { std::vector locations; // 从容器获取文档服务 auto& document_service = context.GetService(); auto content = document_service.GetContent(uri); auto tree = document_service.GetSyntaxTree(uri); if (!content.has_value() || !tree) { spdlog::warn("{}: Document not found or no syntax tree: {}", GetProviderName(), uri); return locations; } TSNode root = ts_tree_root_node(tree); FindReferencesInNode(root, identifier, *content, uri, locations, include_declaration); return locations; } std::string References::GetIdentifierAtPosition(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context) { auto& document_service = context.GetService(); auto content = document_service.GetContent(uri); auto tree = document_service.GetSyntaxTree(uri); if (!content.has_value() || !tree) return ""; size_t byte_offset = 0; size_t current_line = 0; size_t current_col = 0; for (size_t i = 0; i < content->length(); i++) { if (current_line == position.line && current_col == position.character) { byte_offset = i; break; } if ((*content)[i] == '\n') { current_line++; current_col = 0; } else { current_col++; } } TSNode root = ts_tree_root_node(tree); TSNode node = ts_node_descendant_for_byte_range(root, byte_offset, byte_offset); while (!ts_node_is_null(node)) { const char* node_type = ts_node_type(node); if (strcmp(node_type, kIdentifier) == 0) { uint32_t start = ts_node_start_byte(node); uint32_t end = ts_node_end_byte(node); return content->substr(start, end - start); } node = ts_node_parent(node); } return ""; } }