Skip to content

feat(graph): add Rust code graph extractor#101

Open
abhinav-phi wants to merge 2 commits into
mex-memory:code-graph-previewfrom
abhinav-phi:feat/rust-code-graph-extractor
Open

feat(graph): add Rust code graph extractor#101
abhinav-phi wants to merge 2 commits into
mex-memory:code-graph-previewfrom
abhinav-phi:feat/rust-code-graph-extractor

Conversation

@abhinav-phi

@abhinav-phi abhinav-phi commented Jul 15, 2026

Copy link
Copy Markdown

What

  • Added a new Rust code graph extractor implementing the existing frozen LanguageExtractor interface.
  • Registered Rust support in the language and grammar registries.
  • Added .rs file detection and vendored the Tree-sitter Rust WASM grammar.
  • Added a representative Rust fixture and focused extractor tests covering common Rust constructs.

Why

Closes #96

This adds initial Rust support to the code graph preview by extracting:

  • Modules
  • Functions
  • Structs
  • Enums
  • Traits
  • Impl blocks
  • Methods
  • Constants
  • Static variables
  • Imports (use)
  • Calls
  • Containment relationships
  • Explicit trait implementations

Cross-file references remain unresolved through targetName, and macro invocations are handled conservatively as required.

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Docs
  • CI/Tooling

How to test

  1. Run:

    npm run typecheck
  2. Run:

    npm test
  3. Run:

    npm run build
  4. Verify that:

    • .rs files are recognized correctly.
    • Rust modules, functions, structs, enums, traits, impl blocks, methods, constants, and statics are extracted.
    • Import, call, containment, and explicit trait implementation references are emitted.
    • Cross-file references remain unresolved through targetName.
    • The Rust grammar WASM is included in the build output.
    • The new Rust extractor tests pass.

Checklist

  • Tests pass (npm test)
  • No breaking changes
  • Tested locally with a real project

Code-graph preview

  • This PR targets code-graph-preview, not main
  • The linked issue states Target branch: code-graph-preview
  • The change follows the frozen LanguageExtractor or FrameworkResolver interface
  • A focused fixture and assertions for the expected node/edge shape are included
  • Any new grammar WASM, extension mapping, extractor, or resolver is registered
  • No graph identity, reconciliation, schema, or drift-semantics changes are included

@abhinav-phi abhinav-phi changed the base branch from main to code-graph-preview July 15, 2026 18:48

@theDakshJaitly theDakshJaitly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes because the implementation does not yet satisfy several explicit acceptance criteria from #96. The existing typecheck, full test suite, and build pass, but focused cases reproduce the inline issues below.

Comment thread src/graph/extraction/languages/rust.ts Outdated
if (!body) return;
this.scopeStack.push(id);
for (const member of body.namedChildren) {
if (member.type === "function_item") {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trait methods without default bodies parse as function_signature_item, not function_item, so declarations such as fn greet(&self) -> String; are silently dropped. The current fixture contains exactly this case, but its test only asserts the Greeter interface node. Please handle signature-only trait methods too and assert that Greeter::greet is emitted with the expected containment/signature data.

private walkBody(body: TSNode, ownerId: string): void {
const type = body.type;

if (CALL_TYPES.has(type)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This body walker never handles Rust struct_expression nodes, so even the fixture's explicit User { ... } construction emits no instantiates -> User reference. Issue #96 explicitly requires instantiation references where syntax is explicit. Please extract struct construction here (and cover it with a focused assertion).

private extractFunction(node: TSNode, isMethod = false): void {
const name = nameOf(node, this.source);
if (!name) return;
const id = this.createNode(isMethod ? "method" : "function", name, node, {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicit generic parameters are not copied into GraphNode.typeParameters: for example, fn make<T> currently produces typeParameters: undefined. The same omission affects structs/enums/traits. Capturing explicit generics is an acceptance criterion in #96, so please parse the grammar's type-parameter field for each supported declaration and add coverage.

// correct (e.g. `Foo::method`).

// Check if the struct/enum is already in the file.
let ownerId: string | null | undefined = this.nodes.find(n => n.name === typeName && (n.kind === "class" || n.kind === "enum" || n.kind === "interface"))?.id;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lookup makes containment depend on declaration order. Valid Rust such as impl User { fn greet(&self) {} } struct User; creates a namespace owner for the impl, and the method never becomes contained by the later User class node. Please make same-file type ownership order-independent, for example by collecting declarations before visiting impls or deferring impl binding.

Comment thread src/graph/extraction/languages/rust.ts Outdated
if (calleeName) this.addRef(ownerId, calleeName, "calls", node);

const args = getChildByField(node, "arguments");
if (args) for (const child of args.namedChildren) this.walkBody(child, ownerId);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguments are walked here and then walked a second time when walkBody continues through all of the call node's namedChildren. As a result, consume(make()) emits two identical calls -> make references, which are persisted as duplicate unresolved refs/edges. Please ensure call arguments are traversed exactly once and add a count-based regression assertion.

tsx: "tree-sitter-tsx.wasm",
javascript: "tree-sitter-javascript.wasm",
jsx: "tree-sitter-javascript.wasm",
rust: "tree-sitter-rust.wasm",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new vendored WASM binary is registered, but its upstream source, exact version/commit, and license are not documented anywhere in this PR. That provenance is explicitly required by issue #96 and docs/extractors.md; please add it alongside the vendored grammar documentation before merge.

@abhinav-phi

Copy link
Copy Markdown
Author

Addressed all requested review feedback:

  • Added support for signature-only trait methods.
  • Added struct instantiation extraction.
  • Captured explicit generic type parameters.
  • Made impl binding order-independent.
  • Removed duplicate call edges.
  • Documented the vendored Rust grammar provenance.
  • Added focused regression tests for all requested cases.

Re-ran validation:

  • npm run typecheck
  • npm test (328/328)
  • npm run build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Rust] Add code-graph extractor

2 participants