mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-27 07:23:43 +08:00
fix(extraction): a function in an initializer is referenced once, by what the initializer declares (#2743)
PRs #693 and #1802 walk a declaration's initializer under the symbol it declares, so `const routes = { home }` references `home` from `routes`. The dispatcher's declaration-wide function-as-value scan then took the same values again for the enclosing file (or class). Flush-time dedup keys on the source, so both stayed: a second reference to the same function from the same spot. Each initializer walk now records what it walked, and the scan skips it. PR #2738 added that mechanism for component wrappers, and C#, Scala and Dart already had their own. The newly covered paths: - TS/JS module-level constants and variables, owned object literals included (#2300), and TS/JS class properties; - Python assignments, Go var/const specs, Rust const/static items; - Java fields, and Kotlin properties (walkInitializer takes the property's id, so their walk is unchanged). Mirrored in the kernel: tsjs, python, go, rustlang, java and kotlin. References no initializer walk takes are unchanged: a module-level call argument `register(fn)`, C-family tables, Rust's `static CB: fn() = handler` (the declaration's own value, which the scan still reads). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ae0fc631e0
commit
51be28d15b
@@ -530,9 +530,11 @@ impl<'t> Walker<'t> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the initializers it walked under a component wrapper, whose
|
||||
/// fn-ref candidates that walk already took (the caller's scan of the
|
||||
/// declaration skips them). Mirrors TreeSitterExtractor.extractVariable.
|
||||
/// Returns the initializers it walked under the symbol they declare — a
|
||||
/// constant's or a variable's (#693), a component wrapper's — whose fn-ref
|
||||
/// candidates that walk already took for the symbol (the caller's scan of
|
||||
/// the declaration skips them; it would take each again for the file).
|
||||
/// Mirrors TreeSitterExtractor.extractVariable.
|
||||
pub(super) fn extract_variable(&mut self, node: Node<'t>) -> Option<HashSet<usize>> {
|
||||
let mut walked: Option<HashSet<usize>> = None;
|
||||
let is_const = self.is_const_decl(node);
|
||||
@@ -619,6 +621,7 @@ impl<'t> Walker<'t> {
|
||||
// the ownedObject branch of TreeSitterExtractor.extractVariable.
|
||||
if let (Some(row), Some(obj)) = (var_row, self.owned_object_value(value)) {
|
||||
self.extract_owned_object_members(obj, row, kind, &name, true, false);
|
||||
walked.get_or_insert_with(HashSet::new).insert(obj.id());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -678,6 +681,7 @@ impl<'t> Walker<'t> {
|
||||
self.stack.push(Scope { row, kind, name: name.clone() });
|
||||
self.visit_function_body(v);
|
||||
self.stack.pop();
|
||||
walked.get_or_insert_with(HashSet::new).insert(v.id());
|
||||
}
|
||||
None => self.visit_function_body(v),
|
||||
}
|
||||
|
||||
@@ -700,12 +700,16 @@ impl<'t> Walker<'t> {
|
||||
{
|
||||
if classify_ts_class_member(node) == Member::Property {
|
||||
let prop = self.extract_property(node);
|
||||
// The initializer walked under the property took its own
|
||||
// candidates; the scan covers the rest of the field.
|
||||
let mut walked: Option<HashSet<usize>> = None;
|
||||
if let (Some((row, name)), Some(value)) = (prop, node.child_by_field_name("value")) {
|
||||
self.stack.push(Scope { row, kind: "property", name });
|
||||
self.visit_function_body(value);
|
||||
self.stack.pop();
|
||||
walked = Some(HashSet::from([value.id()]));
|
||||
}
|
||||
self.scan_fn_ref_subtree(node, 0, None);
|
||||
self.scan_fn_ref_subtree(node, 0, walked.as_ref());
|
||||
} else {
|
||||
self.extract_method(node);
|
||||
}
|
||||
@@ -719,8 +723,9 @@ impl<'t> Walker<'t> {
|
||||
} else if self.variant.is_ts() && kind == "type_alias_declaration" {
|
||||
skip_children = self.extract_type_alias(node);
|
||||
} else if is_variable_type(kind) && !self.inside_class_like() {
|
||||
// A component wrapper's initializer extract_variable walked under
|
||||
// the component captured its own candidates; the scan skips it.
|
||||
// An initializer extract_variable walked under the symbol it
|
||||
// declares (a constant's, a component wrapper's) captured its own
|
||||
// candidates; the scan skips it.
|
||||
let walked = self.extract_variable(node);
|
||||
self.scan_fn_ref_subtree(node, 0, walked.as_ref());
|
||||
skip_children = true;
|
||||
|
||||
Reference in New Issue
Block a user