# How code-review-graph Extracts CALLS, IMPORTS_FROM, and INHERITS Edges

> Discover how code-review-graph extracts CALLS, IMPORTS_FROM, and INHERITS edges by parsing language-specific ASTs. Learn about its dedicated resolvers and typed Edge objects.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: deep-dive
- Published: 2026-07-22

---

**The code-review-graph parser extracts CALLS, IMPORTS_FROM, and INHERITS edges by traversing language-specific ASTs using dedicated resolvers that emit typed Edge objects when they encounter call expressions, import statements, and class inheritance declarations.**

The open-source `code-review-graph` repository provides a language-agnostic tool that transforms source code into a queryable graph structure. By walking the abstract syntax tree (AST) of every source file, the parser identifies three fundamental relationship types that power downstream analysis like visualisation, blast-radius detection, and dead-code identification.

## Parser Architecture Overview

The extraction pipeline in [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py) coordinates a five-step process to build the graph:

1. **File discovery** – Loads every file matching supported extensions (Python, TypeScript, Java, C++, etc.).
2. **Language dispatch** – Selects a resolver module based on file extension (e.g., `jedi_resolver` for Python, `ts_resolver` for TypeScript, `java_resolver` for Java).
3. **AST construction** – Each resolver builds an AST using the appropriate library (Jedi for Python, TypeScript-compiler-API for TS, JavaParser for Java).
4. **Visitor traversal** – A visitor walks the tree and invokes edge-emission helpers (`_emit_call`, `_emit_import`, `_emit_inherit`).
5. **Edge emission** – These helpers append an `Edge` object to the in-memory graph defined in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py), which persists after all files are processed.

## How Each Edge Type Is Extracted

### CALLS Edges

**CALLS** edges represent function or method invocations. In each language-specific resolver, the visitor looks for call-expression nodes such as Python's `Call`, TypeScript's `NewExpression`, or Java's `MethodInvocation`.

When a resolver successfully identifies a callee, it instantiates `Edge(kind="CALLS", source=<caller-qualified>, target=<callee-qualified>)`. For example, in [`code_review_graph/jedi_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/jedi_resolver.py), the resolver uses Jedi's name resolution to determine the fully qualified name of both the caller and the target function before emitting the edge.

### IMPORTS_FROM Edges

**IMPORTS_FROM** edges model dependency relationships between files or modules. Resolvers inspect import-statement nodes including Python's `Import` and `ImportFrom`, JavaScript's `import ... from ...`, Java's `import` declarations, or C++ `include` directives.

The edge connects the importer file to the module or file supplying the symbols: `Edge(kind="IMPORTS_FROM", source=<importer-file>, target=<imported-module-or-file>)`. The target represents the source of the imported symbols rather than individual imported names, creating a file-to-file dependency link suitable for build-graph analysis.

### INHERITS Edges

**INHERITS** edges capture class hierarchy relationships. When a resolver encounters a class definition containing base-class lists, it emits inheritance edges.

For Python, this means inspecting `ClassDef.bases`; for Java, checking `extends` and `implements` clauses; for TypeScript, examining `heritageClauses`. The resulting `Edge(kind="INHERITS", source=<child-class-qualified>, target=<parent-class-qualified>)` connects the derived class to its parent or implemented interface.

## Language-Specific Resolvers

The parser delegates AST traversal to modular resolvers located in the `code_review_graph/` directory:

- **[`jedi_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/jedi_resolver.py)** – Handles Python source files using the Jedi library to resolve names and extract the three edge types from Python's AST.
- **[`ts_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/ts_resolver.py)** – Processes TypeScript and JavaScript files via the TypeScript-compiler-API, identifying call expressions, ES6 modules, and class heritage.
- **[`java_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/java_resolver.py)** – Extracts edges from Java source using JavaParser, handling method invocations, import statements, and class inheritance declarations.

Each resolver implements the same visitor pattern but uses language-specific node types to identify relationships, ensuring the graph model remains uniform across languages.

## Querying Extracted Edges

After parsing completes, you can query the in-memory graph using the API defined in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py):

```python
from code_review_graph import parse, EdgeKind

# Parse a repository (or a single file) and obtain the full graph

graph = parse(root_path="/path/to/repo")

# 1️⃣ All CALLS edges

calls = graph.edges_of_kind(EdgeKind.CALLS)
print(f"Found {len(calls)} CALLS relationships")
for e in calls[:5]:
    print(f"{e.source} → {e.target}")

# 2️⃣ All IMPORTS_FROM edges

imports = graph.edges_of_kind(EdgeKind.IMPORTS_FROM)
print(f"Found {len(imports)} IMPORTS_FROM relationships")

# 3️⃣ All INHERITS edges

inherits = graph.edges_of_kind(EdgeKind.INHERITS)
print(f"Found {len(inherits)} INHERITS relationships")

```

The `Edge` dataclass provides a consistent interface for accessing `source`, `target`, and `kind` attributes regardless of which language resolver created the edge.

## Summary

- **The parser** in [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py) orchestrates AST parsing across multiple languages using specialized resolver modules.
- **CALLS edges** are emitted when resolvers identify function or method call expressions and successfully resolve the callee's qualified name.
- **IMPORTS_FROM edges** connect importer files to their dependency sources by analyzing import statements and module declarations.
- **INHERITS edges** represent class hierarchy relationships extracted from base-class lists in class definitions.
- All edges use the uniform `Edge` dataclass defined in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py), enabling downstream tools to treat relationships interchangeably across Python, TypeScript, Java, and other supported languages.

## Frequently Asked Questions

### How does code-review-graph handle name resolution for CALLS edges in Python?

The [`jedi_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/jedi_resolver.py) module leverages the Jedi library's static analysis capabilities to resolve symbol names across the entire project. When the visitor encounters a `Call` node, Jedi performs name lookup to determine the fully qualified path of the target function, ensuring edges point to the actual definition rather than just the local alias or import name.

### Can the parser extract edges from languages not explicitly supported?

The architecture supports adding new resolvers by implementing the visitor pattern for additional languages. You would create a new resolver module (e.g., [`cpp_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/cpp_resolver.py)) that constructs an AST using an appropriate parser (like Tree-sitter or Clang), then implements `_emit_call`, `_emit_import`, and `_emit_inherit` helpers to populate `Edge` objects with the same three relationship types.

### What is the difference between IMPORTS_FROM and CALLS edges?

**IMPORTS_FROM** edges represent static dependencies between files or modules at the import level, while **CALLS** edges represent dynamic execution flow between specific functions or methods. A file may import another module (IMPORTS_FROM) without necessarily calling any functions from it, or it may call functions from imported modules (requiring both an IMPORTS_FROM edge to the file and a CALLS edge to the specific function).

### Where are the extracted edges stored after parsing?

Edges are stored in memory using the `Edge` dataclass defined in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) and managed by the graph object returned by `parse()`. The graph persists as a Python object during runtime, allowing immediate querying via methods like `edges_of_kind()`. Persistence to disk or export to graph databases requires additional serialization logic not shown in the core parser implementation.