Skip to content

Commit 477222b

Browse files
committed
feat(parity): port the JS points-to solver to the native engine and unify per-engine resolution
Native (Rust): - Extract all eight pts binding kinds in the JS extractor (param, this-call, array-element, spread-arg, for-of, array-callback, object-rest-param, object-prop) and surface them on FileSymbols - Run the same fixed-point points-to solver as the WASM path inside build_call_edges: thisCall-to-fnRef conversion, four-case key gate with receiver-key fallback, hop-penalised alias edges with pts upgrade - Normalize inline-new receivers (new A().t() -> receiver "A") in extract_receiver_name, mirroring extractReceiverName in the TS extractor - Apply the >=0.5 confidence filter on exact cross-file lookups (#1439) WASM/TS: - Plumb params and all eight binding arrays through NativeFileEntry so the hybrid path feeds the native solver - Serialize thisCallBindings across the WASM worker boundary - Backport the native engine's class-field type-annotation extraction (private repo: Repository seeds typeMap "repo"/"this.repo") - Remove the four JS pts post-passes that duplicated the native solver on the hybrid path (param-flow, fnRef, thisCall, object-rest) - Report the native build summary and build_meta counts after the JS edge-writing post-passes so they include CHA/this-dispatch edges (#1452) WASM, full-native orchestrator, and hybrid builds now produce identical edge multisets on the javascript fixture (155 rows each, including confidence and dynamic flags); javascript 42/42 and pts-javascript 13/13 expected edges on both engines; 392 Rust tests, 3043 JS tests, and the 176-test resolution benchmark are green. Closes #1453 Closes #1452 Closes #1439
1 parent 4ef042e commit 477222b

13 files changed

Lines changed: 2150 additions & 552 deletions

File tree

crates/codegraph-core/src/domain/graph/builder/pipeline.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,10 @@ fn build_and_insert_call_edges(
13481348
})
13491349
.collect();
13501350

1351+
fn non_empty<T: Clone>(v: &[T]) -> Option<Vec<T>> {
1352+
if v.is_empty() { None } else { Some(v.to_vec()) }
1353+
}
1354+
13511355
file_entries.push(FileEdgeInput {
13521356
file: rel_path.clone(),
13531357
file_node_id,
@@ -1359,6 +1363,15 @@ fn build_and_insert_call_edges(
13591363
kind: d.kind.clone(),
13601364
line: d.line,
13611365
end_line: d.end_line,
1366+
// Phase 8.3c: ordered parameter names for parameter-flow pts —
1367+
// mirrors buildDefinitionParamsMap reading def.children.
1368+
params: d.children.as_ref().map(|children| {
1369+
children
1370+
.iter()
1371+
.filter(|c| c.kind == "parameter")
1372+
.map(|c| c.name.clone())
1373+
.collect()
1374+
}),
13621375
})
13631376
.collect(),
13641377
calls: symbols
@@ -1382,11 +1395,15 @@ fn build_and_insert_call_edges(
13821395
})
13831396
.collect(),
13841397
type_map,
1385-
fn_ref_bindings: if symbols.fn_ref_bindings.is_empty() {
1386-
None
1387-
} else {
1388-
Some(symbols.fn_ref_bindings.clone())
1389-
},
1398+
fn_ref_bindings: non_empty(&symbols.fn_ref_bindings),
1399+
param_bindings: non_empty(&symbols.param_bindings),
1400+
this_call_bindings: non_empty(&symbols.this_call_bindings),
1401+
array_elem_bindings: non_empty(&symbols.array_elem_bindings),
1402+
spread_arg_bindings: non_empty(&symbols.spread_arg_bindings),
1403+
for_of_bindings: non_empty(&symbols.for_of_bindings),
1404+
array_callback_bindings: non_empty(&symbols.array_callback_bindings),
1405+
object_rest_param_bindings: non_empty(&symbols.object_rest_param_bindings),
1406+
object_prop_bindings: non_empty(&symbols.object_prop_bindings),
13901407
});
13911408
}
13921409

crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs

Lines changed: 805 additions & 117 deletions
Large diffs are not rendered by default.

crates/codegraph-core/src/domain/graph/builder/stages/import_edges.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,14 @@ mod tests {
566566
dataflow: None,
567567
line_count: None,
568568
fn_ref_bindings: vec![],
569+
param_bindings: vec![],
570+
this_call_bindings: vec![],
571+
array_elem_bindings: vec![],
572+
spread_arg_bindings: vec![],
573+
for_of_bindings: vec![],
574+
array_callback_bindings: vec![],
575+
object_rest_param_bindings: vec![],
576+
object_prop_bindings: vec![],
569577
}
570578
}
571579

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

