Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
c650292
feat(identity): callable identity plumbing, no language enabled (#2061)
DeusData Sep 25, 2026
7abaa91
chore(lint): clang-format the callable_sig.h include comment in store.c
DeusData Sep 25, 2026
d8a845e
fix(swift): preserve overload identity and label-aware call edges
DavidHLP Sep 26, 2026
7ae8300
style(swift): format overload patch
DavidHLP Sep 26, 2026
20b55ff
test(swift): cover parallel overload candidate edges
DavidHLP Sep 26, 2026
d5cb9b5
test(swift): accept signature-qualified caller names in call matrix
DavidHLP Sep 26, 2026
19c8d07
fix(swift): unify incompatible-overload fallback across resolver paths
DavidHLP Sep 29, 2026
bbd0957
fix(pipeline): use tracked allocator for suffix lookup
DavidHLP Sep 29, 2026
2100204
fix: guard zero-length signature buffer copy
DavidHLP Sep 30, 2026
b0958c6
refactor: narrow Swift candidate variable scope
DavidHLP Sep 30, 2026
b7c8669
fix(swift): merge current callable identity plumbing
DavidHLP Oct 1, 2026
f583ad9
fix(swift): match multiple trailing closure labels
DavidHLP Oct 3, 2026
73f4475
docs(swift): record focused identity validation evidence
DavidHLP Oct 3, 2026
6fc5af9
test(swift): add standalone issue 2061 graph reproduction
DavidHLP Oct 3, 2026
ceb1914
docs(swift): record original issue 2061 graph red-green evidence
DavidHLP Oct 3, 2026
617c030
test(swift): add MCP presentation repro driver
DavidHLP Oct 3, 2026
f6c5ef6
docs(swift): record scoped MCP validation failure
DavidHLP Oct 3, 2026
eea3143
docs(swift): record index format rebuild validation
DavidHLP Oct 3, 2026
251c06a
fix(swift): integrate callable identity with current main
DavidHLP Oct 5, 2026
b4e3daf
test(swift): reproduce default-before-required argument matching
DavidHLP Oct 5, 2026
233f569
fix(swift): propagate route mounts through overload emitters
DavidHLP Oct 5, 2026
9aad2f9
fix(swift): retain default argument matching alternatives
DavidHLP Oct 5, 2026
98c3a40
style(swift): format variadic matching transition
DavidHLP Oct 5, 2026
44294f8
test(swift): preserve MCP observations through sanitizer teardown
DavidHLP Oct 5, 2026
997cb1e
refactor(swift): bound matcher transition complexity
DavidHLP Oct 5, 2026
a03131c
fix(swift): account for service signature scratch allocation
DavidHLP Oct 5, 2026
0f294df
refactor(swift): reuse signature depth tracking for closure types
DavidHLP Oct 5, 2026
39d5db4
docs(swift): publish current main integration and validation evidence
DavidHLP Oct 5, 2026
7188414
test(swift): expose generic and async identity collisions
DavidHLP Oct 5, 2026
e1eb929
fix(swift): retain generic requirements and async callable identity
DavidHLP Oct 5, 2026
5d214b3
docs(swift): archive history and provide portable graph and MCP repro
DavidHLP Oct 5, 2026
5f77b45
docs(swift): clarify fresh reproduction database requirements
DavidHLP Oct 5, 2026
6222b52
test(swift): share incompatible-call fixture across resolver paths
DavidHLP Oct 5, 2026
5d21def
test(swift): require persisted incremental repair path
DavidHLP Oct 5, 2026
6a8905e
test(swift): verify incompatible-edge assertion detects injected faults
DavidHLP Oct 5, 2026
9ea6058
style(swift): format identity regression additions
DavidHLP Oct 5, 2026
9a18323
refactor(swift): keep signature parsing within lint limits
DavidHLP Oct 5, 2026
ee61f3b
refactor(swift): remove new static analysis violations
DavidHLP Oct 5, 2026
d4f10e9
style(swift): preserve signature constant formatting
DavidHLP Oct 5, 2026
3bde72e
refactor(swift): preserve service matching order without assignment c…
DavidHLP Oct 5, 2026
f2da1f4
style(swift): format service matching table
DavidHLP Oct 5, 2026
500707c
docs(swift): publish final repair evidence and main controls
DavidHLP Oct 5, 2026
f234417
test(swift): reproduce qualified and return overload collisions
DavidHLP Oct 5, 2026
598d068
test(swift): cover return candidates and format-three migration
DavidHLP Oct 5, 2026
3113c6a
test(swift): guard returned operator and capped identities
DavidHLP Oct 5, 2026
e3cd15a
test(swift): preserve nested generic requirement boundaries
DavidHLP Oct 5, 2026
ab0dce1
fix(swift): retain qualified parameter and return identities
DavidHLP Oct 5, 2026
90bfd2e
style(swift): format overload identity regressions
DavidHLP Oct 5, 2026
7867379
refactor(swift): simplify balanced return validation
DavidHLP Oct 5, 2026
10f4769
style(swift): wrap generic boundary guard
DavidHLP Oct 5, 2026
35533b2
docs(swift): record qualified and return identity validation
DavidHLP Oct 5, 2026
6ca78d0
chore(swift): merge main and resolve indexing conflicts
DavidHLP Oct 7, 2026
f6d8c70
chore(swift): merge main PHP route resolution without conflicts
DavidHLP Oct 8, 2026
542e9e0
chore(swift): merge main and retain definition metadata
DavidHLP Oct 9, 2026
4810738
merge: resolve Swift identity conflicts with current main
DavidHLP Oct 10, 2026
a146763
fix(lint): clarify PDF duplicate node name comparison
DavidHLP Oct 10, 2026
67c46cb
fix(swift): integrate upstream candidate ranking API
DavidHLP Oct 11, 2026
2a4d50d
merge: resolve PR #2436 conflicts with main
DavidHLP Oct 13, 2026
caa4d0c
fix: pass language to parallel service edge
DavidHLP Oct 13, 2026
ba26041
fix: address CI route and sanitizer findings
DavidHLP Oct 13, 2026
49d6798
merge: sync main and resolve PR #2436 conflicts
DavidHLP Oct 14, 2026
09fcf9b
test(cypher): cap Windows UNION stress branches
DavidHLP Oct 14, 2026
fd05880
Merge branch 'main' of github.com:DeusData/codebase-memory-mcp into f…
DavidHLP Oct 14, 2026
1010bde
fix(swift): preserve distinct identities and uncapped selectors
DavidHLP Oct 15, 2026
5142a75
Merge upstream main into feat/issue-2061-swift-identity
DavidHLP Oct 15, 2026
a9e56d9
style(swift): format candidate scratch allocation
DavidHLP Oct 15, 2026
4ab447f
chore: merge main and reconcile index migrations
DavidHLP Oct 17, 2026
4885230
Merge branch 'main' into feat/issue-2061-swift-identity
DavidHLP Oct 18, 2026
c9baad7
fix(swift): address callable identity review and merge main
DavidHLP Oct 26, 2026
8e91d3f
fix(swift): integrate lifecycle identities and preserve receiver inhe…
DavidHLP Oct 26, 2026
debefaf
fix(registry): bound receiver root scan by initialized length
DavidHLP Oct 26, 2026
d33c6ac
fix(swift): resolve members declared in cross-file extensions
DavidHLP Nov 4, 2026
05c7ba7
Merge upstream main into Swift declaration identity
DavidHLP Nov 4, 2026
c652f23
test(swift): reserve space for Windows temp directory paths
DavidHLP Nov 4, 2026
38df8e5
fix(swift): scope extension owners by module
DavidHLP Nov 4, 2026
6eddf54
fix(swift): resolve chains within SwiftPM target scope
DavidHLP Nov 4, 2026
ff4b1eb
test(registry): avoid Windows near macro collisions
DavidHLP Nov 4, 2026
1a6b292
fix(swift): retain Sendable alias parameters in selectors
DavidHLP Nov 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
474 changes: 432 additions & 42 deletions internal/cbm/callable_sig.c

Large diffs are not rendered by default.

34 changes: 24 additions & 10 deletions internal/cbm/callable_sig.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
*
* A callable's graph identity is
*
* callable_qn := base_qn [<tparams>] (params) [cvref]
* callable_qn := base_qn [<tparams>] (params) [cvref/static/class] [async] [=>return_type]
* Swift includes generic declarations and where requirements in <tparams>
* (associated-type paths use '/' instead of '.') and appends function-level
* async after params and an explicit return type after "=>". Qualified types keep their last
* segment. These distinguish declarations, not call applicability.
*
* so overloads that share a base QN (Java/C#/C++/Kotlin/Swift/Scala/ObjC)
* become distinct nodes instead of merging into one node that collects every
Expand All @@ -22,8 +26,8 @@
* - it is whitespace-normalized: one space only between two identifier
* characters ("unsigned long", "const T&"), none elsewhere;
* - type spelling: comments, annotations and attributes are dropped;
* qualified type paths keep their last segment (java.util.List -> List,
* std::vector -> vector); "->" in function types is spelled "=>"; a
* qualified paths keep their last segment (java.util.List
* -> List, std::vector -> vector); "->" in function types is spelled "=>"; a
* variadic/rest marker is "[]" for Java (the JVM array it is) and "~"
* everywhere else; C++ top-level cv-qualifiers are dropped and array
* parameters decay to pointers, as the language itself does;
Expand All @@ -38,6 +42,7 @@
#include "arena.h"
#include "tree_sitter/api.h"
#include <stddef.h>
#include <stdint.h>

typedef enum {
CBM_CALLABLE_ID_NONE = 0, /* historical base QN, no suffix */
Expand All @@ -49,20 +54,26 @@ typedef enum {

enum { CBM_CALLABLE_SIG_MAX = 200 };

/* The identity mode a language uses for callable QNs. Every language is
* CBM_CALLABLE_ID_NONE until its enable change lands (with its index-format
* bump). Kept as a side table, like cbm_string_dispatch_suffixes, rather than
* a CBMLangSpec field: the ~160 positional lang_specs rows would all have to
* spell the new member under -Wmissing-field-initializers. */
/* The identity mode a language uses for callable QNs. Languages remain
* CBM_CALLABLE_ID_NONE until their enable change lands with an index-format
* bump; Swift is enabled by #2061. Kept as a side table, like
* cbm_string_dispatch_suffixes, rather than a CBMLangSpec field: the ~160
* positional lang_specs rows would all have to spell the new member under
* -Wmissing-field-initializers. */
CBMCallableIdentity cbm_callable_identity(CBMLanguage lang);

/* Swift parameter defaults are call-resolution metadata, not graph identity.
* Returns a bit per parameter; count > 64 is reported as 255. */
uint64_t cbm_swift_default_mask(TSNode func_node, const char *source, uint8_t *count);
/* Uncapped parameter and return spelling: matching and chains must not parse a hashed identity. */
const char *cbm_swift_selector(CBMArena *a, TSNode func_node, const char *source);
/* The identity suffix for the callable at `func_node` in the language's own
* mode, or NULL when that mode is NONE (or the node carries no parameter
* information the mode can use). Arena-owned. */
const char *cbm_callable_sig(CBMArena *a, TSNode func_node, const char *source, CBMLanguage lang);

/* Same, with an explicit mode — the builder the enable changes and the golden
* tables exercise before a language is switched on. */
/* Same, with an explicit mode — the builder's golden tables exercise modes
* independently of each language's production enablement. */
const char *cbm_callable_sig_mode(CBMArena *a, TSNode func_node, const char *source,
CBMLanguage lang, CBMCallableIdentity mode);

Expand All @@ -72,6 +83,9 @@ const char *cbm_callable_sig_mode(CBMArena *a, TSNode func_node, const char *sou
* name, not a suffix. NULL -> 0. */
size_t cbm_qn_callable_base_len(const char *qn);

/* Top-level declaration return marker; strlen(suffix) if absent, 0 if malformed. */
size_t cbm_callable_return_offset(const char *suffix);

/* The inverse anchored to the callable's bare `name` (the node's name
* column): the suffix is stripped only when the base QN is `name` or ends in
* "." / "::" + `name`. Other QN text can end in ')' as well — a Java field
Expand Down
124 changes: 124 additions & 0 deletions internal/cbm/cbm.c
Original file line number Diff line number Diff line change
Expand Up @@ -3331,6 +3331,73 @@ static const char *extract_parse_bytes(CBMArena *a, CBMLanguage language, const
return source;
}

/* The Swift grammar rejects conditional directives in type bodies. Mask only
* real AST directive tokens, so strings/comments and source coordinates survive. */
static bool swift_mask_conditional_node(CBMArena *a, TSNode node, const char *source,
int source_len, char **masked) {
const char *kind = ts_node_type(node);
if (strcmp(kind, "#if") == 0 || strcmp(kind, "#elseif") == 0 || strcmp(kind, "#else") == 0 ||
strcmp(kind, "#endif") == 0) {
if (!*masked) {
*masked = cbm_arena_strndup(a, source, (size_t)source_len);
if (!*masked) {
return false;
}
}
for (uint32_t i = ts_node_start_byte(node);
i < (uint32_t)source_len && source[i] != '\n' && source[i] != '\r'; i++) {
(*masked)[i] = ' ';
}
} else if (*masked &&
(strcmp(kind, "comment") == 0 || strcmp(kind, "multiline_comment") == 0)) {
for (uint32_t i = ts_node_start_byte(node);
i < ts_node_end_byte(node) && i < (uint32_t)source_len; i++) {
(*masked)[i] = source[i];
}
}
return true;
}

static const char *swift_mask_conditional_directives(CBMArena *a, TSNode root, const char *source,
int source_len) {
char *masked = NULL;
TSTreeCursor cursor = ts_tree_cursor_new(root);
bool more = true;
while (more) {
TSNode node = ts_tree_cursor_current_node(&cursor);
if (!swift_mask_conditional_node(a, node, source, source_len, &masked)) {
break;
}
if (ts_tree_cursor_goto_first_child(&cursor)) {
continue;
}
while (!ts_tree_cursor_goto_next_sibling(&cursor)) {
if (!ts_tree_cursor_goto_parent(&cursor)) {
more = false;
break;
}
}
}
ts_tree_cursor_delete(&cursor);
return masked ? masked : source;
}

static TSTree *swift_retry_conditional_parse(CBMArena *a, TSParser *parser, TSTree *tree,
CBMLanguage language, const char *source,
int source_len, TSParseOptions opts) {
if (!tree || language != CBM_LANG_SWIFT || !ts_node_has_error(ts_tree_root_node(tree))) {
return tree;
}
const char *masked =
swift_mask_conditional_directives(a, ts_tree_root_node(tree), source, source_len);
if (masked == source) {
return tree;
}
ts_tree_delete(tree);
ts_parser_reset(parser);
return cbm_parse_source(parser, masked, (uint32_t)source_len, opts);
}

/* Initial block for the per-file traversal scratch arena, chosen by measuring
* arena_grow on a 14k-file TypeScript tree: it fires on one file in 12,000 at
* both this size and at 1 MB, and on most files at 256 KB, where the two
Expand Down Expand Up @@ -3634,6 +3701,61 @@ int cbm_test_enclosing_sweep_mismatches(const CBMFileResult *result) {
}
#endif

/* Extension visibility uses the file's direct imports, including imports
* written after a type declaration. The joined text is shared by its types. */
static void cbm_swift_type_imports(CBMFileResult *result, CBMLanguage language) {
if (language != CBM_LANG_SWIFT) {
return;
}
size_t length = SKIP_ONE;
for (int i = 0; i < result->imports.count; i++) {
const char *path = result->imports.items[i].module_path;
if (path && path[0]) {
length += strlen(path) + SKIP_ONE;
}
}
char *imports = cbm_arena_alloc(&result->arena, length);
if (!imports) {
return;
}
size_t used = 0;
for (int i = 0; i < result->imports.count; i++) {
const char *path = result->imports.items[i].module_path;
if (!path || !path[0]) {
continue;
}
if (used) {
imports[used++] = '|';
}
size_t n = strlen(path);
memcpy(imports + used, path, n);
used += n;
}
imports[used] = '\0';
for (int i = 0; i < result->defs.count; i++) {
CBMDefinition *def = &result->defs.items[i];
size_t count = 0;
bool is_type = false;
for (const char **kv = def->extra_props; kv && kv[0] && kv[SKIP_ONE]; kv += PAIR_LEN) {
is_type = is_type || strcmp(kv[0], "swift_type_path") == 0 ||
strcmp(kv[0], "swift_extension") == 0;
count += PAIR_LEN;
}
if (!is_type) {
continue;
}
const char **props =
cbm_arena_alloc(&result->arena, (count + PAIR_LEN + SKIP_ONE) * sizeof(*props));
if (props) {
memcpy(props, def->extra_props, count * sizeof(*props));
props[count] = "swift_imports";
props[count + SKIP_ONE] = imports;
props[count + PAIR_LEN] = NULL;
def->extra_props = props;
}
}
}

static CBMFileResult *extract_file_ex_body(const char *source, int source_len, CBMLanguage language,
const char *project, const char *rel_path,
int64_t timeout_micros, const char **extra_defines,
Expand Down Expand Up @@ -3814,6 +3936,7 @@ static CBMFileResult *extract_file_ex_body(const char *source, int source_len, C
cbm_sql_values_kept_ranges(source, (uint32_t)source_len, &sql_kept) &&
ts_parser_set_included_ranges(parser, sql_kept.items, sql_kept.count);
TSTree *tree = cbm_parse_source(parser, source, (uint32_t)source_len, opts);
tree = swift_retry_conditional_parse(a, parser, tree, language, source, source_len, opts);
if (sql_ranged) {
(void)ts_parser_set_included_ranges(parser, NULL, 0);
}
Expand Down Expand Up @@ -3901,6 +4024,7 @@ static CBMFileResult *extract_file_ex_body(const char *source, int source_len, C
cbm_extract_imports(&ctx);
cbm_extract_python_namespace_facts(&ctx);
cbm_extract_unified(&ctx);
cbm_swift_type_imports(result, language);
if (cbm_lang_needs_cpp_branch_views(language)) {
extract_cpp_branch_views(&ctx, ts_lang, timeout_micros);
}
Expand Down
27 changes: 25 additions & 2 deletions internal/cbm/cbm.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ typedef struct {
* qualified_name (base QN = the first qn_sig_off bytes); 0 = no suffix.
* Always 0 until a language enables its callable_identity mode. */
uint32_t qn_sig_off;
/* Call matching: defaulted parameters, indexed in declaration order. */
uint64_t param_default_mask;
uint8_t selector_param_count;
const char *call_selector;
/* C# only: declared namespace of a TOP-LEVEL type, "" for the global
* namespace (proven only by a clean parse), NULL for nested types, an
* unknown namespace and every other language. Per type, because the
Expand Down Expand Up @@ -340,6 +344,9 @@ typedef struct {
} CBMCallArg;

#define CBM_MAX_CALL_ARGS 8
/* Swift trailing-closure capture bound (#2061): more than this on one call
* marks the call truncated and the overload matcher fails closed. */
#define CBM_MAX_TRAILING_CLOSURES 8

/* The qualified name of a C-preprocessor macro (`#define NAME ...` in C, C++,
* CUDA, Objective-C, GLSL, ISPC) is `<module QN>.<NAME>#macro`. C keeps macros
Expand Down Expand Up @@ -396,6 +403,20 @@ typedef struct {
// (self.compiler.apply_converters()). An object the
// class owns, not a parameter: read by the weak-member
// guard's unique-name exemption. Default false.
bool has_trailing_closure;
bool args_truncated;
/* Swift multi-trailing-closure capture (#2061). `has_trailing_closure`
* stays the "there is at least one trailing closure" flag manual callers
* and existing tests set; `trailing_closure_count` is the actual number
* captured (0 => fall back to the bool, treated as one unlabelled closure).
* `trailing_closure_labels[i]` is closure i's argument label from the
* grammar's `lambda_literal (simple_identifier ':')*` sequence (NULL when
* unlabelled; entry 0 is always unlabelled). More closures than
* CBM_MAX_TRAILING_CLOSURES sets `trailing_closure_truncated`, and the
* overload matcher then fails closed rather than guessing a partial set. */
uint8_t trailing_closure_count;
bool trailing_closure_truncated;
const char **trailing_closure_labels;
} CBMCall;

// What an import statement names, when the syntax says so. Only PHP's
Expand Down Expand Up @@ -554,8 +575,10 @@ typedef struct {

typedef struct {
const char *var_name; // variable being assigned
const char *type_name; // class/type name of RHS constructor
const char *enclosing_func_qn; // QN of enclosing function
const char *type_name; // declared type or RHS constructor type
const char *enclosing_func_qn; // enclosing function, class, or module QN
uint32_t value_start_byte; // Swift call initializer span; type_name may be unknown
uint32_t value_end_byte; // exclusive; zero when no initializer call was recorded
} CBMTypeAssign;

// String reference: URL, config key, or async target found in source.
Expand Down
Loading
Loading