How Dead Code Detection Identifies Functions with Zero Callers in Codebase-Memory-MCP
Dead code detection identifies functions with zero callers by analyzing the CALLS relationship graph built during indexing, exposing virtual in_degree properties that count incoming call edges, and filtering out legitimate entry points like main() functions and public APIs.
The Codebase-Memory-MCP engine implements dead code detection through a graph-based analysis pipeline that tracks every function invocation across your codebase. By treating function calls as directed edges in a graph stored in SQLite, the system can efficiently query for isolated nodes—functions that never receive incoming calls—while excluding false positives such as framework handlers and test entry points.
Building the CALLS Graph for Dead Code Analysis
The foundation of dead code detection lies in the CALLS relationship graph constructed during the indexing phase.
Parsing Function Invocations in pass_calls.c
During indexing, the pipeline stage src/pipeline/pass_calls.c walks the abstract syntax trees (ASTs) produced by Tree-Sitter to identify every function-call expression. For each call discovered, it creates a directed edge of type CALLS from the caller node to the callee node, storing these relationships in the SQLite backing store (src/store/store.c).
/* Excerpt from pass_calls.c */
if (is_call_expression(node)) {
int caller_id = get_node_id(caller);
int callee_id = get_node_id(callee);
cbm_edge_t edge = {
.project = proj,
.source_id = caller_id,
.target_id = callee_id,
.type = "CALLS"
};
cbm_store_add_edge(store, &edge);
}
Every detected call results in a directed edge that connects the calling function to its target, enabling the system to calculate reachability metrics.
Virtual Degree Properties in cypher.c
The query engine exposes edge counts as virtual node properties through src/cypher/cypher.c. When a Cypher query requests in_degree or out_degree, the engine looks up pre-computed CALLS edge counts and injects them as ordinary JSON fields (see lines 2216–2222).
/* Virtual properties handling – lines 2216-2222 */
if (store && (strcmp(prop, "in_degree") == 0 || strcmp(prop, "out_degree") == 0)) {
int val = (strcmp(prop, "in_degree") == 0) ? in_deg : out_deg;
yyjson_mut_obj_add_int(doc, row, prop, val);
}
This mechanism allows developers to query in_degree (the number of incoming CALLS edges) as if it were a native property of each function node.
Filtering Out False Positives in Dead Code Detection
Not every function with zero callers represents truly dead code. The detector applies smart filters to exclude legitimate entry points that intentionally lack callers.
Excluding Entry Points and Public APIs
The system recognizes several categories of functions that should not be flagged as dead, even when their in_degree equals zero:
main()functions – Recognized by name patterns (main,init)- Route handlers and framework decorators – Detected via language-specific conventions (e.g., FastAPI, Spring annotations)
- Exported symbols – Marked in the index as
exportedorpublic - Test functions – Tagged with the
testlabel
These exclusions are implemented in the query layer, where the in_degree filter combines with additional predicates to eliminate false positives.
UI-Level Filtering in FilterPanel.tsx
The React component graph-ui/src/components/FilterPanel.tsx provides a "Show only dead code" toggle (line 218) that automatically constructs the appropriate query constraints.
{/* FilterPanel.tsx – line 218 */}
<label>
<input
type="checkbox"
name="showDead"
onChange={toggleDeadCode}
/>
Show only dead code
</label>
When activated, this component appends in_degree = 0 to the current Cypher query while applying the entry-point exclusion rules.
Querying for Dead Functions with Cypher
You can retrieve dead functions directly through Cypher queries that combine the virtual in_degree property with exclusion filters:
-- Find functions that have no callers and are not exported
MATCH (f:Function)
WHERE f.in_degree = 0
AND NOT f.exported
AND NOT f.is_route_handler
RETURN f.name, f.file_path
A function is reported as dead code only when its in_degree is 0 and it matches none of the exclusion criteria defined in the query layer.
Summary
- Dead code detection relies on the CALLS graph built by
pass_calls.cduring AST parsing. - The
in_degreevirtual property incypher.ccounts incoming call edges without storing redundant data. - Entry-point filters exclude
main()functions, route handlers, and public APIs from dead code reports. - Both the CLI (
cbm search_graph) and web UI (FilterPanel.tsx) support querying for zero-caller functions.
Frequently Asked Questions
What file creates the CALLS edges for dead code detection?
The pipeline stage src/pipeline/pass_calls.c creates CALLS edges by walking Tree-Sitter ASTs during the indexing phase. It identifies function call expressions and stores directed edges in the SQLite backing store via cbm_store_add_edge().
How does the query engine calculate in_degree for functions?
The query engine calculates in_degree dynamically in src/cypher/cypher.c (lines 2216–2222). When a Cypher query requests this property, the engine counts the incoming CALLS edges for the node from the pre-computed graph stored in SQLite, returning the value as a virtual property.
Why doesn't dead code detection flag main() functions?
The detector applies smart filters that recognize legitimate entry points by name patterns (main, init), framework conventions, export status, and test labels. These filters prevent functions that serve as program entry points or public APIs from being incorrectly identified as dead code.
Can I filter dead code through the web interface?
Yes. The FilterPanel.tsx component in the graph UI provides a "Show only dead code" checkbox that automatically appends in_degree = 0 constraints to your query while excluding entry points. You can also use the CLI command cbm search_graph with custom Cypher filters to retrieve dead functions programmatically.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →