Skip to content

Commit 3ead775

Browse files
committed
fix(python): skip annotation-only imports without a new raw free
The memory-core linter counts raw allocator calls per file and fails when a file grows. The TYPE_CHECKING change freed the copied local name of an annotation-only import with a new raw free in two import-map builders. build_import_map now asks the predicate on the name's span in the edge properties before copying it (cbm_imports_local_span_binds_runtime_name, which cbm_imports_local_binds_runtime_name now wraps), and the cross-LSP builder routes an annotation-only name through its existing no-value path. Same behaviour, no new raw allocator site. Signed-off-by: Martin Vogel <[email protected]>
1 parent 2455e75 commit 3ead775

4 files changed

Lines changed: 36 additions & 19 deletions

File tree

‎internal/cbm/cbm.c‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,14 +402,16 @@ void cbm_imports_push(CBMImportArray *arr, CBMArena *a, CBMImport imp) {
402402
arr->items[arr->count++] = imp;
403403
}
404404

405-
bool cbm_imports_local_binds_runtime_name(const CBMImportArray *imports, const char *local_name) {
406-
if (!imports || !local_name) {
405+
bool cbm_imports_local_span_binds_runtime_name(const CBMImportArray *imports, const char *name,
406+
size_t len) {
407+
if (!imports || !name) {
407408
return true;
408409
}
409410
bool seen = false;
410411
for (int i = 0; i < imports->count; i++) {
411412
const CBMImport *imp = &imports->items[i];
412-
if (!imp->local_name || strcmp(imp->local_name, local_name) != 0) {
413+
if (!imp->local_name || strncmp(imp->local_name, name, len) != 0 ||
414+
imp->local_name[len] != '\0') {
413415
continue;
414416
}
415417
if (cbm_import_binds_runtime_name(imp)) {
@@ -420,6 +422,11 @@ bool cbm_imports_local_binds_runtime_name(const CBMImportArray *imports, const c
420422
return !seen;
421423
}
422424

425+
bool cbm_imports_local_binds_runtime_name(const CBMImportArray *imports, const char *local_name) {
426+
return !local_name ||
427+
cbm_imports_local_span_binds_runtime_name(imports, local_name, strlen(local_name));
428+
}
429+
423430
void cbm_usages_push(CBMUsageArray *arr, CBMArena *a, CBMUsage usage) {
424431
GROW_ARRAY(arr, a);
425432
arr->items[arr->count++] = usage;

‎internal/cbm/cbm.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,10 @@ void cbm_imports_push(CBMImportArray *arr, CBMArena *a, CBMImport imp);
13211321
* annotation-only (cbm_import_binds_runtime_name), so also true when no import
13221322
* names it: the rule for the builders that key IMPORTS edges by local name. */
13231323
bool cbm_imports_local_binds_runtime_name(const CBMImportArray *imports, const char *local_name);
1324+
/* The same for the `len` bytes at `name` (not NUL-terminated): lets a caller
1325+
* decide before it copies the name. */
1326+
bool cbm_imports_local_span_binds_runtime_name(const CBMImportArray *imports, const char *name,
1327+
size_t len);
13241328
void cbm_usages_push(CBMUsageArray *arr, CBMArena *a, CBMUsage usage);
13251329
void cbm_throws_push(CBMThrowArray *arr, CBMArena *a, CBMThrow thr);
13261330
void cbm_rw_push(CBMRWArray *arr, CBMArena *a, CBMReadWrite rw);

‎src/pipeline/pass_calls.c‎

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,24 @@ static const char *itoa_log(int val) {
9595

9696
/* Build per-file import map from cached extraction result or graph buffer edges.
9797
* Returns parallel arrays of (local_name, module_qn) pairs. Caller frees. */
98-
/* Parse "local_name":"value" from JSON properties string. Returns strdup'd key or NULL. */
99-
static char *extract_local_name_from_json(const char *props_json) {
98+
/* The "local_name":"value" of a JSON properties string, as a span of it;
99+
* false when absent or empty. */
100+
static bool local_name_span_from_json(const char *props_json, const char **out, size_t *len) {
100101
if (!props_json) {
101-
return NULL;
102+
return false;
102103
}
103104
const char *start = strstr(props_json, "\"local_name\":\"");
104105
if (!start) {
105-
return NULL;
106+
return false;
106107
}
107108
start += strlen("\"local_name\":\"");
108109
const char *end = strchr(start, '"');
109110
if (!end || end <= start) {
110-
return NULL;
111+
return false;
111112
}
112-
return cbm_strndup(start, end - start);
113+
*out = start;
114+
*len = (size_t)(end - start);
115+
return true;
113116
}
114117

115118
/* The graph node whose QN is cbm_pipeline_fqn_compute(project, rel_path, name),
@@ -193,11 +196,16 @@ static int build_import_map(cbm_pipeline_ctx_t *ctx, const char *rel_path,
193196
if (!target) {
194197
continue;
195198
}
196-
char *key = extract_local_name_from_json(e->properties_json);
197-
if (key && !cbm_imports_local_binds_runtime_name(result ? &result->imports : NULL, key)) {
198-
free(key); /* annotation-only import (#1277): no CALLS binding */
199-
key = NULL;
199+
const char *name = NULL;
200+
size_t name_len = 0;
201+
/* An annotation-only import (#1277) binds no CALLS name: skipped before
202+
* the key is copied. */
203+
if (!local_name_span_from_json(e->properties_json, &name, &name_len) ||
204+
!cbm_imports_local_span_binds_runtime_name(result ? &result->imports : NULL, name,
205+
name_len)) {
206+
continue;
200207
}
208+
char *key = cbm_strndup(name, name_len);
201209
if (key) {
202210
keys[count] = key;
203211
vals[count] = target->qualified_name;

‎src/pipeline/pass_lsp_cross.c‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,12 +1147,10 @@ int cbm_pxc_build_import_map_ex(const cbm_gbuf_t *gbuf, const char *project_name
11471147
continue;
11481148
memcpy(local, start, n);
11491149
local[n] = '\0';
1150-
if (!include_type_only &&
1151-
!cbm_imports_local_binds_runtime_name(result ? &result->imports : NULL, local)) {
1152-
free(local); /* annotation-only import (#1277): no CALLS binding */
1153-
continue;
1154-
}
1155-
char *value = pxc_import_value_qn(lang, result, local, target);
1150+
/* An annotation-only import (#1277) binds no CALLS name: it gets no value. */
1151+
bool binds = include_type_only ||
1152+
cbm_imports_local_binds_runtime_name(result ? &result->imports : NULL, local);
1153+
char *value = binds ? pxc_import_value_qn(lang, result, local, target) : NULL;
11561154
if (!value) {
11571155
free(local);
11581156
continue;

0 commit comments

Comments
 (0)