Skip to content

C++ out-of-line method definitions: CALLS edge source falls back to Module (file-level) instead of the enclosing Method #554

Description

@spwlyzx

Version

0.8.1

Platform

macOS (Apple Silicon)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

standard

What happened, and what did you expect?

For C++ out-of-line method definitions (void Foo::Bar() { ... } in a .cpp file), CALLS edges emitted from call sites inside the method body have source = Module (file-level node) instead of source = the enclosing Method node. This causes trace_path(direction=inbound) to return file paths rather than specific caller method names, and prevents multi-hop method-to-method BFS traversal.

Expected: CALLS edges should have source = Method("Foo::Bar"), matching how in-class definitions are handled.

Actual: CALLS edges have source = Module("path/to/file.cpp"). The calls_find_source() fallback to __file__ fires because call->enclosing_func_qn does not match the graph node's qualified name after PR #428 promoted out-of-line definitions from Function to Method (changing their QN).

Reproduction

Reproduction:

  1. Create a minimal C++ project:
// include/factory.h
#pragma once
class TileDataFactory {
public:
    void CreateTileData(int level);
};

// src/factory.cpp
#include "factory.h"
void TileDataFactory::CreateTileData(int level) {}  // out-of-line

// src/consumer.cpp
#include "factory.h"
class DataProvider {
public:
    void ConvertBlob();   // in-class declaration
};

void DataProvider::ConvertBlob() {   // out-of-line definition
    TileDataFactory f;
    f.CreateTileData(1);   // <-- this call site
}
  1. Index and query:
codebase-memory-mcp cli index_repository '{"repo_path": "/tmp/repro"}'
codebase-memory-mcp cli query_graph '{"query": "MATCH (src)-[:CALLS]->(dst {name: \"CreateTileData\"}) RETURN src.name, src.label, dst.name, dst.label", "project": "..."}'
  1. Actual output: src.name = "src/consumer.cpp", src.label = "Module"
  2. Expected output: src.name = "ConvertBlob", src.label = "Method" (with parent_class = DataProvider)

Root cause (from source inspection):

In src/pipeline/pass_calls.c L320–333, calls_find_source() first tries enclosing_func_qn:

static const cbm_gbuf_node_t *calls_find_source(ctx, rel, enclosing_qn) {
    if (enclosing_qn) {
        src = cbm_gbuf_find_by_qn(ctx->gbuf, enclosing_qn);
    }
    if (!src) {
        // fallback to file-level Module
        file_qn = cbm_pipeline_fqn_compute(ctx->project_name, rel, "__file__");
        src = cbm_gbuf_find_by_qn(ctx->gbuf, file_qn);
    }
}

After PR #428 (commit a50b086), out-of-line method definitions are correctly promoted from Function to Method with a class-qualified QN. However, call->enclosing_func_qn (set during extraction in pass_definitions.c) still carries the old pre-promotion QN (free-function style), so gbuf_find_by_qn fails → fallback fires.

This is visible in production: a 2500-file C++ engine module shows 99.6% of CALLS edges have source.label = Module (5779 Module→Method vs 43 Function/Method→Function/Method).

Logs


Project scale (if relevant)

2543 files, 36,219 nodes, 79,170 edges

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions