How CRG Identifies Execution Paths and Flows: Static Call Graph Analysis
CRG identifies execution paths and flows by statically parsing source code into abstract syntax trees, resolving function call edges, and materializing complete call chains into a queryable SQLite database with calculated depth metrics.
The tirth8205/code-review-graph repository implements a multi-language static analysis engine that maps execution paths and flows without runtime instrumentation. By walking ASTs and recording caller-callee relationships, CRG constructs a persistent flow graph that enables precise impact analysis and automated code review workflows.
Static Tracing: Mapping the Call Graph
CRG begins execution path discovery through static tracing, a process that traverses source files to identify every reachable function call. The entry point for this analysis is the trace_flows function in code_review_graph/flows.py, which orchestrates the AST parsing and edge resolution logic lines 285-306.
For each source file, CRG uses language-specific parsers to resolve imports and attribute accesses, converting raw syntax into structured call edges. When repositories evolve, the incremental_trace_flows function lines 459-473 retraces only modified files, merging new edges with existing flows to maintain an up-to-date call graph without full reanalysis.
Flow Representation and Graph Construction
Once edges are collected, CRG materializes them into flow records using the FlowAdjacency model defined in code_review_graph/graph.py lines 156-165. Each flow represents a complete execution path from an entry point through its deepest call chain.
The system calculates depth as the longest call-chain length from the entry point, classifies the kind of entry point (e.g., Function, Class), and stores an ordered list of steps representing caller-to-callee transitions. This structured representation enables precise querying of specific execution scenarios and dependency chains.
Persistence and Query Interface
CRG persists discovered flows to an embedded SQLite database via the store_flows function, ensuring atomic transactions that roll back completely on failure [as tested in tests/test_transactions.py lines 63-81](https://github.com/tirth8205/code-review-graph/blob/main/tests/test_transactions.py#L63-L81). The flows are stored in a dedicated flows table with indexed columns for rapid retrieval.
The repository exposes these capabilities through MCP-tool wrappers including list_flows, get_flow, and get_affected_flows_func, which are validated in tests/test_tools.py lines 1062-1190. These utilities provide both programmatic Python APIs and CLI commands for inspecting execution paths.
Practical Examples: Tracing and Querying Execution Flows
Generate and inspect execution paths using the CRG CLI:
# Trace all flows in the current repository
code-review-graph trace-flows
# List flows sorted by call depth, limiting to 10 results
code-review-graph list-flows --sort-by depth --limit 10
# Retrieve a specific flow with source code context
code-review-graph get-flow --name handle_request --include-source
# Identify affected flows after modifying specific files
code-review-graph get-affected-flows --changed-files auth.py
For programmatic access, import the MCP tools directly:
from code_review_graph.tools import list_flows, get_flow, get_affected_flows_func
# Query top-level execution paths
flows = list_flows(repo_root=".", sort_by="depth", limit=5)
# Retrieve detailed flow with source snippets
flow = get_flow(flow_name="handle_request", repo_root=".", include_source=True)
# Analyze impact of file changes
affected = get_affected_flows_func(changed_files=["auth.py"], repo_root=".")
Summary
- Static AST Parsing: CRG uses
trace_flowsincode_review_graph/flows.pyto walk source trees and resolve static call edges without runtime execution. - Incremental Updates: The
incremental_trace_flowsfunction retraces only changed files, enabling efficient updates to the execution path graph. - Structured Storage: Flow records stored via
store_flowsinclude depth metrics, entry-point classification, and ordered step sequences in an atomic SQLite transaction. - Multi-Interface Access: Execution paths are queryable through both CLI commands and Python MCP tools like
get_flowandget_affected_flows_func.
Frequently Asked Questions
How does CRG handle incremental updates when source files change?
CRG implements incremental analysis through the incremental_trace_flows function in code_review_graph/flows.py lines 459-473. This function identifies modified files since the last trace, re-parses only those ASTs, and merges the resulting call edges with the existing flow graph, avoiding costly full-repository rescans.
What specific data is stored for each identified execution flow?
Each flow record contains a unique identifier, the depth (maximum call-chain length from entry), the kind of entry point (Function, Class, etc.), and an ordered list of steps representing caller-to-callee pairs. These fields are defined in the FlowAdjacency model within code_review_graph/graph.py lines 156-165.
How does CRG ensure database consistency during flow storage?
The store_flows function wraps all INSERT operations in a SQLite transaction. If any part of the storage operation fails, the entire transaction rolls back, leaving the database in a consistent state. This atomic behavior is verified in tests/test_transactions.py lines 63-81.
Can CRG trace execution paths across multiple programming languages?
Yes, CRG supports multi-language analysis through language-specific parsers that resolve static imports and attribute accesses for Python, Java, Rust, and other languages. The tracing engine abstracts these differences to produce a unified call graph representation regardless of source language.
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 →