mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-11 09:25:35 +08:00
tree-sitter's ts_node_child(node, i) is O(i) — it walks the child iterator from the first child on every call — so the common 'for (i=0; i<count; i++) ts_node_child(node, i)' idiom is O(n^2) over a node's children. On a file whose top level is very wide (e.g. a 580k-line fixture parsed as hundreds of thousands of sibling comment nodes) this made extraction run for over an hour. Add ts_nstack_push_children(), which enumerates a node's children in a single O(n) cursor pass, and use it in the whole-tree DFS walkers (calls, channels, env-accesses, imports, type-assigns). Convert the module-level variable walk to a cursor too, and add cbm_is_module_level_p() so callers that already hold the parent node skip the O(n) ts_node_parent() rescan. Indexing microsoft/TypeScript drops from ~5100s to ~50s with identical graph output.
66 lines
2.7 KiB
C
66 lines
2.7 KiB
C
#ifndef CBM_HELPERS_H
|
|
#define CBM_HELPERS_H
|
|
|
|
#include "cbm.h"
|
|
|
|
// Extract text of a node from source. Returns arena-allocated string.
|
|
char *cbm_node_text(CBMArena *a, TSNode node, const char *source);
|
|
|
|
// Check if a string is a language keyword (should be skipped as callee/usage).
|
|
bool cbm_is_keyword(const char *name, CBMLanguage lang);
|
|
|
|
// Classify a string literal as URL, config, or neither.
|
|
// Returns CBM_STRREF_URL (0), CBM_STRREF_CONFIG (1), or -1 for neither.
|
|
int cbm_classify_string(const char *str, int len);
|
|
|
|
// Check if a name is exported per language convention.
|
|
bool cbm_is_exported(const char *name, CBMLanguage lang);
|
|
|
|
// Check if a file is a test file based on path and language.
|
|
bool cbm_is_test_file(const char *rel_path, CBMLanguage lang);
|
|
|
|
// Find the innermost enclosing function node by walking parent chain.
|
|
// Returns a null node if none found.
|
|
TSNode cbm_find_enclosing_func(TSNode node, CBMLanguage lang);
|
|
|
|
// Get the QN of an enclosing function, or module_qn if none.
|
|
const char *cbm_enclosing_func_qn(CBMArena *a, TSNode node, CBMLanguage lang, const char *source,
|
|
const char *project, const char *rel_path, const char *module_qn);
|
|
|
|
// Cached version: uses ctx->ef_cache to avoid repeated parent-chain walks.
|
|
const char *cbm_enclosing_func_qn_cached(CBMExtractCtx *ctx, TSNode node);
|
|
|
|
// Find a child node by kind string.
|
|
TSNode cbm_find_child_by_kind(TSNode parent, const char *kind);
|
|
|
|
// Check if node kind matches a set of types (NULL-terminated array of strings).
|
|
bool cbm_kind_in_set(TSNode node, const char **types);
|
|
|
|
// Check if node has an ancestor of the given kind, within max_depth levels.
|
|
bool cbm_has_ancestor_kind(TSNode node, const char *kind, int max_depth);
|
|
|
|
// Count nodes of given kinds in subtree (for complexity metric).
|
|
int cbm_count_branching(TSNode node, const char **branching_types);
|
|
|
|
// Is this a module-level node? (not nested inside function/class body)
|
|
bool cbm_is_module_level(TSNode node, CBMLanguage lang);
|
|
|
|
// Same check, but the node's PARENT is supplied directly — avoids the
|
|
// O(n) ts_node_parent rescan. Use at call sites iterating a known
|
|
// parent's children (the common case). `parent` is the parent of the
|
|
// node being classified.
|
|
bool cbm_is_module_level_p(TSNode parent, CBMLanguage lang);
|
|
|
|
// --- FQN computation ---
|
|
|
|
// Compute qualified name: project.rel_path_parts.name
|
|
char *cbm_fqn_compute(CBMArena *a, const char *project, const char *rel_path, const char *name);
|
|
|
|
// Module QN (file without name): project.rel_path_parts
|
|
char *cbm_fqn_module(CBMArena *a, const char *project, const char *rel_path);
|
|
|
|
// Folder QN: project.dir_parts
|
|
char *cbm_fqn_folder(CBMArena *a, const char *project, const char *rel_dir);
|
|
|
|
#endif // CBM_HELPERS_H
|