Skip to content

Commit 1e9971e

Browse files
committed
fix(extractors): mirror Rust handle_record_decl field-name lookup in JS (#1103)
1 parent ee561e6 commit 1e9971e

2 files changed

Lines changed: 17 additions & 8 deletions

File tree

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,19 @@ fn extract_params(clause_node: &Node, source: &[u8]) -> Vec<Definition> {
209209

210210
fn handle_define(node: &Node, source: &[u8], symbols: &mut FileSymbols) {
211211
// pp_define: -define(NAME, value). Name may be in `var`, `atom`, or `macro_lhs`.
212-
// For parametric macros, the grammar wraps the name in a `macro_lhs(name, args)`
213-
// node. Inside `macro_lhs` the name comes first, followed by `(`, the argument
214-
// `var` children, and `)`. We must therefore try `atom` (lowercase macros,
215-
// e.g. `-define(foo(X), X+1)`) before `var` (uppercase macros, e.g.
216-
// `-define(FOO(X), X+1)`) — otherwise `find_child(.., "var")` skips the
217-
// leading atom and lands on the first argument variable, mislabeling the
218-
// definition with the argument name instead of the macro name.
212+
// For non-parametric macros the grammar exposes the name directly as either
213+
// a `var` (uppercase, e.g. `-define(FOO, 1)`) or an `atom` (lowercase,
214+
// e.g. `-define(foo, 1)`) child of `pp_define`. We check `var` first
215+
// because uppercase macros are the common case.
216+
//
217+
// For parametric macros the grammar wraps the name in a
218+
// `macro_lhs(name, args)` node. Inside `macro_lhs` the name comes first,
219+
// followed by `(`, the argument `var` children, and `)`. We must therefore
220+
// try `atom` (lowercase, e.g. `-define(foo(X), X+1)`) before `var`
221+
// (uppercase, e.g. `-define(FOO(X), X+1)`) inside `macro_lhs` —
222+
// otherwise `find_child(.., "var")` skips the leading atom and lands on
223+
// the first argument variable, mislabeling the definition with the
224+
// argument name instead of the macro name.
219225
let name = if let Some(v) = find_child(node, "var") {
220226
node_text(&v, source).to_string()
221227
} else if let Some(a) = find_child(node, "atom") {

src/extractors/erlang.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ function handleModuleAttr(node: TreeSitterNode, ctx: ExtractorOutput): void {
8686

8787
function handleRecordDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
8888
// record_decl: - record ( atom , { record_field, ... } ) .
89-
const nameNode = findChild(node, 'atom');
89+
// Prefer the named `name` field exposed by tree-sitter-erlang; fall back to
90+
// the first atom child for grammar versions that don't expose it. Mirrors
91+
// the Rust `handle_record_decl` defensive pattern.
92+
const nameNode = node.childForFieldName('name') ?? findChild(node, 'atom');
9093
if (!nameNode) return;
9194

9295
const children: SubDeclaration[] = [];

0 commit comments

Comments
 (0)