From ac7301196e08bbf75dce6f6061d579cc68cf98f2 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 20 Mar 2026 11:08:57 -0400
Subject: [PATCH 38/38] FIXME: WIP on implementing "textDocument/declaration"

---
 gcc/lsp/gcc-impl/server.cc             | 47 +++++++++++++++++++
 gcc/lsp/gcc-impl/server.h              |  4 ++
 gcc/lsp/gcc-impl/worker-diagnostics.cc |  3 +-
 gcc/lsp/gcc-impl/worker.cc             | 65 ++++++++++++++++++++++----
 gcc/lsp/gcc-impl/worker.h              |  7 +++
 gcc/lsp/lsp-spec.cc                    | 22 ++++++++-
 gcc/lsp/lsp-spec.h                     |  6 +++
 gcc/topics/ast-events-recorder.h       |  8 ++--
 8 files changed, 147 insertions(+), 15 deletions(-)

diff --git a/gcc/lsp/gcc-impl/server.cc b/gcc/lsp/gcc-impl/server.cc
index 77511e200d0..71d0e6849da 100644
--- a/gcc/lsp/gcc-impl/server.cc
+++ b/gcc/lsp/gcc-impl/server.cc
@@ -448,6 +448,29 @@ consume_client_request (json_rpc::request &&req)
       gcc_unreachable ();
       // return dispatch_call_shutdown (std::move (req));
     }
