mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-18 22:02:49 +08:00
fix(kernel): a Go value like wm.new or raft.None keeps its function ref (#2401)
* fix(kernel): a Go value like `wm.new` or `raft.None` keeps its function ref
The kernel's Go fn-ref capture checked a selector value's field name
against the name stoplist, so `raft.None`, `compression.None`, cgo's
`C.NULL` and a method value like `sync.Pool{New: wm.new}` were dropped.
The wasm extractor, the reference, applies NAME_STOPLIST to the
normalized name (`raft.None`), which the stoplist never matches. It also
builds that name from the operand and the field, so a line break or
comment beside the dot keeps the candidate; the kernel validated the
selector's whole source text and dropped it.
Build the name from operand and field as normalizeSpecial does, and drop
the field-name check. No other walker has the pattern: each applies the
stoplist to the same name as its TS spec.
kernel-parity.mjs --lang go: prometheus 202 -> 0 function_ref diffs,
etcd 6 -> 0, golang/go 35 -> 0, kapacitor 2 -> 0, plus 0 on gin, grpc-go,
hugo, caddy and go-ethereum. Indexed with both kernels, edges are
unchanged on prometheus, etcd, gin and hugo; kapacitor gains the one
missing edge, NewExecutor -> workerMaker::new.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(kernel): note that a comment before the dot keeps a Go selector value too
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+13
-11
@@ -1028,18 +1028,20 @@ impl<'t> Walker<'t> {
|
||||
row: p.row,
|
||||
});
|
||||
}
|
||||
// #1820: preserve the receiver of a method value.
|
||||
// #1820: preserve the receiver of a method value. The name is
|
||||
// rebuilt from operand and field, as normalizeSpecial does, so a
|
||||
// comment or line break beside the dot keeps the candidate.
|
||||
// NAME_STOPLIST applies to the whole name and holds no dotted
|
||||
// word, so it never drops one: `raft.None` is a candidate even
|
||||
// though a bare `None` is not.
|
||||
"selector_expression" => {
|
||||
let field = v
|
||||
.child_by_field_name("field")
|
||||
.or_else(|| v.named_child(v.named_child_count().saturating_sub(1)));
|
||||
let Some(field) = field else { return };
|
||||
let name = self.text(field);
|
||||
if name.is_empty() || is_stoplisted(name) {
|
||||
let (Some(operand), Some(field)) =
|
||||
(v.child_by_field_name("operand"), v.child_by_field_name("field"))
|
||||
else {
|
||||
return;
|
||||
}
|
||||
let value = self.text(v);
|
||||
if !value.split('.').all(|part| {
|
||||
};
|
||||
let name = format!("{}.{}", self.text(operand), self.text(field));
|
||||
if !name.split('.').all(|part| {
|
||||
!part.is_empty() && part.chars().enumerate().all(|(i, c)| {
|
||||
c == '_' || c.is_ascii_alphabetic() || (i > 0 && c.is_ascii_digit())
|
||||
})
|
||||
@@ -1047,7 +1049,7 @@ impl<'t> Walker<'t> {
|
||||
let p = field.start_position();
|
||||
self.fn_ref_cands.push(Cand {
|
||||
from,
|
||||
name: value.to_string(),
|
||||
name,
|
||||
line: p.row as u32 + 1,
|
||||
column_byte: field.start_byte(),
|
||||
row: p.row,
|
||||
|
||||
Reference in New Issue
Block a user