-
Notifications
You must be signed in to change notification settings - Fork 59
Call Graph Analysis
Drift builds a complete call graph of your codebase, enabling powerful data flow analysis and impact assessment.
A call graph maps every function call in your codebase:
main()
βββ handleRequest()
β βββ validateInput()
β βββ authenticate()
β β βββ verifyToken()
β βββ processData()
β βββ fetchUser()
β β βββ db.query("SELECT * FROM users")
β βββ updateRecord()
β βββ db.query("UPDATE users SET...")
βββ sendResponse()
This enables Drift to answer questions like:
- "What data can this code access?"
- "Who can access this sensitive data?"
- "What's the blast radius if I change this function?"
# Build call graph (happens automatically during scan)
drift scan
# Or build explicitly
drift callgraph build
# Check status
drift callgraph status
# Security-prioritized view (P0-P4 tiers)
drift callgraph status --securityOutput:
Call Graph Status
=================
Files analyzed: 247
Functions extracted: 1,842
Calls mapped: 5,631
Data access points: 312
Languages:
TypeScript: 189 files, 1,456 functions
Python: 58 files, 386 functions
Frameworks detected:
Express: 45 route handlers
Prisma: 89 data access points
FastAPI: 23 endpoints
"What data can this code access?"
Starting from a code location, trace forward to see all data it can reach:
# From a specific line
drift callgraph reach src/api/users.ts:42
# From a function
drift callgraph reach handleUserUpdate
# Limit traversal depth
drift callgraph reach src/api/users.ts:42 --max-depth 5Example Output:
Forward Reachability from src/api/users.ts:42
=============================================
Direct Access (depth 1):
β users.email (PII)
β users.name (PII)
β users.updated_at
Via fetchUserProfile (depth 2):
β users.password_hash (SENSITIVE)
β users.phone (PII)
β sessions.token (SENSITIVE)
Via updateUserPreferences (depth 3):
β preferences.*
β audit_log.*
Total: 12 data points reachable
- 4 PII fields
- 2 SENSITIVE fields
- 6 regular fields
{
"direction": "forward",
"location": "src/api/users.ts:42",
"maxDepth": 10,
"sensitiveOnly": true,
"limit": 15
}"Who can access this data?"
Starting from a data point, trace backward to find all code that can access it:
# Who can access password hashes?
drift callgraph inverse users.password_hash
# Who can access any user data?
drift callgraph inverse users
# Limit depth
drift callgraph inverse users.email --max-depth 5Example Output:
Inverse Reachability to users.password_hash
===========================================
Direct Access:
β src/auth/login.ts:verifyPassword (line 45)
β src/auth/register.ts:hashPassword (line 23)
β src/admin/users.ts:resetPassword (line 89)
Indirect Access (via verifyPassword):
β src/api/auth.controller.ts:login (line 34)
β src/api/auth.controller.ts:changePassword (line 78)
Entry Points:
POST /api/auth/login
POST /api/auth/change-password
POST /api/admin/users/:id/reset-password
β οΈ Warning: 3 entry points can reach sensitive data
{
"direction": "inverse",
"target": "users.password_hash",
"maxDepth": 10,
"limit": 15
}"What breaks if I change this?"
Before making changes, understand the blast radius:
# Analyze impact of changing a file
drift callgraph impact src/auth/login.ts
# Analyze impact of changing a function
drift callgraph impact verifyToken
# Find dead code (functions never called)
drift callgraph dead
# Analyze test coverage for sensitive data
drift callgraph coverageExample Output:
Impact Analysis: src/auth/login.ts
==================================
Direct Callers (12):
src/api/auth.controller.ts:login
src/api/auth.controller.ts:refreshToken
src/middleware/auth.ts:requireAuth
...
Indirect Callers (47):
All routes using @RequireAuth middleware
Affected Tests (8):
tests/auth/login.test.ts
tests/api/auth.controller.test.ts
tests/middleware/auth.test.ts
tests/e2e/auth-flow.test.ts
...
Entry Points Affected (23):
All authenticated API endpoints
Risk Assessment: HIGH
- Core authentication function
- 23 entry points depend on this
- Recommend comprehensive testing
{
"target": "src/auth/login.ts",
"maxDepth": 10,
"limit": 10
}Get detailed information about a specific function:
drift callgraph function handleUserUpdateOutput:
Function: handleUserUpdate
==========================
Location: src/services/user.service.ts:45-89
Signature: async handleUserUpdate(userId: string, data: UpdateUserDTO): Promise<User>
Calls (8):
β validateUpdateData (src/validators/user.ts:12)
β fetchUser (src/repositories/user.ts:34)
β checkPermissions (src/auth/permissions.ts:56)
β updateUser (src/repositories/user.ts:78)
β invalidateCache (src/cache/user.ts:23)
β publishEvent (src/events/user.ts:45)
β logAudit (src/audit/logger.ts:12)
β sendNotification (src/notifications/user.ts:34)
Called By (3):
β UserController.update (src/controllers/user.controller.ts:67)
β AdminController.updateUser (src/controllers/admin.controller.ts:123)
β BatchProcessor.processUserUpdates (src/jobs/batch.ts:89)
Data Access:
β users.* (read, write)
β audit_log.* (write)
β cache:user:* (delete)
Patterns Detected:
- Repository pattern
- Event-driven updates
- Audit logging
Drift's call graph works across languages:
TypeScript Frontend Python Backend
================== ==============
fetchUsers()
β fetch('/api/users') βββ get_users()
β db.query(users)
updateUser()
β fetch('/api/users/:id') βββ update_user()
β validate_input()
β db.update(users)
This enables:
- API contract verification β Frontend calls match backend endpoints
- Full-stack data flow β Trace data from UI to database
- Cross-service impact β Understand microservice dependencies
Drift uses Tree-sitter to parse source code into ASTs:
// Source code
function handleLogin(email: string, password: string) {
const user = await findUserByEmail(email);
const valid = await verifyPassword(password, user.passwordHash);
return valid ? createSession(user) : null;
}
// Extracted calls
[
{ callee: "findUserByEmail", args: ["email"], line: 2 },
{ callee: "verifyPassword", args: ["password", "user.passwordHash"], line: 3 },
{ callee: "createSession", args: ["user"], line: 4 }
]Drift resolves call targets across files:
handleLogin
β findUserByEmail β src/repositories/user.ts:findUserByEmail
β verifyPassword β src/auth/password.ts:verifyPassword
β createSession β src/auth/session.ts:createSession
Drift detects database access patterns:
// Prisma
const user = await prisma.user.findUnique({ where: { email } });
// Detected: users.* (read)
// Raw SQL
const result = await db.query('SELECT * FROM users WHERE email = $1', [email]);
// Detected: users.* (read)
// TypeORM
const user = await userRepository.findOne({ email });
// Detected: users.* (read)All data is combined into a unified call graph:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Call Graph β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Nodes: Functions, Methods, Classes β
β Edges: Calls, Data Access, Imports β
β Metadata: Line numbers, Types, Patterns β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Call graph data is stored in SQLite for optimal performance:
.drift/lake/callgraph/
βββ callgraph.db # SQLite database with WAL mode
Key benefits:
- O(1) memory queries β No need to load entire graph
- Concurrent access β Multiple tools can query simultaneously
- 8x faster builds β Parallel parsing with batched writes
- No OOM β Handles 10K+ file codebases that previously crashed
Only changed files are re-analyzed:
# Full build
drift callgraph build
# Incremental (default)
drift callgraph build --incremental
# Force full rebuild
drift callgraph build --force| Codebase Size | Build Time | Query Time |
|---|---|---|
| <10K LOC | <1s | <50ms |
| 10-100K LOC | 1-5s | <100ms |
| 100K-1M LOC | 5-30s | <500ms |
| >1M LOC | 30s-2min | <1s |
Note: v1.0 introduced SQLite-backed storage and Rust-native parsing, providing 4-8x performance improvements over previous versions.
# Always scan first
drift scan
# Then query
drift callgraph reach src/api/users.ts:42For large codebases, limit traversal depth:
drift callgraph reach src/api/users.ts:42 --max-depth 5Use --sensitive-only to focus on what matters:
drift callgraph inverse users.password_hash --sensitive-onlyBefore making changes:
# 1. Check what you're changing
drift callgraph function handleLogin
# 2. Check impact
drift callgraph impact handleLogin
# 3. Check test coverage for sensitive data
drift callgraph coverage
# 4. Check what tests to run
drift test-topology affected src/auth/login.tsRun drift scan first to build the call graph.
Check the function name matches exactly. Use drift callgraph status to see what's indexed.
- Use
--max-depthto limit traversal - Use
--sensitive-onlyto filter results - Run
drift callgraph build --forceto rebuild
Some dynamic calls can't be statically analyzed:
-
eval()/exec() - Dynamic imports
- Reflection-based calls
Drift uses regex fallback for common patterns but may miss edge cases.
- Cortex V2 Overview
- Memory Setup Wizard
- Memory CLI
- Universal Memory Types
- Learning System
- Token Efficiency
- Causal Graphs
- Code Generation
- Predictive Retrieval
- Architecture
- Call Graph Analysis
- Impact Analysis
- Security Analysis
- Data Boundaries
- Test Topology
- Coupling Analysis
- Error Handling Analysis
- Wrappers Detection
- Environment Variables
- Constants Analysis
- Styling DNA
- Constraints
- Contracts
- Decision Mining
- Speculative Execution
- Watch Mode
- Trends Analysis
- Projects Management
- Package Context
- Monorepo Support
- Reports & Export
- Dashboard
- 10 Languages
- 21 Frameworks
- 16 ORMs
- 400+ Detectors
- 50+ MCP Tools
- 60+ CLI Commands
- 23 Memory Types