How CodeGraph's Dead Code Detection Algorithm Identifies Unreferenced Symbols

CodeGraph identifies dead code by querying its knowledge graph for symbols that have no incoming usage references, filtering out exported symbols and excluding containment edges from the analysis.

Dead code detection is essential for maintaining healthy codebases by identifying unused functions, methods, and classes. In the colbymchenry/codegraph repository, the dead code detection algorithm leverages a graph-based approach to pinpoint unreferenced symbols with precision. This article examines how the GraphQueryManager.findDeadCode method in src/graph/queries.ts analyzes the knowledge graph to determine which symbols are truly unreachable.

The Core Algorithm in GraphQueryManager.findDeadCode

The dead code detection logic resides in GraphQueryManager.findDeadCode at lines 33-61 of src/graph/queries.ts. This method implements a six-step graph traversal that distinguishes between hierarchical relationships and actual usage references.

Step 1: Selecting Target Node Kinds

By default, the algorithm targets functions, methods, and classes, as these represent the most common dead code candidates. However, the method accepts an optional parameter allowing callers to specify any array of Node['kind'] values to examine custom symbol types.

Step 2: Retrieving Nodes and Filtering Exports

For each selected kind, the algorithm retrieves all matching nodes via queries.getNodesByKind(kind). It immediately applies a critical filter: exported symbols are skipped. The check if (node.isExported) continue assumes that exported nodes may be referenced from outside the project scope, rendering them ineligible for dead code classification regardless of internal graph state.

Step 3: Analyzing Incoming References

For each non-exported node, the algorithm fetches every incoming edge using queries.getIncomingEdges(node.id). This returns all relationships where other nodes point to the current symbol, including both usage references and structural containment relationships.

Step 4: Excluding Containment Edges

The algorithm filters the incoming edge collection to remove containment edges (kind === 'contains'). These edges represent hierarchical structure (such as a method contained within a class) rather than actual usage. Only edges indicating active references—such as calls, imports, or references—are retained for the final assessment.

Step 5: Determining Dead Code Status

If the filtered edge list is empty, the symbol has no external usage references within the codebase. The node is immediately added to the dead code results list. This determination relies on the distinction between structural containment and functional dependency established in the previous step.

Public API Access Through CodeGraph.findDeadCode

The graph-level functionality is exposed through the public CodeGraph.findDeadCode method in src/index.ts at lines 66-73. This wrapper makes dead code detection accessible to library consumers and CLI tooling without requiring direct interaction with the graph query layer.

Practical Implementation Example

The following TypeScript example demonstrates how to invoke the dead code detection API and process results:

import CodeGraph from 'codegraph';

// Open an existing CodeGraph project
const cg = await CodeGraph.open('/path/to/project');

// Find dead code for the default kinds (functions, methods, classes)
const dead = cg.findDeadCode();
console.log('Dead symbols:', dead.map(n => `${n.filePath}:${n.startLine}-${n.endLine} ${n.kind} ${n.qualifiedName}`));

// Find dead symbols for a custom set of kinds (e.g., variables and constants)
const deadVars = cg.findDeadCode(['variable', 'constant']);
console.log('Unused variables/constants:', deadVars);

The returned Node objects contain full metadata including file paths, line numbers, and qualified names suitable for integration with reporting tools, IDE extensions, or automated cleanup scripts.

Summary

  • Graph traversal approach: The algorithm queries src/graph/queries.ts to inspect incoming edges for each symbol node.
  • Export protection: Symbols marked as exported are automatically excluded from dead code detection to prevent false positives on public APIs.
  • Containment filtering: Hierarchical relationships defined in src/types.ts as contains edges are excluded from reference counting.
  • Flexible targeting: The API supports custom node kinds beyond the default functions, methods, and classes.
  • Public availability: The CodeGraph.findDeadCode method in src/index.ts provides the primary interface for library users.

Frequently Asked Questions

What symbol types does CodeGraph analyze for dead code detection?

By default, CodeGraph analyzes functions, methods, and classes. However, you can pass a custom array of node kinds—such as ['variable', 'constant', 'interface']—to the findDeadCode method to target specific symbol types based on your project's dead code detection requirements.

Why are containment edges excluded when detecting dead code?

Containment edges represent hierarchical relationships (e.g., a method located inside a class body) rather than functional usage. If containment edges counted as references, every method would appear used simply by virtue of being declared within its parent class. The algorithm filters these out to identify only actual usage references like function calls or imports.

How does CodeGraph handle exported symbols in dead code detection?

CodeGraph assumes exported symbols are accessible from outside the project scope. During the iteration in GraphQueryManager.findDeadCode, any node with isExported set to true is skipped immediately via continue, ensuring that public APIs and library exports are never flagged as dead code regardless of internal usage patterns.

How does the algorithm determine that a symbol is truly unreferenced?

After retrieving all incoming edges via queries.getIncomingEdges(node.id), the algorithm filters out containment relationships. If the resulting array contains zero edges of kinds like calls, imports, or references, the symbol has no active dependencies within the codebase and is classified as dead code.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →