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

Function cbm_compute_complexity

internal/cbm/helpers.c:586–656  ·  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

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