Skip to content

Commit af0fb4d

Browse files
authored
fix(native/cpp): strip reference modifier from parameter names (#1192)
* fix(native/cpp): strip reference modifier from parameter names tree-sitter-cpp's `reference_declarator` rule (covering `&` and `&&`) doesn't expose a `declarator` field, so `child_by_field_name("declarator")` returns None and `unwrap_cpp_declarator` falls through to emitting the full node text (`& action`). Native C++ parameter nodes ended up named `& action` while WASM emitted `action`, producing divergent `contains` and `parameter_of` edges across engines. Fall back to scanning children for the next nested declarator or identifier when the field lookup misses. Covers lvalue (`int& x`) and rvalue (`int&& x`) references, and applies transitively to fields, type-map entries, and function-name extraction since they all route through the helper. Closes #1187 * fix(native/cpp): drop function_declarator from declarator-child fallback (#1192) unwrap_cpp_declarator's main loop has no arm for function_declarator, so including it in next_cpp_declarator_child's match list stalls the loop on a node it cannot unwrap and emits the full node text (e.g. `callback(int)` instead of `callback`) for exotic parameter types like `void (&callback)(int)`. Removing it lets the loop break cleanly and fall back to node_text without the extra detour through a node kind it does not handle.
1 parent d447071 commit af0fb4d

1 file changed

Lines changed: 47 additions & 1 deletion

File tree

  • crates/codegraph-core/src/extractors

crates/codegraph-core/src/extractors/cpp.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,14 @@ fn unwrap_cpp_declarator(node: &Node, source: &[u8]) -> String {
7171
match current.kind() {
7272
"pointer_declarator" | "reference_declarator" | "array_declarator"
7373
| "parenthesized_declarator" => {
74-
if let Some(inner) = current.child_by_field_name("declarator") {
74+
// tree-sitter-cpp's `reference_declarator` rule does not expose a
75+
// `declarator` field, so `child_by_field_name` returns None and
76+
// the full node text (`& name`) leaks out. Fall back to scanning
77+
// children for the next nested declarator or identifier.
78+
let inner = current
79+
.child_by_field_name("declarator")
80+
.or_else(|| next_cpp_declarator_child(&current));
81+
if let Some(inner) = inner {
7582
current = inner;
7683
} else {
7784
break;
@@ -84,6 +91,23 @@ fn unwrap_cpp_declarator(node: &Node, source: &[u8]) -> String {
8491
node_text(&current, source).to_string()
8592
}
8693

94+
fn next_cpp_declarator_child<'a>(node: &Node<'a>) -> Option<Node<'a>> {
95+
for i in 0..node.child_count() {
96+
if let Some(child) = node.child(i) {
97+
match child.kind() {
98+
"identifier"
99+
| "field_identifier"
100+
| "pointer_declarator"
101+
| "reference_declarator"
102+
| "array_declarator"
103+
| "parenthesized_declarator" => return Some(child),
104+
_ => {}
105+
}
106+
}
107+
}
108+
None
109+
}
110+
87111
fn extract_cpp_function_name(node: &Node, source: &[u8]) -> Option<String> {
88112
let declarator = node.child_by_field_name("declarator")?;
89113
extract_cpp_func_name_from_declarator(&declarator, source)
@@ -433,4 +457,26 @@ mod tests {
433457
assert_eq!(s.imports.len(), 2);
434458
assert!(s.imports[0].c_include.unwrap());
435459
}
460+
461+
#[test]
462+
fn reference_parameter_name_strips_ampersand() {
463+
// tree-sitter-cpp's `reference_declarator` does not expose a `declarator`
464+
// field, so the unwrap helper has to scan children for the underlying
465+
// identifier — otherwise the parameter name comes back as `& action`.
466+
let s = parse_cpp("void log_action(const std::string& action) {}");
467+
let func = s.definitions.iter().find(|d| d.name == "log_action").unwrap();
468+
let params = func.children.as_ref().expect("function has children");
469+
assert_eq!(params.len(), 1);
470+
assert_eq!(params[0].name, "action");
471+
assert_eq!(params[0].kind, "parameter");
472+
}
473+
474+
#[test]
475+
fn rvalue_reference_parameter_name_strips_ampersand() {
476+
let s = parse_cpp("void take(int&& x) {}");
477+
let func = s.definitions.iter().find(|d| d.name == "take").unwrap();
478+
let params = func.children.as_ref().expect("function has children");
479+
assert_eq!(params.len(), 1);
480+
assert_eq!(params[0].name, "x");
481+
}
436482
}

0 commit comments

Comments
 (0)