Skip to content

cfg-gated twin functions collapse into one node; get_code_snippet returns the inactive branch's body #495

@metalmon

Description

@metalmon

Bug Description

When two items share a qualified name and are distinguished only by #[cfg(...)] attributes (the common Rust #[cfg(feature = "x")] / #[cfg(not(feature = "x"))] pair), the indexer stores a single graph node. get_code_snippet then returns the body of one arbitrary branch — in practice the inactive/fallback one — silently hiding the real implementation. An agent asking "what does f do?" gets a misleading answer (e.g. "it's a no-op returning None") when the feature-enabled build has a full implementation.

Steps to Reproduce

Index any Rust crate containing a cfg-gated twin, e.g.:

#[cfg(feature = "rag-pdf")]
fn try_extract_pdf_text(bytes: &[u8]) -> Option<String> {
    if bytes.len() < 5 || &bytes[..5] != b"%PDF-" { return None; }
    /* real extraction */
}

#[cfg(not(feature = "rag-pdf"))]
fn try_extract_pdf_text(_bytes: &[u8]) -> Option<String> { None }
query_graph: MATCH (n) WHERE n.name = 'try_extract_pdf_text'
             RETURN n.qualified_name, n.start_line, n.end_line, n.signature

Observed

  • total: 1 — only one node exists for the two definitions.
  • It is the #[cfg(not(...))] stub: start_line 385, end_line 387, signature (_bytes: &[u8]).
  • get_code_snippet returns fn try_extract_pdf_text(_bytes: &[u8]) -> Option<String> { None } — the real #[cfg(feature = "rag-pdf")] impl (lines 372–383) is absent from the graph entirely.

Expected

Either (a) keep both definitions as distinct nodes tagged by their cfg predicate, or (b) at minimum surface that the symbol has multiple cfg-gated definitions so get_code_snippet can't silently return a non-representative branch. Returning the inactive fallback as if it were the implementation is the worst outcome.

Impact

  • get_code_snippet — a core tool — can return source that is misleading or the opposite of the real behavior.
  • Complexity/metrics (complexity, cognitive, bt) are computed from whichever branch wins, so they misrepresent the active build.
  • Common in real Rust: #[cfg(feature)], #[cfg(test)], #[cfg(unix)]/#[cfg(windows)] twins.

Relation to existing issues

Distinct from #405 (which targets call-edge resolution via the rust-analyzer integration) — this is a node-extraction / snippet-fidelity defect that's independent of call-graph accuracy and fixable in the existing C pipeline. Not #478 (cross-package bare-name collision) nor #438 (edge→Module attribution).

Environment

  • codebase-memory-mcp v0.8.1
  • Project: Rust workspace (~786 Rust files), Windows 11
  • Repro symbol: crates/zeroclaw-runtime/src/tools/file_read.rs

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edges

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions