use crate::clangd::session::ClangdSessionTrait;
use serde::{Deserialize, Serialize};
use crate::lsp::traits::LspClientTrait;
use crate::mcp_server::tools::analyze_symbols::AnalyzerError;
use crate::project::component_session::ComponentSession;
use crate::symbol::FileLocation;
#[derive(Debug, Serialize, Deserialize)]
pub struct CallHierarchy {
pub callers: Vec<String>,
pub callees: Vec<String>,
}
pub async fn get_call_hierarchy(
symbol_location: &FileLocation,
component_session: &ComponentSession,
) -> Result<CallHierarchy, AnalyzerError> {
let uri = symbol_location.get_uri();
let lsp_position: lsp_types::Position = symbol_location.range.start.into();
component_session
.ensure_file_ready(&symbol_location.file_path)
.await?;
let mut session = component_session.lsp_session().await;
let client = session.client_mut();
let call_hierarchy_items = client
.text_document_prepare_call_hierarchy(uri, lsp_position)
.await
.map_err(AnalyzerError::from)?;
let call_hierarchy_item = if call_hierarchy_items.is_empty() {
return Ok(CallHierarchy {
callers: Vec::new(),
callees: Vec::new(),
});
} else {
call_hierarchy_items.into_iter().next().unwrap()
};
let callers = client
.call_hierarchy_incoming_calls(call_hierarchy_item.clone())
.await
.map_err(AnalyzerError::from)?
.into_iter()
.map(|call| call.from.name)
.collect();
let callees = client
.call_hierarchy_outgoing_calls(call_hierarchy_item)
.await
.map_err(AnalyzerError::from)?
.into_iter()
.map(|call| call.to.name)
.collect();
Ok(CallHierarchy { callers, callees })
}