mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 18:58:00 +00:00
refactor(extract): dedup C declarator-name walker into one shared helper
Addresses #463 review: the declarator-chain name resolver was copied into helpers.c, extract_unified.c, and extract_defs.c, and CBM_DECLARATOR_DEPTH_LIMIT was #defined twice -- the same triplication drift that caused #438. - Add cbm_resolve_c_declarator_name_node() to helpers.{c,h} as the single source of truth, carrying is_c_terminal_name/resolve_qualified_name with it. - Route the defs, calls, and unified extractors through it. - Hoist CBM_DECLARATOR_DEPTH_LIMIT into helpers.h; extract_defs.c's DECLARATOR_DEPTH_LIMIT now derives from it. Canonicalizes on the original extract_defs.c logic (operator/destructor aware) so defs behavior is unchanged and calls/unified now agree with it. Test: full suite green except an unrelated ASan RSS-budget check; clang-format clean. Signed-off-by: Kris Kersey <kris@kerseyfabrications.com>
This commit is contained in:
1 parent
13c3429651
commit
adc8304c57
4 files changed
+45
-108
No files matched your search
@@ -23,7 +23,8 @@
|
||||
// Tree traversal limits.
|
||||
enum {
|
||||
TEMPLATE_DEPTH_LIMIT = 4,
|
||||
DECLARATOR_DEPTH_LIMIT = 8,
|
||||
DECLARATOR_DEPTH_LIMIT = CBM_DECLARATOR_DEPTH_LIMIT, // shared define in helpers.h
|
||||
|
||||
EXPORT_ANCESTOR_DEPTH = 4,
|
||||
DECORATOR_SCAN_LIMIT = 3,
|
||||
C_RETURN_WALK_DEPTH = 5,
|
||||
@@ -457,27 +458,6 @@ static TSNode resolve_func_name_fp(TSNode node, CBMLanguage lang, const char *ki
|
||||
return null_node;
|
||||
}
|
||||
|
||||
// Check if a node type is a terminal C declarator name.
|
||||
static bool is_c_terminal_name(const char *dk) {
|
||||
return strcmp(dk, "identifier") == 0 || strcmp(dk, "field_identifier") == 0 ||
|
||||
strcmp(dk, "operator_name") == 0 || strcmp(dk, "operator_cast") == 0 ||
|
||||
strcmp(dk, "destructor_name") == 0;
|
||||
}
|
||||
|
||||
// Resolve name from a C++ qualified_identifier/scoped_identifier.
|
||||
static TSNode resolve_qualified_name(TSNode decl) {
|
||||
static const char *name_kinds[] = {"operator_name", "operator_cast", "destructor_name",
|
||||
"identifier", "field_identifier", NULL};
|
||||
for (const char **k = name_kinds; *k; k++) {
|
||||
TSNode found = cbm_find_child_by_kind(decl, *k);
|
||||
if (!ts_node_is_null(found)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
TSNode null_node = {0};
|
||||
return null_node;
|
||||
}
|
||||
|
||||
// C++/CUDA: out-of-line method definitions name the function with a qualified
|
||||
// declarator (`Foo::bar`, or `ns::Foo::bar`). Return the immediate enclosing
|
||||
// class name (the scope segment directly left of the function name, e.g. "Foo"),
|
||||
@@ -528,30 +508,6 @@ static char *cpp_out_of_line_parent_class(CBMArena *a, TSNode node, const char *
|
||||
return (text && text[0]) ? text : NULL;
|
||||
}
|
||||
|
||||
// Resolve function name from C/C++/CUDA/GLSL declarator chain.
|
||||
static TSNode resolve_c_declarator_name(TSNode node) {
|
||||
TSNode decl = ts_node_child_by_field_name(node, TS_FIELD("declarator"));
|
||||
for (int depth = 0; depth < DECLARATOR_DEPTH_LIMIT && !ts_node_is_null(decl); depth++) {
|
||||
const char *dk = ts_node_type(decl);
|
||||
if (is_c_terminal_name(dk)) {
|
||||
return decl;
|
||||
}
|
||||
if (strcmp(dk, "qualified_identifier") == 0 || strcmp(dk, "scoped_identifier") == 0) {
|
||||
return resolve_qualified_name(decl);
|
||||
}
|
||||
TSNode inner = ts_node_child_by_field_name(decl, TS_FIELD("declarator"));
|
||||
if (ts_node_is_null(inner) && ts_node_named_child_count(decl) > 0) {
|
||||
inner = ts_node_named_child(decl, 0);
|
||||
}
|
||||
if (ts_node_is_null(inner)) {
|
||||
break;
|
||||
}
|
||||
decl = inner;
|
||||
}
|
||||
TSNode null_node = {0};
|
||||
return null_node;
|
||||
}
|
||||
|
||||
// R: resolve function_definition name from parent binary_operator lhs.
|
||||
static TSNode resolve_r_func_name(TSNode node) {
|
||||
TSNode parent = ts_node_parent(node);
|
||||
@@ -675,7 +631,7 @@ static TSNode resolve_func_name_c_family(TSNode *node_ptr, CBMLanguage lang, con
|
||||
lang == CBM_LANG_GLSL || lang == CBM_LANG_HLSL || lang == CBM_LANG_ISPC ||
|
||||
lang == CBM_LANG_SLANG) &&
|
||||
strcmp(kind, "function_definition") == 0) {
|
||||
return resolve_c_declarator_name(*node_ptr);
|
||||
return cbm_resolve_c_declarator_name_node(*node_ptr);
|
||||
}
|
||||
TSNode null_node = {0};
|
||||
return null_node;
|
||||
|
||||
@@ -87,44 +87,6 @@ static const char *compute_wolfram_func_qn(CBMExtractCtx *ctx, TSNode node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* C/C++/CUDA/GLSL: function_definition has no `name` field — the name is nested
|
||||
* in the declarator chain. Descend the `declarator` field to the innermost name
|
||||
* node. Without this, the enclosing-function scope for calls made inside a C
|
||||
* function resolves to NULL and the call is attributed to the module rather than
|
||||
* the function (issue #438). Mirrors resolve_c_declarator_name() in extract_defs.c. */
|
||||
#ifndef CBM_DECLARATOR_DEPTH_LIMIT
|
||||
#define CBM_DECLARATOR_DEPTH_LIMIT 8 /* matches DECLARATOR_DEPTH_LIMIT in extract_defs.c */
|
||||
#endif
|
||||
static TSNode resolve_c_declarator_name_node(TSNode node) {
|
||||
TSNode decl = ts_node_child_by_field_name(node, TS_FIELD("declarator"));
|
||||
for (int depth = 0; depth < CBM_DECLARATOR_DEPTH_LIMIT && !ts_node_is_null(decl); depth++) {
|
||||
const char *dk = ts_node_type(decl);
|
||||
if (strcmp(dk, "identifier") == 0 || strcmp(dk, "field_identifier") == 0 ||
|
||||
strcmp(dk, "type_identifier") == 0 || strcmp(dk, "destructor_name") == 0 ||
|
||||
strcmp(dk, "operator_name") == 0 || strcmp(dk, "operator_cast") == 0) {
|
||||
return decl;
|
||||
}
|
||||
if (strcmp(dk, "qualified_identifier") == 0 || strcmp(dk, "scoped_identifier") == 0) {
|
||||
TSNode nm = ts_node_child_by_field_name(decl, TS_FIELD("name"));
|
||||
if (!ts_node_is_null(nm)) {
|
||||
decl = nm;
|
||||
continue;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
TSNode inner = ts_node_child_by_field_name(decl, TS_FIELD("declarator"));
|
||||
if (ts_node_is_null(inner) && ts_node_named_child_count(decl) > 0) {
|
||||
inner = ts_node_named_child(decl, 0);
|
||||
}
|
||||
if (ts_node_is_null(inner)) {
|
||||
break;
|
||||
}
|
||||
decl = inner;
|
||||
}
|
||||
TSNode null_node = {0};
|
||||
return null_node;
|
||||
}
|
||||
|
||||
// Resolve the name node for a function, handling arrow functions.
|
||||
static TSNode resolve_func_name_node(TSNode node) {
|
||||
TSNode name_node = ts_node_child_by_field_name(node, TS_FIELD("name"));
|
||||
@@ -141,7 +103,7 @@ static TSNode resolve_func_name_node(TSNode node) {
|
||||
}
|
||||
/* C/C++/CUDA/GLSL: function_definition name lives in the declarator chain. */
|
||||
if (ts_node_is_null(name_node) && strcmp(ts_node_type(node), "function_definition") == 0) {
|
||||
name_node = resolve_c_declarator_name_node(node);
|
||||
name_node = cbm_resolve_c_declarator_name_node(node);
|
||||
}
|
||||
return name_node;
|
||||
}
|
||||
|
||||
+27
-22
@@ -717,33 +717,38 @@ TSNode cbm_find_enclosing_func(TSNode node, CBMLanguage lang) {
|
||||
return null_node;
|
||||
}
|
||||
|
||||
// Get the name of a function node (basic: try "name" field)
|
||||
// C/C++/CUDA/GLSL: function_definition has no "name" field — the function name is
|
||||
// nested in the declarator chain (pointer/function/parenthesized/array
|
||||
// declarators wrap it). Descend the `declarator` field to the innermost name
|
||||
// node. Without this, calls made inside C functions are attributed to the module
|
||||
// rather than the enclosing function (issue #438). Mirrors resolve_c_declarator_name()
|
||||
// in extract_defs.c.
|
||||
#ifndef CBM_DECLARATOR_DEPTH_LIMIT
|
||||
#define CBM_DECLARATOR_DEPTH_LIMIT 8 /* matches DECLARATOR_DEPTH_LIMIT in extract_defs.c */
|
||||
#endif
|
||||
static TSNode c_declarator_name_node(TSNode func_node) {
|
||||
// Check if a node type is a terminal C declarator name.
|
||||
static bool is_c_terminal_name(const char *dk) {
|
||||
return strcmp(dk, "identifier") == 0 || strcmp(dk, "field_identifier") == 0 ||
|
||||
strcmp(dk, "operator_name") == 0 || strcmp(dk, "operator_cast") == 0 ||
|
||||
strcmp(dk, "destructor_name") == 0;
|
||||
}
|
||||
|
||||
// Resolve name from a C++ qualified_identifier/scoped_identifier.
|
||||
static TSNode resolve_qualified_name(TSNode decl) {
|
||||
static const char *name_kinds[] = {"operator_name", "operator_cast", "destructor_name",
|
||||
"identifier", "field_identifier", NULL};
|
||||
for (const char **k = name_kinds; *k; k++) {
|
||||
TSNode found = cbm_find_child_by_kind(decl, *k);
|
||||
if (!ts_node_is_null(found)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
TSNode null_node = {0};
|
||||
return null_node;
|
||||
}
|
||||
|
||||
// Resolve function name from C/C++/CUDA/GLSL declarator chain. Shared canonical
|
||||
// implementation — see the header for the full rationale (#438).
|
||||
TSNode cbm_resolve_c_declarator_name_node(TSNode func_node) {
|
||||
TSNode decl = ts_node_child_by_field_name(func_node, TS_FIELD("declarator"));
|
||||
for (int depth = 0; depth < CBM_DECLARATOR_DEPTH_LIMIT && !ts_node_is_null(decl); depth++) {
|
||||
const char *dk = ts_node_type(decl);
|
||||
if (strcmp(dk, "identifier") == 0 || strcmp(dk, "field_identifier") == 0 ||
|
||||
strcmp(dk, "type_identifier") == 0 || strcmp(dk, "destructor_name") == 0 ||
|
||||
strcmp(dk, "operator_name") == 0 || strcmp(dk, "operator_cast") == 0) {
|
||||
if (is_c_terminal_name(dk)) {
|
||||
return decl;
|
||||
}
|
||||
if (strcmp(dk, "qualified_identifier") == 0 || strcmp(dk, "scoped_identifier") == 0) {
|
||||
// out-of-line method def (Foo::bar): take the rightmost name segment
|
||||
TSNode nm = ts_node_child_by_field_name(decl, TS_FIELD("name"));
|
||||
if (!ts_node_is_null(nm)) {
|
||||
decl = nm;
|
||||
continue;
|
||||
}
|
||||
return decl;
|
||||
return resolve_qualified_name(decl);
|
||||
}
|
||||
TSNode inner = ts_node_child_by_field_name(decl, TS_FIELD("declarator"));
|
||||
if (ts_node_is_null(inner) && ts_node_named_child_count(decl) > 0) {
|
||||
@@ -794,7 +799,7 @@ static const char *func_node_name(CBMArena *a, TSNode func_node, const char *sou
|
||||
}
|
||||
// C/C++/CUDA/GLSL: function_definition carries its name in the declarator chain.
|
||||
if (strcmp(ts_node_type(func_node), "function_definition") == 0) {
|
||||
TSNode dn = c_declarator_name_node(func_node);
|
||||
TSNode dn = cbm_resolve_c_declarator_name_node(func_node);
|
||||
if (!ts_node_is_null(dn)) {
|
||||
return cbm_node_text(a, dn, source);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,20 @@ const char *cbm_enclosing_func_qn(CBMArena *a, TSNode node, CBMLanguage lang, co
|
||||
// Cached version: uses ctx->ef_cache to avoid repeated parent-chain walks.
|
||||
const char *cbm_enclosing_func_qn_cached(CBMExtractCtx *ctx, TSNode node);
|
||||
|
||||
// Max declarator-chain descent depth for C/C++/CUDA/GLSL function-name
|
||||
// resolution. Single source of truth — extract_defs.c's DECLARATOR_DEPTH_LIMIT
|
||||
// is derived from this so the three extractors cannot drift.
|
||||
#define CBM_DECLARATOR_DEPTH_LIMIT 8
|
||||
|
||||
// Resolve the function-name node for a C/C++/CUDA/GLSL `function_definition`.
|
||||
// Such nodes have no `name` field — the name is nested in the declarator chain
|
||||
// (pointer/function/parenthesized/array declarators wrap it; out-of-line method
|
||||
// definitions name it with a qualified_identifier). Descends the `declarator`
|
||||
// field to the innermost name node and returns it, or a null node if none is
|
||||
// found. Shared by the defs, calls, and unified extractors so all three agree on
|
||||
// enclosing-function attribution — drift between private copies caused #438.
|
||||
TSNode cbm_resolve_c_declarator_name_node(TSNode func_node);
|
||||
|
||||
// Find a child node by kind string.
|
||||
TSNode cbm_find_child_by_kind(TSNode parent, const char *kind);
|
||||
|
||||
|
||||
Reference in new issue
Block a user