| 5315 | } |
| 5316 | |
| 5317 | static int arch_clusters(cbm_store_t *s, const char *project, const char *path, |
| 5318 | cbm_architecture_info_t *out) { |
| 5319 | char norm[CBM_SZ_512]; |
| 5320 | char like[CBM_SZ_512]; |
| 5321 | bool scoped = arch_path_prepare(path, norm, sizeof(norm), like, sizeof(like)); |
| 5322 | char nsqlbuf[ST_SQL_BUF]; |
| 5323 | const char *nbase = "SELECT id, name, qualified_name, file_path FROM nodes " |
| 5324 | "WHERE project=?1 AND label IN ('Function','Method','Class')"; |
| 5325 | if (scoped) { |
| 5326 | snprintf(nsqlbuf, sizeof(nsqlbuf), "%s%s ORDER BY id LIMIT ?4", nbase, |
| 5327 | arch_path_scope_sql()); |
| 5328 | } else { |
| 5329 | snprintf(nsqlbuf, sizeof(nsqlbuf), "%s ORDER BY id LIMIT ?2", nbase); |
| 5330 | } |
| 5331 | sqlite3_stmt *st = NULL; |
| 5332 | if (sqlite3_prepare_v2(s->db, nsqlbuf, CBM_NOT_FOUND, &st, NULL) != SQLITE_OK) { |
| 5333 | return CBM_STORE_OK; /* clusters are best-effort */ |
| 5334 | } |
| 5335 | bind_text(st, SKIP_ONE, project); |
| 5336 | if (scoped) { |
| 5337 | arch_bind_path_scope(st, ST_COL_2, ST_COL_3, norm, like); |
| 5338 | sqlite3_bind_int(st, ST_COL_4, CBM_CLUSTER_NODE_CAP); |
| 5339 | } else { |
| 5340 | sqlite3_bind_int(st, CBM_SZ_2, CBM_CLUSTER_NODE_CAP); |
| 5341 | } |
| 5342 | int cap = ST_INIT_CAP_8; |
| 5343 | int n = 0; |
| 5344 | int64_t *ids = malloc((size_t)cap * sizeof(int64_t)); |
| 5345 | const char **names = malloc((size_t)cap * sizeof(char *)); |
| 5346 | const char **qns = malloc((size_t)cap * sizeof(char *)); |
| 5347 | while (sqlite3_step(st) == SQLITE_ROW) { |
| 5348 | if (n >= cap) { |
| 5349 | cap *= ST_GROWTH; |
| 5350 | ids = safe_realloc(ids, (size_t)cap * sizeof(int64_t)); |
| 5351 | names = safe_realloc(names, (size_t)cap * sizeof(char *)); |
| 5352 | qns = safe_realloc(qns, (size_t)cap * sizeof(char *)); |
| 5353 | } |
| 5354 | ids[n] = sqlite3_column_int64(st, 0); |
| 5355 | names[n] = heap_strdup((const char *)sqlite3_column_text(st, SKIP_ONE)); |
| 5356 | qns[n] = heap_strdup((const char *)sqlite3_column_text(st, CBM_SZ_2)); |
| 5357 | n++; |
| 5358 | } |
| 5359 | sqlite3_finalize(st); |
| 5360 | if (n < CBM_CLUSTER_MIN_MEMBERS) { |
| 5361 | for (int i = 0; i < n; i++) { |
| 5362 | safe_str_free(&names[i]); |
| 5363 | safe_str_free(&qns[i]); |
| 5364 | } |
| 5365 | free(ids); |
| 5366 | free(names); |
| 5367 | free(qns); |
| 5368 | return CBM_STORE_OK; |
| 5369 | } |
| 5370 | |
| 5371 | /* 2. Load CALLS edges with both endpoints in the node set (store indices). */ |
| 5372 | cbm_louvain_edge_t *edges = malloc((size_t)n * sizeof(cbm_louvain_edge_t)); |
| 5373 | int *esrc = malloc((size_t)n * sizeof(int)); |
| 5374 | int *edst = malloc((size_t)n * sizeof(int)); |
no test coverage detected