Skip to content

Commit b523116

Browse files
committed
Achieve zero clang-tidy errors at CC<=25 threshold
Split all remaining pipeline functions. Extract 40+ helpers. Add lint-no-suppress quality gate. Add clang-tidy to lint.sh. Zero NOLINTNEXTLINE, zero clang-tidy errors, 2741 tests pass.
1 parent 6e4ca93 commit b523116

File tree

8 files changed

+1450
-1544
lines changed

8 files changed

+1450
-1544
lines changed

Makefile.cbm

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,21 @@ lint-format:
524524
@echo "=== clang-format ==="
525525
@$(CLANG_FORMAT) --dry-run --Werror $(LINT_SRCS) $(LINT_HDRS)
526526

527+
# Ban NOLINTNEXTLINE in our code (vendored code exempt)
528+
lint-no-suppress:
529+
@echo "=== NOLINTNEXTLINE check ==="
530+
@if grep -rn 'NOLINTNEXTLINE\|NOLINTBEGIN\|NOLINTEND' src/ internal/cbm/*.c 2>/dev/null | grep -v vendored; then \
531+
echo "ERROR: NOLINTNEXTLINE/NOLINTBEGIN/NOLINTEND found in source code."; \
532+
echo "Fix the underlying issue instead of suppressing the linter."; \
533+
exit 1; \
534+
fi
535+
527536
# All linters (run with make -j3 lint for parallel execution)
528-
lint: lint-tidy lint-cppcheck lint-format
537+
lint: lint-tidy lint-cppcheck lint-format lint-no-suppress
529538
@echo "=== All linters passed ==="
530539

531540
# CI linters (no clang-tidy — platform-dependent, enforced locally via pre-commit)
532-
lint-ci: lint-cppcheck lint-format
541+
lint-ci: lint-cppcheck lint-format lint-no-suppress
533542
@echo "=== CI linters passed ==="
534543

535544
# ── Security audit (6 layers) ────────────────────────────────────

internal/cbm/extract_imports.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,8 @@ static void emit_py_import_from_name(CBMExtractCtx *ctx, TSNode child, const cha
186186
static void process_py_import_from(CBMExtractCtx *ctx, TSNode node) {
187187
CBMArena *a = ctx->arena;
188188
TSNode module_node = resolve_py_module_node(node);
189-
// NOLINTBEGIN(readability-implicit-bool-conversion)
190189
char *mod_path =
191190
ts_node_is_null(module_node) ? NULL : cbm_node_text(a, module_node, ctx->source);
192-
// NOLINTEND(readability-implicit-bool-conversion)
193191

194192
uint32_t nc = ts_node_child_count(node);
195193
for (uint32_t j = 0; j < nc; j++) {

src/pipeline/pass_calls.c

Lines changed: 278 additions & 273 deletions
Large diffs are not rendered by default.

src/pipeline/pass_definitions.c

Lines changed: 90 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -65,60 +65,53 @@ static const char *itoa_log(int val) {
6565
/* Append a JSON-escaped string value to buf at position *pos.
6666
* Writes: ,"key":"escaped_value"
6767
* Handles: \, ", \n, \r, \t */
68-
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
68+
static int def_json_escape_char(char *buf, size_t avail, char ch) {
69+
char esc = 0;
70+
switch (ch) {
71+
case '"':
72+
esc = '"';
73+
break;
74+
case '\\':
75+
esc = '\\';
76+
break;
77+
case '\n':
78+
esc = 'n';
79+
break;
80+
case '\r':
81+
esc = 'r';
82+
break;
83+
case '\t':
84+
esc = 't';
85+
break;
86+
default:
87+
if (avail >= 1) {
88+
buf[0] = ch;
89+
}
90+
return 1;
91+
}
92+
if (avail >= 2) {
93+
buf[0] = '\\';
94+
buf[1] = esc;
95+
}
96+
return 2;
97+
}
98+
6999
static void append_json_string(char *buf, size_t bufsize, size_t *pos, const char *key,
70100
const char *val) {
71-
if (!val || !val[0]) {
101+
if (!val || val[0] == '\0') {
72102
return;
73103
}
74104
if (*pos >= bufsize - 10) {
75105
return;
76106
}
77-
78107
size_t p = *pos;
79-
/* ,\"key\":\" */
80108
int w = snprintf(buf + p, bufsize - p, ",\"%s\":\"", key);
81109
if (w <= 0 || (size_t)w >= bufsize - p) {
82110
return;
83111
}
84112
p += (size_t)w;
85-
86113
for (const char *s = val; *s && p < bufsize - 3; s++) {
87-
switch (*s) {
88-
case '"':
89-
buf[p++] = '\\';
90-
if (p < bufsize - 2) {
91-
buf[p++] = '"';
92-
}
93-
break;
94-
case '\\':
95-
buf[p++] = '\\';
96-
if (p < bufsize - 2) {
97-
buf[p++] = '\\';
98-
}
99-
break;
100-
case '\n':
101-
buf[p++] = '\\';
102-
if (p < bufsize - 2) {
103-
buf[p++] = 'n';
104-
}
105-
break;
106-
case '\r':
107-
buf[p++] = '\\';
108-
if (p < bufsize - 2) {
109-
buf[p++] = 'r';
110-
}
111-
break;
112-
case '\t':
113-
buf[p++] = '\\';
114-
if (p < bufsize - 2) {
115-
buf[p++] = 't';
116-
}
117-
break;
118-
default:
119-
buf[p++] = *s;
120-
break;
121-
}
114+
p += (size_t)def_json_escape_char(buf + p, bufsize - p - 2, *s);
122115
}
123116
if (p < bufsize - 1) {
124117
buf[p++] = '"';
@@ -196,7 +189,61 @@ static void build_def_props(char *buf, size_t bufsize, const CBMDefinition *def)
196189
}
197190
}
198191

199-
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
192+
/* Process one definition: create node, register, DEFINES + DEFINES_METHOD edges. */
193+
static void process_def(cbm_pipeline_ctx_t *ctx, const CBMDefinition *def, const char *rel) {
194+
if (!def->qualified_name || !def->name) {
195+
return;
196+
}
197+
char props[2048];
198+
build_def_props(props, sizeof(props), def);
199+
int64_t node_id = cbm_gbuf_upsert_node(
200+
ctx->gbuf, def->label ? def->label : "Function", def->name, def->qualified_name,
201+
def->file_path ? def->file_path : rel, (int)def->start_line, (int)def->end_line, props);
202+
if (node_id > 0 && def->label &&
203+
(strcmp(def->label, "Function") == 0 || strcmp(def->label, "Method") == 0 ||
204+
strcmp(def->label, "Class") == 0)) {
205+
cbm_registry_add(ctx->registry, def->name, def->qualified_name, def->label);
206+
}
207+
char *file_qn = cbm_pipeline_fqn_compute(ctx->project_name, rel, "__file__");
208+
const cbm_gbuf_node_t *file_node = cbm_gbuf_find_by_qn(ctx->gbuf, file_qn);
209+
if (file_node && node_id > 0) {
210+
cbm_gbuf_insert_edge(ctx->gbuf, file_node->id, node_id, "DEFINES", "{}");
211+
}
212+
free(file_qn);
213+
if (def->parent_class && def->label && strcmp(def->label, "Method") == 0) {
214+
const cbm_gbuf_node_t *parent = cbm_gbuf_find_by_qn(ctx->gbuf, def->parent_class);
215+
if (parent && node_id > 0) {
216+
cbm_gbuf_insert_edge(ctx->gbuf, parent->id, node_id, "DEFINES_METHOD", "{}");
217+
}
218+
}
219+
}
220+
221+
/* Create IMPORTS edges for one file's imports. */
222+
static int create_import_edges_for_file(cbm_pipeline_ctx_t *ctx, const CBMFileResult *result,
223+
const char *rel) {
224+
int count = 0;
225+
for (int j = 0; j < result->imports.count; j++) {
226+
const CBMImport *imp = &result->imports.items[j];
227+
if (!imp->module_path) {
228+
continue;
229+
}
230+
char *target_qn = cbm_pipeline_fqn_module(ctx->project_name, imp->module_path);
231+
const cbm_gbuf_node_t *target = cbm_gbuf_find_by_qn(ctx->gbuf, target_qn);
232+
char *file_qn = cbm_pipeline_fqn_compute(ctx->project_name, rel, "__file__");
233+
const cbm_gbuf_node_t *source_node = cbm_gbuf_find_by_qn(ctx->gbuf, file_qn);
234+
if (source_node && target) {
235+
char imp_props[256];
236+
snprintf(imp_props, sizeof(imp_props), "{\"local_name\":\"%s\"}",
237+
imp->local_name ? imp->local_name : "");
238+
cbm_gbuf_insert_edge(ctx->gbuf, source_node->id, target->id, "IMPORTS", imp_props);
239+
count++;
240+
}
241+
free(target_qn);
242+
free(file_qn);
243+
}
244+
return count;
245+
}
246+
200247
int cbm_pipeline_pass_definitions(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *files,
201248
int file_count) {
202249
cbm_log_info("pass.start", "pass", "definitions", "files", itoa_log(file_count));
@@ -240,75 +287,14 @@ int cbm_pipeline_pass_definitions(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t
240287

241288
/* Create nodes for each definition */
242289
for (int d = 0; d < result->defs.count; d++) {
243-
CBMDefinition *def = &result->defs.items[d];
244-
if (!def->qualified_name || !def->name) {
245-
continue;
246-
}
247-
248-
char props[2048];
249-
build_def_props(props, sizeof(props), def);
250-
251-
int64_t node_id =
252-
cbm_gbuf_upsert_node(ctx->gbuf, def->label ? def->label : "Function", def->name,
253-
def->qualified_name, def->file_path ? def->file_path : rel,
254-
(int)def->start_line, (int)def->end_line, props);
255-
256-
/* Register callable symbols in the registry */
257-
if (node_id > 0 && def->label &&
258-
(strcmp(def->label, "Function") == 0 || strcmp(def->label, "Method") == 0 ||
259-
strcmp(def->label, "Class") == 0)) {
260-
cbm_registry_add(ctx->registry, def->name, def->qualified_name, def->label);
261-
}
262-
263-
/* DEFINES edge: File node → Definition node */
264-
const char *file_qn_name = "__file__";
265-
char *file_qn = cbm_pipeline_fqn_compute(ctx->project_name, rel, file_qn_name);
266-
const cbm_gbuf_node_t *file_node = cbm_gbuf_find_by_qn(ctx->gbuf, file_qn);
267-
if (file_node && node_id > 0) {
268-
cbm_gbuf_insert_edge(ctx->gbuf, file_node->id, node_id, "DEFINES", "{}");
269-
}
270-
free(file_qn);
271-
272-
/* DEFINES_METHOD edge: Class → Method */
273-
if (def->parent_class && def->label && strcmp(def->label, "Method") == 0) {
274-
const cbm_gbuf_node_t *parent = cbm_gbuf_find_by_qn(ctx->gbuf, def->parent_class);
275-
if (parent && node_id > 0) {
276-
cbm_gbuf_insert_edge(ctx->gbuf, parent->id, node_id, "DEFINES_METHOD", "{}");
277-
}
278-
}
279-
290+
process_def(ctx, &result->defs.items[d], rel);
280291
total_defs++;
281292
}
282293

283294
/* Store calls for pass_calls (we save them in the extraction results
284295
* for now — a future optimization would batch these) */
285296
total_calls += result->calls.count;
286-
total_imports += result->imports.count;
287-
288-
/* Store per-file import map for later use by pass_calls.
289-
* For each import, create an IMPORTS edge: File → imported module. */
290-
for (int j = 0; j < result->imports.count; j++) {
291-
CBMImport *imp = &result->imports.items[j];
292-
if (!imp->module_path) {
293-
continue;
294-
}
295-
296-
/* Find or create the target module node */
297-
char *target_qn = cbm_pipeline_fqn_module(ctx->project_name, imp->module_path);
298-
const cbm_gbuf_node_t *target = cbm_gbuf_find_by_qn(ctx->gbuf, target_qn);
299-
300-
char *file_qn = cbm_pipeline_fqn_compute(ctx->project_name, rel, "__file__");
301-
const cbm_gbuf_node_t *source_node = cbm_gbuf_find_by_qn(ctx->gbuf, file_qn);
302-
303-
if (source_node && target) {
304-
char imp_props[256];
305-
snprintf(imp_props, sizeof(imp_props), "{\"local_name\":\"%s\"}",
306-
imp->local_name ? imp->local_name : "");
307-
cbm_gbuf_insert_edge(ctx->gbuf, source_node->id, target->id, "IMPORTS", imp_props);
308-
}
309-
free(target_qn);
310-
free(file_qn);
311-
}
297+
total_imports += create_import_edges_for_file(ctx, result, rel);
312298

313299
/* Cache or free the extraction result */
314300
if (ctx->result_cache) {

0 commit comments

Comments
 (0)