Skip to content

Commit 4a1329f

Browse files
authored
fix(native): add first-write-wins dedup to Rust type-map entry helpers
* fix(native): add first-write-wins dedup to Rust type-map entry helpers `push_type_map_entry` in helpers.rs always appended to the Vec without checking for duplicate keys, diverging from the TS `setTypeMapEntry` which only writes when the new confidence is strictly higher than any existing entry for the same key. Introduce `set_type_map_entry` (mirrors TS `setTypeMapEntry`) that scans for an existing entry and skips/replaces based on confidence. Rewrite `push_type_map_entry` to delegate to it so all existing call sites get the fix automatically. In the `field_definition` handler's `None` branch (class expressions), replace the bare `push_type_map_entry` calls with `set_type_map_entry` at the explicit confidence values that match the TS path. Also replace the `Some(class_name)` branch's direct `symbols.type_map.push` calls with `set_type_map_entry` so the fallback bare keys at 0.6 confidence are likewise deduplicated. Fixes #1501. Impact: 3 functions changed, 5 affected * docs(native): correct set_type_map_entry semantics label to highest-confidence-wins
1 parent e5ea649 commit 4a1329f

2 files changed

Lines changed: 41 additions & 17 deletions

File tree

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -958,24 +958,55 @@ pub fn extract_simple_parameters(
958958

959959
// ── Type-map helpers ───────────────────────────────────────────────────────
960960

961-
/// Record a parameter name → type binding in the type-map sink, using
962-
/// the default confidence of `0.9` shared by every Rust extractor.
963-
pub fn push_type_map_entry(
961+
/// Merge a type-map entry into the sink with highest-confidence-wins semantics,
962+
/// matching `setTypeMapEntry` in `src/extractors/helpers.ts`.
963+
///
964+
/// If the key already exists with equal-or-higher confidence the new entry is
965+
/// silently dropped; otherwise the old entry is replaced. This prevents
966+
/// duplicate entries from accumulating when the same bare key is written
967+
/// multiple times (e.g. two class expressions in one file that both define a
968+
/// field with the same name).
969+
///
970+
/// Mirrors `setTypeMapEntry` in `src/extractors/helpers.ts`.
971+
pub fn set_type_map_entry(
964972
symbols: &mut FileSymbols,
965973
name: impl Into<String>,
966974
type_name: impl Into<String>,
975+
confidence: f64,
967976
) {
968977
let name = name.into();
969978
if name.is_empty() {
970979
return;
971980
}
981+
// Scan for an existing entry with the same key.
982+
if let Some(existing) = symbols.type_map.iter_mut().find(|e| e.name == name) {
983+
if confidence > existing.confidence {
984+
existing.type_name = type_name.into();
985+
existing.confidence = confidence;
986+
}
987+
return;
988+
}
972989
symbols.type_map.push(TypeMapEntry {
973990
name,
974991
type_name: type_name.into(),
975-
confidence: 0.9,
992+
confidence,
976993
});
977994
}
978995

996+
/// Record a parameter name → type binding in the type-map sink, using
997+
/// the default confidence of `0.9` shared by every Rust extractor.
998+
///
999+
/// Delegates to [`set_type_map_entry`] so duplicate keys are deduplicated with
1000+
/// highest-confidence-wins semantics (first-write-wins at the uniform 0.9
1001+
/// confidence), matching `setTypeMapEntry` in `src/extractors/helpers.ts`.
1002+
pub fn push_type_map_entry(
1003+
symbols: &mut FileSymbols,
1004+
name: impl Into<String>,
1005+
type_name: impl Into<String>,
1006+
) {
1007+
set_type_map_entry(symbols, name, type_name, 0.9);
1008+
}
1009+
9791010
/// C-family `declaration` / `parameter_declaration` type-map matcher.
9801011
///
9811012
/// The cpp / cuda / c extractors all emit verbatim copies of the same

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

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -224,28 +224,21 @@ fn match_js_type_map(node: &Node, source: &[u8], symbols: &mut FileSymbols, _dep
224224
match enclosing_type_map_class(node, source) {
225225
Some(class_name) => {
226226
// Primary: class-scoped key prevents cross-class collision.
227-
push_type_map_entry(
227+
set_type_map_entry(
228228
symbols,
229229
format!("{}.{}", class_name, field_name),
230230
type_name.to_string(),
231+
0.9,
231232
);
232233
// Fallback bare keys at lower confidence.
233-
symbols.type_map.push(TypeMapEntry {
234-
name: field_name.clone(),
235-
type_name: type_name.to_string(),
236-
confidence: 0.6,
237-
});
238-
symbols.type_map.push(TypeMapEntry {
239-
name: format!("this.{}", field_name),
240-
type_name: type_name.to_string(),
241-
confidence: 0.6,
242-
});
234+
set_type_map_entry(symbols, field_name.clone(), type_name.to_string(), 0.6);
235+
set_type_map_entry(symbols, format!("this.{}", field_name), type_name.to_string(), 0.6);
243236
}
244237
None => {
245238
// No enclosing class declaration (e.g. class expression)
246239
// — use bare keys only at full confidence.
247-
push_type_map_entry(symbols, field_name.clone(), type_name.to_string());
248-
push_type_map_entry(symbols, format!("this.{}", field_name), type_name.to_string());
240+
set_type_map_entry(symbols, field_name.clone(), type_name.to_string(), 0.9);
241+
set_type_map_entry(symbols, format!("this.{}", field_name), type_name.to_string(), 0.9);
249242
}
250243
}
251244
}

0 commit comments

Comments
 (0)