Skip to content

Commit 428edb4

Browse files
authored
fix(native): extract parameters for prototype method definitions (#1345) (#1345)
emit_js_prototype_method and extract_js_prototype_object_literal were emitting children: None for function_expression/arrow_function/method_definition RHS nodes, unlike all other method handlers (handle_method_def, handle_var_decl) which call extract_js_parameters and populate the children field. Call extract_js_parameters at both sites and pass the result through opt_children, completing parity with handle_method_def and handle_var_decl. Add 4 new unit tests verifying non-None complexity, CFG, and children (including all declared parameters) for every affected code shape: direct function assignment, direct arrow assignment, shorthand method definition, and key-value function pair. Closes #1345
1 parent 4fc5b38 commit 428edb4

1 file changed

Lines changed: 80 additions & 2 deletions

File tree

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

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ fn emit_js_prototype_method(class_name: &str, method_name: &str, rhs: &Node, sou
515515
let full_name = format!("{}.{}", class_name, method_name);
516516
match rhs.kind() {
517517
"function_expression" | "arrow_function" => {
518+
let children = extract_js_parameters(rhs, source);
518519
symbols.definitions.push(Definition {
519520
name: full_name,
520521
kind: "method".to_string(),
@@ -523,7 +524,7 @@ fn emit_js_prototype_method(class_name: &str, method_name: &str, rhs: &Node, sou
523524
decorators: None,
524525
complexity: compute_all_metrics(rhs, source, "javascript"),
525526
cfg: build_function_cfg(rhs, "javascript", source),
526-
children: None,
527+
children: opt_children(children),
527528
});
528529
}
529530
"identifier" => {
@@ -545,6 +546,7 @@ fn extract_js_prototype_object_literal(class_name: &str, obj_node: &Node, source
545546
match child.kind() {
546547
"method_definition" => {
547548
let Some(name_node) = child.child_by_field_name("name") else { continue };
549+
let children = extract_js_parameters(&child, source);
548550
symbols.definitions.push(Definition {
549551
name: format!("{}.{}", class_name, node_text(&name_node, source)),
550552
kind: "method".to_string(),
@@ -553,7 +555,7 @@ fn extract_js_prototype_object_literal(class_name: &str, obj_node: &Node, source
553555
decorators: None,
554556
complexity: compute_all_metrics(&child, source, "javascript"),
555557
cfg: build_function_cfg(&child, "javascript", source),
556-
children: None,
558+
children: opt_children(children),
557559
});
558560
}
559561
"shorthand_property_identifier" => {
@@ -2691,6 +2693,82 @@ mod tests {
26912693
assert!(def.is_none(), "built-in prototype assignment should be ignored; got: {:?}", def);
26922694
}
26932695

2696+
#[test]
2697+
fn prototype_direct_method_has_complexity_cfg_and_children() {
2698+
let s = parse_js(
2699+
"function C() {}\n\
2700+
C.prototype.foo = function(x, y) { if (true) { return 1; } return 0; };",
2701+
);
2702+
let def = s.definitions.iter().find(|d| d.name == "C.foo").expect("C.foo missing");
2703+
assert!(def.complexity.is_some(), "C.foo should have complexity metrics");
2704+
assert!(def.cfg.is_some(), "C.foo should have CFG data");
2705+
let children = def.children.as_deref().unwrap_or(&[]);
2706+
assert!(
2707+
children.iter().any(|c| c.name == "x"),
2708+
"C.foo should have parameter 'x'; got: {:?}", children
2709+
);
2710+
assert!(
2711+
children.iter().any(|c| c.name == "y"),
2712+
"C.foo should have parameter 'y'; got: {:?}", children
2713+
);
2714+
}
2715+
2716+
#[test]
2717+
fn prototype_direct_arrow_has_complexity_cfg_and_children() {
2718+
let s = parse_js(
2719+
"function C() {}\n\
2720+
C.prototype.bar = (a, b) => a > 0 ? a : b;",
2721+
);
2722+
let def = s.definitions.iter().find(|d| d.name == "C.bar").expect("C.bar missing");
2723+
assert!(def.complexity.is_some(), "C.bar arrow should have complexity metrics");
2724+
assert!(def.cfg.is_some(), "C.bar arrow should have CFG data");
2725+
let children = def.children.as_deref().unwrap_or(&[]);
2726+
assert!(
2727+
children.iter().any(|c| c.name == "a"),
2728+
"C.bar should have parameter 'a'; got: {:?}", children
2729+
);
2730+
assert!(
2731+
children.iter().any(|c| c.name == "b"),
2732+
"C.bar should have parameter 'b'; got: {:?}", children
2733+
);
2734+
}
2735+
2736+
#[test]
2737+
fn prototype_object_literal_method_definition_has_complexity_cfg_and_children() {
2738+
let s = parse_js(
2739+
"function C() {}\n\
2740+
C.prototype = {\n\
2741+
greet(name) { if (true) { return 'hi'; } return ''; },\n\
2742+
};",
2743+
);
2744+
let def = s.definitions.iter().find(|d| d.name == "C.greet").expect("C.greet missing");
2745+
assert!(def.complexity.is_some(), "C.greet should have complexity metrics");
2746+
assert!(def.cfg.is_some(), "C.greet should have CFG data");
2747+
let children = def.children.as_deref().unwrap_or(&[]);
2748+
assert!(
2749+
children.iter().any(|c| c.name == "name"),
2750+
"C.greet should have parameter 'name'; got: {:?}", children
2751+
);
2752+
}
2753+
2754+
#[test]
2755+
fn prototype_object_literal_pair_fn_has_complexity_cfg_and_children() {
2756+
let s = parse_js(
2757+
"function C() {}\n\
2758+
C.prototype = {\n\
2759+
bar: function(n) { if (true) { return 1; } return 0; },\n\
2760+
};",
2761+
);
2762+
let def = s.definitions.iter().find(|d| d.name == "C.bar").expect("C.bar missing");
2763+
assert!(def.complexity.is_some(), "C.bar should have complexity metrics");
2764+
assert!(def.cfg.is_some(), "C.bar should have CFG data");
2765+
let children = def.children.as_deref().unwrap_or(&[]);
2766+
assert!(
2767+
children.iter().any(|c| c.name == "n"),
2768+
"C.bar should have parameter 'n'; got: {:?}", children
2769+
);
2770+
}
2771+
26942772
/// Phase 8.3e: Object.defineProperty seeds composite type_map key.
26952773
#[test]
26962774
fn type_map_from_define_property() {

0 commit comments

Comments
 (0)