MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / cbm_compute_complexity

Function cbm_compute_complexity

internal/cbm/helpers.c:599–669  ·  view source on GitHub ↗

One traversal computing cyclomatic + cognitive + loop-nesting + access-depth metrics. Each frame carries its branch-, loop- and access-nesting depth so every metric (cognitive Campbell penalty, loop_depth polynomial-degree proxy, max chained access depth) is produced in a single walk.

Source from the content-addressed store, hash-verified

597// every metric (cognitive Campbell penalty, loop_depth polynomial-degree proxy,
598// max chained access depth) is produced in a single walk.
599void cbm_compute_complexity(TSNode node, const char **branching_types, cbm_complexity_t *out) {
600 out->cyclomatic = 0;
601 out->cognitive = 0;
602 out->loop_count = 0;
603 out->loop_depth = 0;
604 out->max_access_depth = 0;
605 if (!branching_types) {
606 return;
607 }
608 struct cx_frame {
609 TSNode node;
610 int bdepth;
611 int ldepth;
612 int adepth;
613 };
614 struct cx_frame stack[BRANCHING_STACK_CAP];
615 int top = 0;
616 stack[top].node = node;
617 stack[top].bdepth = 0;
618 stack[top].ldepth = 0;
619 stack[top].adepth = 0;
620 top++;
621 while (top > 0) {
622 struct cx_frame f = stack[--top];
623 const char *kind = ts_node_type(f.node);
624 bool is_branch = false;
625 for (const char **t = branching_types; *t; t++) {
626 if (strcmp(kind, *t) == 0) {
627 is_branch = true;
628 break;
629 }
630 }
631 int child_b = f.bdepth;
632 int child_l = f.ldepth;
633 /* Chained member/subscript access: a.b.c.d nests as access(access(access(a))),
634 * so each consecutive access node deepens the chain; non-access nodes reset it. */
635 int child_a = 0;
636 if (ts_node_is_named(f.node) && is_member_access_node(kind)) {
637 child_a = f.adepth + 1;
638 if (child_a > out->max_access_depth) {
639 out->max_access_depth = child_a;
640 }
641 }
642 if (is_branch) {
643 out->cyclomatic++;
644 out->cognitive += 1 + f.bdepth; /* +1 plus nesting penalty (Campbell) */
645 child_b = f.bdepth + 1;
646 }
647 /* Only *named* nodes count as loops. In many grammars (Go, C, …) the
648 * loop's `for`/`while` keyword is an anonymous child token whose node
649 * type literally equals "for"/"while"; without this guard each loop is
650 * counted twice and nesting depth is inflated by one. Named loop nodes
651 * (e.g. Ruby's `while`/`until`/`for`) still match correctly. */
652 if (ts_node_is_named(f.node) && cbm_is_loop_node_type(kind)) {
653 out->loop_count++;
654 int d = f.ldepth + 1;
655 if (d > out->loop_depth) {
656 out->loop_depth = d;

Callers 1

set_def_complexityFunction · 0.85

Calls 2

is_member_access_nodeFunction · 0.85
cbm_is_loop_node_typeFunction · 0.85

Tested by

no test coverage detected