Lines changed: 1058 additions & 25 deletions
Large diffs are not rendered by default.

crates/codegraph-core/src/features/structure.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -921,21 +921,8 @@ mod tests {
921921
#[test]
922922
fn line_count_map_from_symbols() {
923923
let mut file_symbols = HashMap::new();
924-
let mut sym = FileSymbols {
925-
file: "src/a.ts".to_string(),
926-
definitions: vec![],
927-
imports: vec![],
928-
calls: vec![],
929-
classes: vec![],
930-
exports: vec![],
931-
type_map: vec![],
932-
return_type_map: vec![],
933-
call_assignments: vec![],
934-
ast_nodes: vec![],
935-
dataflow: None,
936-
line_count: Some(42),
937-
fn_ref_bindings: vec![],
938-
};
924+
let mut sym = FileSymbols::new("src/a.ts".to_string());
925+
sym.line_count = Some(42);
939926
file_symbols.insert("src/a.ts".to_string(), sym.clone());
940927

941928
sym.file = "src/b.ts".to_string();

crates/codegraph-core/src/types.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,102 @@ pub struct FnRefBinding {
318318
pub rhs_receiver: Option<String>,
319319
}
320320

321+
/// Argument-to-parameter binding at a call site (Phase 8.3c).
322+
/// Records `f(x)` where `x` is an identifier that may carry a function reference.
323+
/// Mirrors the `ParamBinding` interface in `src/types.ts`.
324+
#[napi(object)]
325+
#[derive(Debug, Clone, Serialize, Deserialize)]
326+
pub struct ParamBinding {
327+
pub callee: String,
328+
#[napi(js_name = "argIndex")]
329+
pub arg_index: u32,
330+
#[napi(js_name = "argName")]
331+
pub arg_name: String,
332+
}
333+
334+
/// This-context binding from `fn.call(ctx, ...)` / `fn.apply(ctx, ...)`.
335+
/// Mirrors the `ThisCallBinding` interface in `src/types.ts`.
336+
#[napi(object)]
337+
#[derive(Debug, Clone, Serialize, Deserialize)]
338+
pub struct ThisCallBinding {
339+
pub callee: String,
340+
#[napi(js_name = "thisArg")]
341+
pub this_arg: String,
342+
}
343+
344+
/// Array-element binding from `const arr = [fn1, fn2]` (Phase 8.3e).
345+
/// Mirrors the `ArrayElemBinding` interface in `src/types.ts`.
346+
#[napi(object)]
347+
#[derive(Debug, Clone, Serialize, Deserialize)]
348+
pub struct ArrayElemBinding {
349+
#[napi(js_name = "arrayName")]
350+
pub array_name: String,
351+
pub index: u32,
352+
#[napi(js_name = "elemName")]
353+
pub elem_name: String,
354+
}
355+
356+
/// Spread-argument binding from `f(...arr)` (Phase 8.3e).
357+
/// Mirrors the `SpreadArgBinding` interface in `src/types.ts`.
358+
#[napi(object)]
359+
#[derive(Debug, Clone, Serialize, Deserialize)]
360+
pub struct SpreadArgBinding {
361+
pub callee: String,
362+
#[napi(js_name = "arrayName")]
363+
pub array_name: String,
364+
#[napi(js_name = "startIndex")]
365+
pub start_index: u32,
366+
}
367+
368+
/// For-of iteration binding from `for (const x of arr)` (Phase 8.3e).
369+
/// Mirrors the `ForOfBinding` interface in `src/types.ts`.
370+
#[napi(object)]
371+
#[derive(Debug, Clone, Serialize, Deserialize)]
372+
pub struct ForOfBinding {
373+
#[napi(js_name = "varName")]
374+
pub var_name: String,
375+
#[napi(js_name = "sourceName")]
376+
pub source_name: String,
377+
#[napi(js_name = "enclosingFunc")]
378+
pub enclosing_func: String,
379+
}
380+
381+
/// Array-callback binding from `Array.from(arr, cb)` (Phase 8.3e).
382+
/// Mirrors the `ArrayCallbackBinding` interface in `src/types.ts`.
383+
#[napi(object)]
384+
#[derive(Debug, Clone, Serialize, Deserialize)]
385+
pub struct ArrayCallbackBinding {
386+
#[napi(js_name = "sourceName")]
387+
pub source_name: String,
388+
#[napi(js_name = "calleeName")]
389+
pub callee_name: String,
390+
}
391+
392+
/// Object-rest parameter binding from `function f({ a, ...rest })` (Phase 8.3f).
393+
/// Mirrors the `ObjectRestParamBinding` interface in `src/types.ts`.
394+
#[napi(object)]
395+
#[derive(Debug, Clone, Serialize, Deserialize)]
396+
pub struct ObjectRestParamBinding {
397+
pub callee: String,
398+
#[napi(js_name = "restName")]
399+
pub rest_name: String,
400+
#[napi(js_name = "argIndex")]
401+
pub arg_index: u32,
402+
}
403+
404+
/// Object-property binding from `const obj = { e4 }` / `{ e4: fn }` (Phase 8.3f).
405+
/// Mirrors the `ObjectPropBinding` interface in `src/types.ts`.
406+
#[napi(object)]
407+
#[derive(Debug, Clone, Serialize, Deserialize)]
408+
pub struct ObjectPropBinding {
409+
#[napi(js_name = "objectName")]
410+
pub object_name: String,
411+
#[napi(js_name = "propName")]
412+
pub prop_name: String,
413+
#[napi(js_name = "valueName")]
414+
pub value_name: String,
415+
}
416+
321417
#[napi(object)]
322418
#[derive(Debug, Clone, Serialize, Deserialize)]
323419
pub struct FileSymbols {
@@ -341,6 +437,30 @@ pub struct FileSymbols {
341437
/// Phase 8.3: function-reference bindings for points-to analysis.
342438
#[napi(js_name = "fnRefBindings")]
343439
pub fn_ref_bindings: Vec<FnRefBinding>,
440+
/// Phase 8.3c: argument-to-parameter bindings for parameter-flow pts.
441+
#[napi(js_name = "paramBindings")]
442+
pub param_bindings: Vec<ParamBinding>,
443+
/// This-context bindings from `fn.call(ctx)` / `fn.apply(ctx)`.
444+
#[napi(js_name = "thisCallBindings")]
445+
pub this_call_bindings: Vec<ThisCallBinding>,
446+
/// Phase 8.3e: array-element bindings from `const arr = [fn1, fn2]`.
447+
#[napi(js_name = "arrayElemBindings")]
448+
pub array_elem_bindings: Vec<ArrayElemBinding>,
449+
/// Phase 8.3e: spread-argument bindings from `f(...arr)`.
450+
#[napi(js_name = "spreadArgBindings")]
451+
pub spread_arg_bindings: Vec<SpreadArgBinding>,
452+
/// Phase 8.3e: for-of iteration variable bindings.
453+
#[napi(js_name = "forOfBindings")]
454+
pub for_of_bindings: Vec<ForOfBinding>,
455+
/// Phase 8.3e: array callback bindings from `Array.from(arr, cb)`.
456+
#[napi(js_name = "arrayCallbackBindings")]
457+
pub array_callback_bindings: Vec<ArrayCallbackBinding>,
458+
/// Phase 8.3f: object-rest parameter bindings from `function f({ ...rest })`.
459+
#[napi(js_name = "objectRestParamBindings")]
460+
pub object_rest_param_bindings: Vec<ObjectRestParamBinding>,
461+
/// Phase 8.3f: object-property bindings from `const obj = { fn }`.
462+
#[napi(js_name = "objectPropBindings")]
463+
pub object_prop_bindings: Vec<ObjectPropBinding>,
344464
}
345465

346466
impl FileSymbols {
@@ -359,6 +479,14 @@ impl FileSymbols {
359479
return_type_map: Vec::new(),
360480
call_assignments: Vec::new(),
361481
fn_ref_bindings: Vec::new(),
482+
param_bindings: Vec::new(),
483+
this_call_bindings: Vec::new(),
484+
array_elem_bindings: Vec::new(),
485+
spread_arg_bindings: Vec::new(),
486+
for_of_bindings: Vec::new(),
487+
array_callback_bindings: Vec::new(),
488+
object_rest_param_bindings: Vec::new(),
489+
object_prop_bindings: Vec::new(),
362490
}
363491
}
364492
}

0 commit comments

Comments
 (0)