Skip to main content
Glama

C++ MCP Server

by kandrwmrtn
call_graph.py4.56 kB
"""Call graph analysis for C++ code.""" import re from typing import Dict, List, Set, Optional, Any from collections import defaultdict from .symbol_info import SymbolInfo class CallGraphAnalyzer: """Manages call graph analysis for C++ code.""" def __init__(self): self.call_graph: Dict[str, Set[str]] = defaultdict(set) # Function USR -> Set of called USRs self.reverse_call_graph: Dict[str, Set[str]] = defaultdict(set) # Function USR -> Set of caller USRs def add_call(self, caller_usr: str, callee_usr: str): """Add a function call relationship""" if caller_usr and callee_usr: self.call_graph[caller_usr].add(callee_usr) self.reverse_call_graph[callee_usr].add(caller_usr) def clear(self): """Clear all call graph data""" self.call_graph.clear() self.reverse_call_graph.clear() def remove_symbol(self, usr: str): """Remove a symbol from the call graph completely""" if usr in self.call_graph: # Remove all calls made by this function called_functions = self.call_graph[usr].copy() for called_usr in called_functions: self.reverse_call_graph[called_usr].discard(usr) # Clean up empty sets if not self.reverse_call_graph[called_usr]: del self.reverse_call_graph[called_usr] del self.call_graph[usr] if usr in self.reverse_call_graph: # Remove all calls to this function calling_functions = self.reverse_call_graph[usr].copy() for caller_usr in calling_functions: self.call_graph[caller_usr].discard(usr) # Clean up empty sets if not self.call_graph[caller_usr]: del self.call_graph[caller_usr] del self.reverse_call_graph[usr] def rebuild_from_symbols(self, symbols: List[SymbolInfo]): """Rebuild call graph from symbol list""" self.clear() for symbol in symbols: if symbol.usr and symbol.calls: for called_usr in symbol.calls: self.add_call(symbol.usr, called_usr) def find_callers(self, function_usr: str) -> Set[str]: """Find all functions that call the specified function""" return self.reverse_call_graph.get(function_usr, set()) def find_callees(self, function_usr: str) -> Set[str]: """Find all functions called by the specified function""" return self.call_graph.get(function_usr, set()) def get_call_paths(self, from_usr: str, to_usr: str, max_depth: int = 10) -> List[List[str]]: """Find all call paths from one function to another""" if from_usr == to_usr: return [[from_usr]] if max_depth <= 0: return [] paths = [] # Get direct callees callees = self.find_callees(from_usr) for callee in callees: if callee == to_usr: # Direct call found paths.append([from_usr, to_usr]) else: # Recursively search for paths sub_paths = self.get_call_paths(callee, to_usr, max_depth - 1) for sub_path in sub_paths: paths.append([from_usr] + sub_path) return paths def get_call_statistics(self) -> Dict[str, Any]: """Get statistics about the call graph""" return { "total_functions_with_calls": len(self.call_graph), "total_functions_being_called": len(self.reverse_call_graph), "total_unique_calls": sum(len(calls) for calls in self.call_graph.values()), "most_called_functions": self._get_most_called_functions(10), "functions_with_most_calls": self._get_functions_with_most_calls(10) } def _get_most_called_functions(self, limit: int) -> List[tuple]: """Get the most frequently called functions""" call_counts = [(usr, len(callers)) for usr, callers in self.reverse_call_graph.items()] return sorted(call_counts, key=lambda x: x[1], reverse=True)[:limit] def _get_functions_with_most_calls(self, limit: int) -> List[tuple]: """Get functions that make the most calls""" call_counts = [(usr, len(callees)) for usr, callees in self.call_graph.items()] return sorted(call_counts, key=lambda x: x[1], reverse=True)[:limit]

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kandrwmrtn/cplusplus_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server