Skip to content

Commit d94370f

Browse files
authored
Break-glass merge PR #2630
2 parents 849b97b + 7aa384b commit d94370f

20 files changed

Lines changed: 592 additions & 104 deletions

‎internal/cbm/cbm.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,15 @@ typedef struct {
304304
* values are escaped where the properties are written. Tail field:
305305
* zero-init stays valid. */
306306
const char **extra_props;
307+
/* C-family platform variants (helpers.h cbm_platform_neutral_qn): the
308+
* platform-neutral QN of a non-static file-scope function whose path
309+
* carries a platform token (foo_win.c, src/unix/fs.c). The definition
310+
* keeps its own path QN; this becomes the node's `variant_key` property,
311+
* and the nodes of a project sharing one key are the platform variants of
312+
* one function (the test-impact walk treats a change in any of them as a
313+
* change of all, store_impact.h follow_variant_keys). NULL on every other
314+
* definition. Tail field: zero-init stays valid. */
315+
const char *variant_key;
307316
} CBMDefinition;
308317

309318
/* Argument captured from a call expression */

‎internal/cbm/extract_defs.c‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6609,14 +6609,6 @@ static void extract_func_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
66096609
* proj.myapp.db.Func, not proj.myapp.db.conn.Func). Other langs unchanged. */
66106610
def.qualified_name =
66116611
cbm_fqn_compute_source_lang(a, ctx->project, ctx->rel_path, qn_name, ctx->language);
6612-
/* C-family platform variants (foo_win.c / foo_posix.c, src/unix/ vs
6613-
* src/win/): an external-linkage file-scope function takes its
6614-
* platform-neutral QN, so its variants are one definition. The call-scope
6615-
* twin in extract_unified.c applies the same rule. */
6616-
if (!ctx->enclosing_class_qn) {
6617-
def.qualified_name = cbm_platform_variant_qn(a, ctx->language, ctx->project, ctx->rel_path,
6618-
qn_name, def.qualified_name, node);
6619-
}
66206612
/* A free function declared inside a namespace (C++/C#/PHP) is qualified by
66216613
* the namespace scope the def walk carries (enclosing_class_qn was extended
66226614
* by is_namespace_scope_kind), so `ns::serialize` is `proj.file.ns.serialize`
@@ -6715,6 +6707,16 @@ static void extract_func_def(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec
67156707
}
67166708
}
67176709

6710+
/* C-family platform variants (foo_win.c / foo_posix.c, src/unix/ vs
6711+
* src/win/): an external-linkage file-scope function keeps its path QN and
6712+
* carries its platform-neutral QN as the key that relates its variants
6713+
* (the node's `variant_key`). NULL for anything scoped, static, or in a
6714+
* path without a platform token. */
6715+
if (!ctx->enclosing_class_qn) {
6716+
def.variant_key = cbm_platform_neutral_qn(a, ctx->language, ctx->project, ctx->rel_path,
6717+
qn_name, def.qualified_name, node);
6718+
}
6719+
67186720
// Pony: fun/be/new (method/constructor/ffi_method) live in pony_func_types,
67196721
// so the main def-walk extracts them here as "Function"; but one declared
67206722
// inside a class/actor/struct/trait/interface/primitive IS a method. Detect

‎internal/cbm/extract_unified.c‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,13 +1111,9 @@ static const char *compute_func_qn(CBMExtractCtx *ctx, TSNode node, const CBMLan
11111111
return cbm_arena_sprintf(ctx->arena, "%s.%s", state->enclosing_class_qn, qn_name);
11121112
}
11131113
/* Java/Go: directory-based module so this enclosing-func QN matches the def
1114-
* QN and the LSP caller_qn (the lsp_resolve join keys on exact equality).
1115-
* C-family platform variants share their platform-neutral QN — the same
1116-
* rule extract_func_def applies, so in-body calls source to the def. */
1117-
const char *qn = cbm_fqn_compute_source_lang(ctx->arena, ctx->project, ctx->rel_path, qn_name,
1118-
ctx->language);
1119-
return cbm_platform_variant_qn(ctx->arena, ctx->language, ctx->project, ctx->rel_path, qn_name,
1120-
qn, node);
1114+
* QN and the LSP caller_qn (the lsp_resolve join keys on exact equality). */
1115+
return cbm_fqn_compute_source_lang(ctx->arena, ctx->project, ctx->rel_path, qn_name,
1116+
ctx->language);
11211117
}
11221118

11231119
// Compute class QN for scope tracking.

‎internal/cbm/helpers.c‎

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,24 +1946,24 @@ static bool func_is_static(TSNode func_node) {
19461946
return false;
19471947
}
19481948