+  else if (0 == strcmp (method, "textDocument/declaration"))
+    {
+      auto unmarshal_result
+	= spec::DeclarationParams::from_json (req.get_id (),
+					      *req.get_params ());
+      if (unmarshal_result.get_error ())
+	{
+	  gcc_unreachable (); // FIXME
+#if 0
+	  send_response_to_client
+	    (json_rpc::response::invalid_params (req,
+						 std::move (unmarshal_result)));
+#endif
+	  return;
+	}
+
+      on_client_request_textDocument_declaration
+	(req.take_id (),
+	 unmarshal_result.take_value ());
+      /* We will expect a response from the worker, and forward
+	 that to the client.  */
+      return;
+    }
   else if (0 == strcmp (method, "textDocument/documentSymbol"))
     {
       auto unmarshal_result
@@ -563,6 +586,24 @@ on_client_request_initialize (std::unique_ptr<json::value> req_id,
     (json_rpc::response::success (std::move (req_id), result.to_json ()));
 }
 
+void
+lsp::gcc_impl::server::mediator::
+on_client_request_textDocument_declaration (std::unique_ptr<json::value> req_id,
+					    spec::DeclarationParams &&p)
+{
+  LSP_LOG_SCOPE (get_logger ());
+
+  auto iter = m_open_documents.find (p.textDocument.uri);
+  gcc_assert (iter != m_open_documents.end ());
+
+  auto doc_ver = iter->second->get_most_recent_version ();
+  gcc_assert (doc_ver);
+  doc_ver->get_worker_subprocess ()->send_request
+    (json_rpc::request ("textDocument/declaration",
+			p.to_json (),
+			std::move (req_id)));
+}
+
 void
 lsp::gcc_impl::server::mediator::
 on_client_request_textDocument_documentSymbol (std::unique_ptr<json::value> req_id,
@@ -669,6 +710,12 @@ lsp::spec::ServerCapabilities
 lsp::gcc_impl::server::mediator::get_ServerCapabilities ()
 {
   lsp::spec::ServerCapabilities result;
+
+#if 1
+  result.declarationProvider.set_optional_value
+    (lsp::spec::boolean (true)); // FIXME
+#endif
+  
 #if 1
   result.documentSymbolProvider.set_optional_value
     (lsp::spec::boolean (true)); // FIXME
diff --git a/gcc/lsp/gcc-impl/server.h b/gcc/lsp/gcc-impl/server.h
index ff919797acf..e9b4c1cea12 100644
--- a/gcc/lsp/gcc-impl/server.h
+++ b/gcc/lsp/gcc-impl/server.h
@@ -243,6 +243,10 @@ public:
   on_client_request_initialize (std::unique_ptr<json::value> req_id,
 				spec::InitializeParams &&p);
 
+  void
+  on_client_request_textDocument_declaration (std::unique_ptr<json::value> req_id,
+					      spec::DeclarationParams &&p);
+
   void
   on_client_request_textDocument_documentSymbol (std::unique_ptr<json::value> req_id,
 						 spec::DocumentSymbolParams &&p);
diff --git a/gcc/lsp/gcc-impl/worker-diagnostics.cc b/gcc/lsp/gcc-impl/worker-diagnostics.cc
index 2b9c203befe..d6a0b327332 100644
--- a/gcc/lsp/gcc-impl/worker-diagnostics.cc
+++ b/gcc/lsp/gcc-impl/worker-diagnostics.cc
@@ -145,7 +145,8 @@ lsp::gcc_impl::worker::diagnostics::sink::on_end_group ()
     {
       if (m_mediator.done_compiling_p ())
 	{
-	  gcc_unreachable (); // FIXME
+	  // FIXME:
+	  // gcc_unreachable (); // FIXME
 	}
       else
 	{
diff --git a/gcc/lsp/gcc-impl/worker.cc b/gcc/lsp/gcc-impl/worker.cc
index def78373cd1..3d48de308e8 100644
--- a/gcc/lsp/gcc-impl/worker.cc
+++ b/gcc/lsp/gcc-impl/worker.cc
@@ -83,7 +83,7 @@ lsp::gcc_impl::worker::mediator::mediator (lsp::logger *logger)
           (*global_dc, *this);
     m_lsp_diagnostic_sink = sink.get ();
     sink->update_printer ();
-#if 1
+#if 0
     global_dc->set_sink (std::move (sink));
 #else
     global_dc->add_sink (std::move (sink));
@@ -126,7 +126,7 @@ handle_events_after_compile (lsp::frontend_worker_interface *frontend)
   m_frontend = frontend;
 
   // FIXME:
-  //dump_ast ();
+  dump_ast ();
 
   // Flush any pending diagnostics
   gcc_assert (m_lsp_diagnostic_sink);
@@ -200,7 +200,28 @@ consume_json_rpc_request (json_rpc::request &&req)
   const char *method = req.get_method ();
   if (logger)
     logger->log ("call: \"%s\"", method);
-  if (0 == strcmp (method, "textDocument/documentSymbol"))
+  if (0 == strcmp (method, "textDocument/declaration"))
+    {
+      auto unmarshal_result
+	= spec::DeclarationParams::from_json (req.get_id (),
+					      *req.get_params ());
+      if (unmarshal_result.get_error ())
+	{
+	  gcc_unreachable (); // FIXME
+#if 0
+	  send_response_to_client
+	    (json_rpc::response::invalid_params (req,
+						 std::move (unmarshal_result)));
+#endif
+	  return;
+	}
+
+      on_request_textDocument_declaration
+	(req.take_id (),
+	 unmarshal_result.take_value ());
+      return;
+    }
+  else if (0 == strcmp (method, "textDocument/documentSymbol"))
     {
       auto unmarshal_result
 	= spec::DocumentSymbolParams::from_json (req.get_id (),
@@ -293,16 +314,36 @@ on_invalid_json_rpc (json_rpc::error &&)
   gcc_unreachable ();
 }
 
+// If we've lost our connection to the server, exit.
+
 void
 lsp::gcc_impl::worker::mediator::
 on_finish ()
 {
-  LSP_LOG_SCOPE (get_logger ());
-  gcc_unreachable ();
+  auto logger = get_logger ();
+  LSP_LOG_SCOPE (logger);
+  if (logger)
+    logger->log ("exiting");
+
+  exit (0);
 }
 
 // Handling of requests from server
 
+void
+lsp::gcc_impl::worker::mediator::
+on_request_textDocument_declaration (std::unique_ptr<json::value> req_id,
+				     spec::DeclarationParams &&p)
+{
+  LSP_LOG_SCOPE (get_logger ());
+
+  gcc_assert (m_frontend);
+
+  auto ast_node = get_ast_node_at_position (p);
+
+  gcc_unreachable (); // FIXME
+}
+
 void
 lsp::gcc_impl::worker::mediator::
 on_request_textDocument_documentSymbol (std::unique_ptr<json::value> req_id,
@@ -311,10 +352,6 @@ on_request_textDocument_documentSymbol (std::unique_ptr<json::value> req_id,
   LSP_LOG_SCOPE (get_logger ());
 
   gcc_assert (m_frontend);
-  /* FIXME: we can hit this with null frontend
-     if the request hits in the same loop as didOpen.
-     We need to stop processing the inputs immediately after
-     didOpen is processed.  */
 
   auto symbols = m_frontend->get_symbols ();
   send_response_to_server
@@ -398,7 +435,15 @@ visit_node (const gcc::topics::ast_events::recorder::saved_node &node)
 {
   // FIXME: see notes for dump_ast
   auto_diagnostic_nesting_level sentinel;
-  inform (node.m_start_loc, "%qs", node.m_kind);
+  inform (node.m_start_loc, "start of %qs", node.m_kind);
   for (auto &iter : node.m_children)
     visit_node (*iter);
+  inform (node.m_end_loc, "end of %qs", node.m_kind);
+}
+
+const gcc::topics::ast_events::recorder::saved_node *
+lsp::gcc_impl::worker::mediator::
+get_ast_node_at_position (const lsp::spec::TextDocumentPositionParams &p)
+{
+  gcc_unreachable (); // FIXME
 }
diff --git a/gcc/lsp/gcc-impl/worker.h b/gcc/lsp/gcc-impl/worker.h
index 5f87ee3718c..1109efb98a1 100644
--- a/gcc/lsp/gcc-impl/worker.h
+++ b/gcc/lsp/gcc-impl/worker.h
@@ -105,6 +105,10 @@ public:
 
   // Handling of requests from server
 
+  void
+  on_request_textDocument_declaration (std::unique_ptr<json::value> req_id,
+				       spec::DeclarationParams &&p);
+
   void
   on_request_textDocument_documentSymbol (std::unique_ptr<json::value> req_id,
 					  spec::DocumentSymbolParams &&p);
@@ -119,6 +123,9 @@ public:
   void dump_ast ();
   void visit_node (const gcc::topics::ast_events::recorder::saved_node &node);
 
+  const gcc::topics::ast_events::recorder::saved_node *
+  get_ast_node_at_position (const spec::TextDocumentPositionParams &p);
+
   ipc::connection m_server_ipc_connection;
   octets_to_json_rpc m_octets_from_server;
   char *m_filename_from_didOpen;
diff --git a/gcc/lsp/lsp-spec.cc b/gcc/lsp/lsp-spec.cc
index 17191bc21b9..d5718bf55fe 100644
--- a/gcc/lsp/lsp-spec.cc
+++ b/gcc/lsp/lsp-spec.cc
@@ -397,13 +397,15 @@ lsp::spec::InitializeParams::to_json () const
 BEGIN_DEFINE_FROM_JSON(ServerCapabilities)
 {
   // FIXME
-  //UNMARSHAL_OPTIONAL_PROPERTY (boolean, documentSymbolProvider);
+  UNMARSHAL_OPTIONAL_PROPERTY (boolean, declarationProvider);
+  UNMARSHAL_OPTIONAL_PROPERTY (boolean, documentSymbolProvider);
 }
 END_DEFINE_FROM_JSON
 
 BEGIN_DEFINE_TO_JSON(ServerCapabilities)
 {
   // FIXME
+  MARSHAL_OPTIONAL_PROPERTY (boolean, declarationProvider);
   MARSHAL_OPTIONAL_PROPERTY (boolean, documentSymbolProvider);
 }
 END_DEFINE_TO_JSON
@@ -753,6 +755,24 @@ lsp::spec::PublishDiagnosticsParams::to_json () const
   return jobj;
 }
 
+// struct DeclarationParams : public TextDocumentPositionParams
+
+BEGIN_DEFINE_FROM_JSON(DeclarationParams)
+{
+  // FIXME: chain up to parent
+  UNMARSHAL_REQUIRED_PROPERTY (TextDocumentIdentifier, textDocument);
+  UNMARSHAL_REQUIRED_PROPERTY (Position, position);
+}
+END_DEFINE_FROM_JSON
+
+BEGIN_DEFINE_TO_JSON(DeclarationParams)
+{
+  // FIXME: chain up to parent
+  MARSHAL_REQUIRED_PROPERTY (TextDocumentIdentifier, textDocument);
+  MARSHAL_REQUIRED_PROPERTY (Position, position);
+}
+END_DEFINE_TO_JSON
+
 // struct DocumentSymbolParams
 
 BEGIN_DEFINE_FROM_JSON(DocumentSymbolParams)
diff --git a/gcc/lsp/lsp-spec.h b/gcc/lsp/lsp-spec.h
index efc4fdc7138..99f41afab15 100644
--- a/gcc/lsp/lsp-spec.h
+++ b/gcc/lsp/lsp-spec.h
@@ -316,6 +316,7 @@ struct ServerCapabilities
 
   // FIXME:
 
+  optional<boolean> declarationProvider;
   optional<boolean> documentSymbolProvider;
 };
 
@@ -517,6 +518,11 @@ struct PublishDiagnosticsParams
   vector<Diagnostic> diagnostics;
 };
 
+struct DeclarationParams : public TextDocumentPositionParams
+{
+  DECLARE_JSON_METHODS(DeclarationParams)
+};
+
 struct DocumentSymbolParams // FIXME
 {
   DECLARE_JSON_METHODS(DocumentSymbolParams)
diff --git a/gcc/topics/ast-events-recorder.h b/gcc/topics/ast-events-recorder.h
index 9100ccfadf5..e831bcae4f9 100644
--- a/gcc/topics/ast-events-recorder.h
+++ b/gcc/topics/ast-events-recorder.h
@@ -35,11 +35,13 @@ public:
   {
     saved_node (const char *kind, location_t start_loc)
     : m_kind (kind),
-      m_start_loc (start_loc)
+      m_start_loc (start_loc),
+      m_end_loc (UNKNOWN_LOCATION)
     {}
 
     const char *m_kind;
     location_t m_start_loc;
+    location_t m_end_loc;
     std::vector<std::unique_ptr<saved_node>> m_children;
   };
 
@@ -58,11 +60,11 @@ public:
     prev_top_of_stack->m_children.push_back (std::move (new_node));
   }
 
-  void on_message (const ast_events::end_node &) final override
+  void on_message (const ast_events::end_node &m) final override
   {
     gcc_assert (!m_stack.empty ());
+    m_stack.back ()->m_end_loc = m.loc;
     m_stack.pop_back ();
-    // FIXME: also capture the endloc in each saved_node?
   }
 
 private:
-- 
2.49.0

