mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
Merge the cross-lane fixes from the first full Linux run
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
commit
e4f967e31f
9 files changed
+99
-69
No files matched your search
@@ -754,6 +754,21 @@ static bool perl_is_direct_coderef_argument(TSNode refgen) {
|
||||
return !ts_node_is_null(args) && ts_node_eq(args, container);
|
||||
}
|
||||
|
||||
/* `$f ? \&a : \&b` and `$f || \&a` hand over one of several values, so each \&name there only
|
||||
* mentions its sub. Parentheses change nothing. */
|
||||
static bool perl_coderef_in_composite(TSNode refgen) {
|
||||
for (TSNode parent = ts_node_parent(refgen); !ts_node_is_null(parent);
|
||||
parent = ts_node_parent(parent)) {
|
||||
const char *kind = ts_node_type(parent);
|
||||
if (strcmp(kind, "conditional_expression") == 0 || strcmp(kind, "binary_expression") == 0 ||
|
||||
strcmp(kind, "lowprec_logical_expression") == 0)
|
||||
return true;
|
||||
if (strcmp(kind, "list_expression") != 0)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void perl_emit_non_direct_coderef_usage(PerlLSPContext *ctx, TSNode refgen) {
|
||||
if (!ctx || !ctx->usages || !ctx->enclosing_func_qn ||
|
||||
perl_is_direct_coderef_argument(refgen)) {
|
||||
@@ -777,6 +792,7 @@ static void perl_emit_non_direct_coderef_usage(PerlLSPContext *ctx, TSNode refge
|
||||
usage.ref_name = name;
|
||||
usage.enclosing_func_qn = ctx->enclosing_func_qn;
|
||||
usage.kind = CBM_USAGE_VALUE;
|
||||
usage.may_be_call_reference = !perl_coderef_in_composite(refgen);
|
||||
usage.site_start_byte = start;
|
||||
usage.site_end_byte = end;
|
||||
cbm_usages_push(ctx->usages, ctx->arena, usage);
|
||||
|
||||
@@ -664,6 +664,7 @@ static void ocaml_collect_structure(cbm_source_walk_t *walk, const char *owner,
|
||||
}
|
||||
}
|
||||
}
|
||||
ts_tree_cursor_delete(&cursor);
|
||||
}
|
||||
|
||||
/* Where this file stands among the modules of its build. */
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
* has no sub import of its own, and lists the name in @EXPORT or @EXPORT_OK. What it
|
||||
* lists can be a name it imported itself, which is then that module's export.
|
||||
*
|
||||
* `\&name` takes a reference to the sub the same lookup selects, without calling it.
|
||||
* `\&name` takes a reference to the sub the same lookup selects, without calling it. Under a
|
||||
* conditional or an operator the value is one of several, so the site only mentions the sub:
|
||||
* the carrier from extraction says which.
|
||||
*
|
||||
* Literal glob assignment and lexical `my sub` replace a name, so that name
|
||||
* abstains. A glob assigned from a computed name can touch any package anywhere
|
||||
|
||||
@@ -4811,6 +4811,7 @@ static void resolve_worker_impl(int worker_id, void *ctx_ptr) {
|
||||
cbm_pxc_set_rust_manifest(NULL);
|
||||
cbm_destroy_thread_parser();
|
||||
cbm_slab_destroy_thread();
|
||||
cbm_kind_in_set_free_cache(); /* a damaged source file's scan fills it here too */
|
||||
cbm_service_pattern_cache_end();
|
||||
cbm_pxc_thread_scratch_end();
|
||||
file_node_cache_clear();
|
||||
|
||||
@@ -4702,8 +4702,7 @@ static bool resolve_usages(file_resolver_t *resolver, CBMArena *arena) {
|
||||
/* Source binding can establish a direct callable argument without a
|
||||
* hybrid row. Composite expressions remain USAGE: the extraction
|
||||
* carrier deliberately leaves may_be_call_reference false for them. */
|
||||
if (!site && (usage->may_be_call_reference || resolver->file->language == CBM_LANG_PERL) &&
|
||||
cbm_resolve_admit(&outcome) &&
|
||||
if (!site && usage->may_be_call_reference && cbm_resolve_admit(&outcome) &&
|
||||
callable_node(cbm_gbuf_find_by_qn(resolver->file->graph, outcome.target)))
|
||||
relation = "CALL_REFERENCE";
|
||||
/* Reading a property hands over its result, not the function. */
|
||||
|
||||
@@ -315,27 +315,17 @@ static const RP_QualityGolden rp_quality_goldens[] = {
|
||||
.label = "Function",
|
||||
.declaration_line = 1,
|
||||
.declaration_text = "sub handler {}"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "perl_exact_coderef_is_call_reference-1",
|
||||
.why = "Delegate or coderef argument values and callable-parameter applicability require an "
|
||||
"audited proof bridge.",
|
||||
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
|
||||
"reviewed; raw and forbidden assertions retained."}},
|
||||
.mode = RQ_REQUIRED}},
|
||||
{"repro_perl_exact_coderef_is_call_reference",
|
||||
{.case_id = "perl_exact_coderef_is_call_reference-2",
|
||||
.site = {.file = "refs.pl", .caller = "argument", .start_byte = 66, .end_byte = 83},
|
||||
.relation = "CALLS",
|
||||
.target = {.file = "refs.pl",
|
||||
.suffix = "refs.accept",
|
||||
.suffix = "refs.submit",
|
||||
.label = "Function",
|
||||
.declaration_line = 2,
|
||||
.declaration_text = "sub accept { my ($callback) = @_; }"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "perl_exact_coderef_is_call_reference-2",
|
||||
.why = "Delegate or coderef argument values and callable-parameter applicability require an "
|
||||
"audited proof bridge.",
|
||||
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
|
||||
"reviewed; raw and forbidden assertions retained."}},
|
||||
.declaration_text = "sub submit { my ($callback) = @_; }"},
|
||||
.mode = RQ_REQUIRED}},
|
||||
{"repro_rust_direct_scoped_function_value_is_exact_reference",
|
||||
{.case_id = "rust_direct_scoped_function_value_is_exact_reference-1",
|
||||
.site = {.file = "main.rs", .caller = "scoped_argument", .start_byte = 83, .end_byte = 98},
|
||||
@@ -890,49 +880,31 @@ static const RP_QualityGolden rp_quality_goldens[] = {
|
||||
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 99, .end_byte = 138},
|
||||
.relation = "CALLS",
|
||||
.target = {.file = "complex.pl",
|
||||
.suffix = "complex.accept",
|
||||
.suffix = "complex.submit",
|
||||
.label = "Function",
|
||||
.declaration_line = 3,
|
||||
.declaration_text = "sub accept { my ($callback) = @_; }"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "perl_conditional_coderefs_stay_usage-1",
|
||||
.why = "Conditional callable values retain genuine target mentions, but complete source "
|
||||
"binding, callable-argument applicability and value-reference proof are not yet "
|
||||
"audited for this language/form.",
|
||||
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
|
||||
"reviewed; raw and forbidden assertions retained."}},
|
||||
.declaration_text = "sub submit { my ($callback) = @_; }"},
|
||||
.mode = RQ_REQUIRED}},
|
||||
{"repro_perl_conditional_coderefs_stay_usage",
|
||||
{.case_id = "perl_conditional_coderefs_stay_usage-2",
|
||||
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 116, .end_byte = 123},
|
||||
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 114, .end_byte = 123},
|
||||
.relation = "USAGE",
|
||||
.target = {.file = "complex.pl",
|
||||
.suffix = "complex.handler",
|
||||
.label = "Function",
|
||||
.declaration_line = 1,
|
||||
.declaration_text = "sub handler {}"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "perl_conditional_coderefs_stay_usage-2",
|
||||
.why = "Conditional callable values retain genuine target mentions, but complete source "
|
||||
"binding, callable-argument applicability and value-reference proof are not yet "
|
||||
"audited for this language/form.",
|
||||
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
|
||||
"reviewed; raw and forbidden assertions retained."}},
|
||||
.mode = RQ_REQUIRED}},
|
||||
{"repro_perl_conditional_coderefs_stay_usage",
|
||||
{.case_id = "perl_conditional_coderefs_stay_usage-3",
|
||||
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 128, .end_byte = 137},
|
||||
.site = {.file = "complex.pl", .caller = "complex", .start_byte = 126, .end_byte = 137},
|
||||
.relation = "USAGE",
|
||||
.target = {.file = "complex.pl",
|
||||
.suffix = "complex.alternate",
|
||||
.label = "Function",
|
||||
.declaration_line = 2,
|
||||
.declaration_text = "sub alternate {}"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "perl_conditional_coderefs_stay_usage-3",
|
||||
.why = "Conditional callable values retain genuine target mentions, but complete source "
|
||||
"binding, callable-argument applicability and value-reference proof are not yet "
|
||||
"audited for this language/form.",
|
||||
.tried = "Original full-MCP fixture retained; exact source occurrence and target declaration "
|
||||
"reviewed; raw and forbidden assertions retained."}},
|
||||
.mode = RQ_REQUIRED}},
|
||||
{"repro_python_local_function_shadows_imported_callable",
|
||||
{.case_id = "repro_python_local_function_shadows_imported_callable-reference",
|
||||
.site = {.file = "use.py", .caller = "crossArgument", .start_byte = 121, .end_byte = 129},
|
||||
@@ -2302,10 +2274,12 @@ TEST(repro_tsx_exact_bound_method_is_call_reference) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* The registrar is not called `accept`: that is a Perl builtin, only an import overrides it
|
||||
* (perlsub), and `perl -c` rejects `accept(\&handler)` as too few arguments to the builtin. */
|
||||
TEST(repro_perl_exact_coderef_is_call_reference) {
|
||||
static const char source[] = "sub handler {}\n"
|
||||
"sub accept { my ($callback) = @_; }\n"
|
||||
"sub argument { accept(\\&handler); }\n";
|
||||
"sub submit { my ($callback) = @_; }\n"
|
||||
"sub argument { submit(\\&handler); }\n";
|
||||
int rc = rp_assert_exact_function_value_reference_quality(
|
||||
"refs.pl", source, CBM_LANG_PERL, "Function", "repro_perl_exact_coderef_is_call_reference");
|
||||
if (rc != 0)
|
||||
@@ -3564,12 +3538,13 @@ TEST(repro_php_complex_first_class_callable_stays_usage) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* The registrar is not called `accept`: see repro_perl_exact_coderef_is_call_reference. */
|
||||
TEST(repro_perl_conditional_coderefs_stay_usage) {
|
||||
static const char source[] = "sub handler {}\n"
|
||||
"sub alternate {}\n"
|
||||
"sub accept { my ($callback) = @_; }\n"
|
||||
"sub submit { my ($callback) = @_; }\n"
|
||||
"sub complex { my ($flag) = @_; "
|
||||
"accept($flag ? \\&handler : \\&alternate); }\n";
|
||||
"submit($flag ? \\&handler : \\&alternate); }\n";
|
||||
int rc = rp_assert_complex_function_values_stay_usage_quality(
|
||||
"complex.pl", source, CBM_LANG_PERL, "Function",
|
||||
"repro_perl_conditional_coderefs_stay_usage");
|
||||
|
||||
@@ -184,9 +184,9 @@ static const MKC_Golden mkc_goldens[] = {
|
||||
{"mkc_c2_csharp_operator_plus", "operator+", "new Vec2(a.X + b.X, a.Y + b.Y)", "Vec2",
|
||||
" public Vec2(float x, float y) { X = x; Y = y; }", "Method", 4, 0, true},
|
||||
{"mkc_c2_scala_symbolic_method", "run", "a + b", "+",
|
||||
" def +(other: Vec2): Vec2 = Vec2(x + other.x, y + other.y)", "Method", 2, 0, false},
|
||||
" def +(other: Vec2): Vec2 = Vec2(x + other.x, y + other.y)", "Method", 2, 0, true},
|
||||
{"mkc_c2_scala_symbolic_method", "run", "(a + b).dot(b)", "dot",
|
||||
" def dot(other: Vec2): Double = x * other.x + y * other.y", "Method", 3, 0, false},
|
||||
" def dot(other: Vec2): Double = x * other.x + y * other.y", "Method", 3, 0, true},
|
||||
{"mkc_c2_ruby_operator_plus", "+", "Vec2.new(@x + other.x, @y + other.y)", "initialize",
|
||||
" def initialize(x, y)", "Method", 3, 0, true},
|
||||
{"mkc_c4_typescript_async_await", "getData", "fetch(url)", "fetch",
|
||||
@@ -211,7 +211,7 @@ static const MKC_Golden mkc_goldens[] = {
|
||||
{"mkc_c4_swift_async_await", "run", "getData(url: url)", "getData",
|
||||
"func getData(url: String) async -> String {", "Function", 5, 0, true},
|
||||
{"mkc_c5_scala_generic_call", "run", "first(ns)", "first",
|
||||
"def first[T](xs: List[T]): Option[T] =", "Function", 1, 0, false},
|
||||
"def first[T](xs: List[T]): Option[T] =", "Function", 1, 0, true},
|
||||
{"mkc_c5_swift_generic_call", "run", "maxOf(a, b)", "maxOf",
|
||||
"func maxOf<T: Comparable>(_ a: T, _ b: T) -> T {", "Function", 1, 0, true},
|
||||
{"mkc_c5_ruby_duck_typed_call", "run", "first(items)", "first", "def first(collection)",
|
||||
|
||||
+33
-20
@@ -4305,12 +4305,7 @@ TEST(pipeline_call_reference_sequential_parallel_edge_set_parity) {
|
||||
.label = "Function",
|
||||
.declaration_line = 1,
|
||||
.declaration_text = "sub perlReferenceTarget {}"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "callback-perl-coderef",
|
||||
.why = "Package/subroutine declaration identity and typeglob/redefinition barriers lack a "
|
||||
"proof adapter.",
|
||||
.tried = "Focused pipeline probe: direct coderef has a legacy carrier only; no legacy "
|
||||
"confidence is admitted."},
|
||||
.mode = RQ_REQUIRED},
|
||||
{.case_id = "javascript-script-shadow-control",
|
||||
.site = {.file = "shadow.js",
|
||||
.caller = "shadow.javascriptShadowSite",
|
||||
@@ -4691,9 +4686,9 @@ TEST(pipeline_call_reference_sequential_parallel_edge_set_parity) {
|
||||
parallel_reference[i]);
|
||||
}
|
||||
for (int i = 0; i < pair_count; i++) {
|
||||
/* These six independent expectations are counted above as source-audited
|
||||
/* These five independent expectations are counted above as source-audited
|
||||
* quality gaps; recovery must promote them to required in the oracle. */
|
||||
if (i != 4 && i != 5 && i != 7 && i != 10 && i != 12 && i != 13)
|
||||
if (i != 4 && i != 5 && i != 7 && i != 10 && i != 12)
|
||||
ASSERT_GT(sequential_reference[i], 0);
|
||||
ASSERT_EQ(parallel_reference[i], sequential_reference[i]);
|
||||
ASSERT_EQ(sequential_usage[i], 0);
|
||||
@@ -15477,26 +15472,44 @@ static bool rust_std_receiver_quality(cbm_store_t *store, const char *project, c
|
||||
.site = {.file = "src/lib.rs", .caller = "lib.real_caller", .needle = "EvidenceTier(1)"},
|
||||
.relation = "CALLS",
|
||||
.target = {.file = "src/lib.rs",
|
||||
.suffix = "lib.EvidenceTier",
|
||||
.label = "Struct",
|
||||
.declaration_line = 4,
|
||||
.declaration_text = "pub struct EvidenceTier(pub u8);"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "RUST-TUPLE-STRUCT-CONSTRUCTOR-IDENTITY",
|
||||
.why = "The tuple-struct constructor is genuine but has no independent callable "
|
||||
"declaration identity in the current graph.",
|
||||
.tried = "Retained the exact source invocation and struct anchor; no synthesized method "
|
||||
"or legacy confidence substitutes for a constructor proof."},
|
||||
.mode = RQ_REQUIRED},
|
||||
{.case_id = "rust.tuple-constructor.argument",
|
||||
.site = {.file = "src/lib.rs", .caller = "lib.real_caller", .needle = "EvidenceTier(2)"},
|
||||
.relation = "CALLS",
|
||||
.target = {.file = "src/lib.rs",
|
||||
.suffix = "lib.EvidenceTier",
|
||||
.label = "Struct",
|
||||
.declaration_line = 4,
|
||||
.declaration_text = "pub struct EvidenceTier(pub u8);"},
|
||||
.mode = RQ_KNOWN_GAP,
|
||||
.gap_id = "RUST-TUPLE-STRUCT-CONSTRUCTOR-IDENTITY",
|
||||
.why = "The argument independently invokes the tuple-struct constructor; its callable "
|
||||
"identity is not represented.",
|
||||
.tried = "Kept the second raw call site in the denominator rather than merging it with "
|
||||
"the receiver constructor."},
|
||||
.mode = RQ_REQUIRED},
|
||||
{.case_id = "rust.return-type.usage",
|
||||
.site = {.file = "src/lib.rs",
|
||||
.caller = "lib.real_caller",
|
||||
.needle = "EvidenceTier",
|
||||
.occurrence_index = 5},
|
||||
.relation = "USAGE",
|
||||
.target = {.file = "src/lib.rs",
|
||||
.suffix = "lib.EvidenceTier",
|
||||
.label = "Struct",
|
||||
.declaration_line = 4,
|
||||
.declaration_text = "pub struct EvidenceTier(pub u8);"},
|
||||
.mode = RQ_REQUIRED},
|
||||
{.case_id = "rust.return-type.uses-type",
|
||||
.site = {.file = "src/lib.rs",
|
||||
.caller = "lib.real_caller",
|
||||
.needle = "EvidenceTier",
|
||||
.occurrence_index = 5},
|
||||
.relation = "USES_TYPE",
|
||||
.target = {.file = "src/lib.rs",
|
||||
.suffix = "lib.EvidenceTier",
|
||||
.label = "Struct",
|
||||
.declaration_line = 4,
|
||||
.declaration_text = "pub struct EvidenceTier(pub u8);"},
|
||||
.mode = RQ_REQUIRED},
|
||||
{.case_id = "rust.iterator-closure.receiver",
|
||||
.site = {.file = "src/lib.rs",
|
||||
.caller = "lib.untyped_receiver",
|
||||
|
||||
@@ -1941,6 +1941,12 @@ static const char PL2_THING[] =
|
||||
"sub takes_ref { my $r = \\&own; $r }\n"
|
||||
"sub takes_qualified_ref { keep(\\&My::Root::root_m) }\n"
|
||||
"sub no_absent_ref { my $r = \\&absent; $r }\n"
|
||||
"sub also { return 5; }\n"
|
||||
"sub picks_one { my $f = shift; keep($f ? \\&own : \\&also) }\n"
|
||||
"sub falls_back { my $f = shift; my $r = $f || \\&also; $r }\n"
|
||||
"sub low_or { my $f = shift; my $r = ($f or \\&also); $r }\n"
|
||||
"sub in_parens { my $f = shift; my $r = $f ? (\\&own) : 0; $r }\n"
|
||||
"sub table_entry { my %t = (a => \\&own); $t{a} }\n"
|
||||
"1;\n";
|
||||
|
||||
static const char PL3_THING[] =
|
||||
@@ -2011,6 +2017,18 @@ TEST(resolver_source_perl_invocant_reexports_and_code_references) {
|
||||
"sub own { return 4; }"),
|
||||
SL_REF_AT("code-reference-with-its-package", "lib/My/Thing.pm", "Thing.takes_qualified_ref", "\\&My::Root::root_m", 0, "lib/My/Root.pm", "Root.root_m", "Function", 2,
|
||||
"sub root_m { return 3; }"),
|
||||
SL_USE_AT("conditional-branch-mentions-its-sub", "lib/My/Thing.pm", "Thing.picks_one", "\\&own", 1, "lib/My/Thing.pm", "Thing.own", "Function", 5,
|
||||
"sub own { return 4; }"),
|
||||
SL_USE_AT("other-conditional-branch-mentions-its-sub", "lib/My/Thing.pm", "Thing.picks_one", "\\&also", 0, "lib/My/Thing.pm", "Thing.also", "Function", 19,
|
||||
"sub also { return 5; }"),
|
||||
SL_USE_AT("logical-operand-mentions-its-sub", "lib/My/Thing.pm", "Thing.falls_back", "\\&also", 1, "lib/My/Thing.pm", "Thing.also", "Function", 19,
|
||||
"sub also { return 5; }"),
|
||||
SL_USE_AT("low-precedence-operand-mentions-its-sub", "lib/My/Thing.pm", "Thing.low_or", "\\&also", 2, "lib/My/Thing.pm", "Thing.also", "Function", 19,
|
||||
"sub also { return 5; }"),
|
||||
SL_USE_AT("parentheses-change-nothing", "lib/My/Thing.pm", "Thing.in_parens", "\\&own", 2, "lib/My/Thing.pm", "Thing.own", "Function", 5,
|
||||
"sub own { return 4; }"),
|
||||
SL_REF_AT("table-entry-names-one-sub", "lib/My/Thing.pm", "Thing.table_entry", "\\&own", 3, "lib/My/Thing.pm", "Thing.own", "Function", 5,
|
||||
"sub own { return 4; }"),
|
||||
};
|
||||
static const RQ_Forbidden forbidden[] = {
|
||||
SL_DENY_AT("plain-function-takes-whatever-it-is-given", "lib/My/Thing.pm", "Thing._select", "$_[0]->own", 0),
|
||||
@@ -2018,6 +2036,11 @@ TEST(resolver_source_perl_invocant_reexports_and_code_references) {
|
||||
SL_DENY_AT("second-shift-is-the-second-argument", "lib/My/Thing.pm", "Thing.second_shift", "shift->own", 1),
|
||||
SL_DENY_AT("anonymous-sub-has-its-own-arguments", "lib/My/Thing.pm", "Thing.anon_has_its_own_args", "shift->own", 2),
|
||||
SL_NO_REF_AT("code-reference-to-nothing", "lib/My/Thing.pm", "Thing.no_absent_ref", "\\&absent", 0),
|
||||
SL_NO_REF_AT("conditional-branch-is-no-reference", "lib/My/Thing.pm", "Thing.picks_one", "\\&own", 1),
|
||||
SL_NO_REF_AT("other-conditional-branch-is-no-reference", "lib/My/Thing.pm", "Thing.picks_one", "\\&also", 0),
|
||||
SL_NO_REF_AT("logical-operand-is-no-reference", "lib/My/Thing.pm", "Thing.falls_back", "\\&also", 1),
|
||||
SL_NO_REF_AT("low-precedence-operand-is-no-reference", "lib/My/Thing.pm", "Thing.low_or", "\\&also", 2),
|
||||
SL_NO_REF_AT("parentheses-are-no-reference", "lib/My/Thing.pm", "Thing.in_parens", "\\&own", 2),
|
||||
};
|
||||
ASSERT(sl_check("perl-invocant", ".pm", "package Filler;\nsub f { return 1; }\n1;\n", sources,
|
||||
sizeof(sources) / sizeof(sources[0]), expected,
|
||||
|
||||
Reference in new issue
Block a user