1949-
const char *cbm_platform_variant_qn(CBMArena *a, CBMLanguage lang, const char *project,
1949+
const char *cbm_platform_neutral_qn(CBMArena *a, CBMLanguage lang, const char *project,
19501950
const char *rel_path, const char *name, const char *qn,
19511951
TSNode func_node) {
19521952
if (!c_family_variant_lang(lang) || !rel_path || !name || !name[0] || !qn ||
19531953
ts_node_is_null(func_node) || func_is_static(func_node)) {
1954-
return qn;
1954+
return NULL;
19551955
}
19561956
char *plain = cbm_fqn_compute(a, project, rel_path, name);
19571957
if (!plain || strcmp(plain, qn) != 0) {
1958-
return qn; /* namespaced or otherwise scoped: not a file-scope function */
1958+
return NULL; /* namespaced or otherwise scoped: not a file-scope function */
19591959
}
19601960
/* Rebuild the path without platform tokens: a directory segment that is
19611961
* one is dropped; a filename stem loses its platform suffix, and a stem
19621962
* that IS a token leaves the function at its directory. */
19631963
size_t len = strlen(rel_path);
19641964
char *neutral = (char *)cbm_arena_alloc(a, len + SKIP_ONE);
19651965
if (!neutral) {
1966-
return qn;
1966+
return NULL;
19671967
}
19681968
size_t out = 0;
19691969
bool changed = false;
@@ -2010,16 +2010,15 @@ const char *cbm_platform_variant_qn(CBMArena *a, CBMLanguage lang, const char *p
20102010
}
20112011
neutral[out] = '\0';
20122012
if (!changed) {
2013-
return qn;
2013+
return NULL;
20142014
}
20152015
if (dir_level) {
20162016
/* No file stem left: the folder form keeps every directory segment
20172017
* (cbm_fqn_compute would strip a dotted segment as an extension). */
20182018
char *folder = cbm_fqn_folder(a, project ? project : "", neutral);
2019-
return folder ? cbm_arena_sprintf(a, "%s.%s", folder, name) : qn;
2019+
return folder ? cbm_arena_sprintf(a, "%s.%s", folder, name) : NULL;
20202020
}
2021-
char *variant = cbm_fqn_compute(a, project, neutral, name);
2022-
return variant ? variant : qn;
2021+
return cbm_fqn_compute(a, project, neutral, name);
20232022
}
20242023

20252024
char *cbm_fqn_folder(CBMArena *a, const char *project, const char *rel_dir) {

‎internal/cbm/helpers.h‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,17 @@ char *cbm_fqn_compute_source_lang(CBMArena *a, const char *project, const char *
295295

296296
// C-family platform variants: the same external-linkage function defined in
297297
// files that differ only by a platform token (foo_win.c / foo_posix.c,
298-
// src/unix/fs.c / src/win/fs.c) is ONE function with platform variants — two
298+
// src/unix/fs.c / src/win/fs.c) is one function with platform variants — two
299299
// external definitions of one name cannot link into one program, so they are
300-
// alternatives by construction. Returns the platform-neutral QN (the path with
301-
// its platform tokens removed) for a non-static file-scope function of
302-
// C/C++/CUDA/ObjC whose `qn` is the plain file-stem form; otherwise `qn`.
303-
const char *cbm_platform_variant_qn(CBMArena *a, CBMLanguage lang, const char *project,
300+
// alternatives by construction. Each definition keeps its own path QN (it is
301+
// found by its file); this returns the KEY that relates the variants: the
302+
// platform-neutral QN (the path with its platform tokens removed), for a
303+
// non-static file-scope function of C/C++/CUDA/ObjC whose `qn` is the plain
304+
// file-stem form and whose path carries a platform token. NULL otherwise. A
305+
// pure function of the definition's own path, name and linkage: no other file
306+
// takes part, so a full index and an incremental repair write the same key.
307+
// It becomes the node's `variant_key` property (CBMDefinition.variant_key).
308+
const char *cbm_platform_neutral_qn(CBMArena *a, CBMLanguage lang, const char *project,
304309
const char *rel_path, const char *name, const char *qn,
305310
TSNode func_node);
306311

‎internal/cbm/result_compact.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ static void cr_walk_def(cr_ctx_t *c, CBMDefinition *d) {
278278
cr_str(c, &d->variants);
279279
cr_list(c, &d->extra_props);
280280
cr_str(c, &d->decl_namespace);
281+
cr_str(c, &d->variant_key);
281282
}
282283

283284
static void cr_walk_call(cr_ctx_t *c, CBMCall *call) {

‎src/graph_buffer/graph_buffer.c‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,11 @@ int cbm_gbuf_duplicate_edge_ids(const cbm_gbuf_t *gb) {
889889
* sorted, unique), so a change in any variant maps to the node. Recorded only
890890
* between definitions of the same label with real spans: a different kind
891891
* sharing the QN (C: struct vs function) is no variant, a span on line 0 is
892-
* no location (delta-route proxies), and a full tie is the same entity. */
892+
* no location (delta-route proxies), and a full tie is the same entity.
893+
* C-family platform files (foo_win.c / foo_posix.c, src/unix/ vs src/win/)
894+
* do not collide here: each definition keeps its path QN, and they share a
895+
* `variant_key` property instead (helpers.h cbm_platform_neutral_qn), which
896+
* the test-impact walk follows (store_impact.h follow_variant_keys). */
893897
static void *gb_yy_malloc(void *ctx, size_t size) {
894898
(void)ctx;
895899
return cbm_alloc(CBM_MEM_CLASS_GBUF_STRING, size);

‎src/mcp/test_impact_engine_reach.c‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,15 @@ static bool te_collect_sinks(te_ctx_t *c, te_sinks_t *s) {
290290

291291
static bool te_walk(te_ctx_t *c, const te_sinks_t *sinks, const int64_t *extra, int extra_count,
292292
cbm_impact_walk_t **out) {
293+
/* A change in one platform variant of a function (foo_win.c / foo_posix.c)
294+
* reaches whoever calls any of its variants: a caller binds to one of
295+
* them, and the build of another platform runs another. */
293296
cbm_impact_policy_t policy = {.project = "test-impact",
294297
.edge_types = te_walk_types,
295298
.edge_type_count =
296299
(int)(sizeof(te_walk_types) / sizeof(te_walk_types[0])),
297-
.follow_routes = true};
300+
.follow_routes = true,
301+
.follow_variant_keys = true};
298302
*out = NULL;
299303
if (cbm_impact_walk_open_scoped(c->scope, &policy, out) != CBM_STORE_OK) {
300304
return te_fallback(c, CBM_TEST_RESULT_FALLBACK_ENGINE_SATURATED,

‎src/mcp/test_impact_seed.c‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,13 @@ static bool ts_has_span(const cbm_ti_node_t *nodes, int count, const cbm_node_t
168168
}
169169

170170
/* The file's definitions, each with every span it has in the file: a
171-
* definition written once per #if branch or platform file is ONE node
171+
* definition written once per #if branch or Go build-tagged file is ONE node
172172
* (graph_buffer.c "Definition variants") whose own span is one variant, so
173173
* its other variants here (other branches, or a node whose file_path names
174-
* another platform file) join as further spans of the same node. A change
175-
* in any variant then seeds that definition. */
174+
* another file of the same QN) join as further spans of the same node. A
175+
* change in any variant then seeds that definition. C-family platform files
176+
* are separate nodes sharing a `variant_key`; the walk relates them
177+
* (store_impact.h follow_variant_keys). */
176178
static ts_file_t *ts_load_file(cbm_ti_graph_t *g, const char *file) {
177179
cbm_node_t *rows = NULL;
178180
int count = 0;

‎src/pipeline/pass_definitions.c‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,9 +309,10 @@ static void build_def_props(char *buf, size_t bufsize, const CBMDefinition *def)
309309
}
310310
size_t pos = (size_t)n;
311311
append_json_string(buf, bufsize, &pos, "docstring", def->docstring);
312-
/* Right after the docstring: the buffer is sized for exactly these two
313-
* uncapped fields (pd_props_buf), so neither can be squeezed out. */
312+
/* Right after the docstring: the buffer is sized for exactly these three
313+
* uncapped fields (pd_props_buf), so none can be squeezed out. */
314314
append_json_raw(buf, bufsize, &pos, "variants", def->variants);
315+
append_json_string(buf, bufsize, &pos, "variant_key", def->variant_key);
315316
append_json_string(buf, bufsize, &pos, "signature", def->signature);
316317
append_json_string(buf, bufsize, &pos, "return_type", def->return_type);
317318
append_json_string(buf, bufsize, &pos, "parent_class", def->parent_class);
@@ -353,10 +354,10 @@ static void build_def_props(char *buf, size_t bufsize, const CBMDefinition *def)
353354
}
354355

355356
/* A def's properties buffer: CBM_SZ_2K for every other field plus the whole
356-
* serialized docstring and variants fields, which have no length cap (a field
357-
* that does not fit is dropped whole). Returns `stack` for a def with neither,
358-
* or when the larger buffer cannot be allocated. Twin of pass_parallel.c --
359-
* keep both in sync. */
357+
* serialized docstring, variants and variant_key fields, which have no length
358+
* cap (a field that does not fit is dropped whole). Returns `stack` for a def
359+
* with none of them, or when the larger buffer cannot be allocated. Twin of
360+
* pass_parallel.c -- keep both in sync. */
360361
static char *pd_props_buf(const CBMDefinition *def, char *stack, size_t *size) {
361362
size_t need = *size;
362363
if (def->docstring && def->docstring[0]) {
@@ -365,6 +366,10 @@ static char *pd_props_buf(const CBMDefinition *def, char *stack, size_t *size) {
365366
if (def->variants && def->variants[0]) {
366367
need += strlen("variants") + strlen(def->variants) + PD_JSON_FIELD_OVERHEAD;
367368
}
369+
if (def->variant_key && def->variant_key[0]) {
370+
need +=
371+
strlen("variant_key") + def_json_escaped_len(def->variant_key) + PD_JSON_FIELD_OVERHEAD;
372+
}
368373
if (need == *size) {
369374
return stack;
370375
}

0 commit comments

Comments
 (0)