mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-12 09:47:20 +08:00
fix: preserve Cargo context in parallel Rust resolution
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
@@ -693,7 +693,10 @@ bool cbm_pxc_has_cross_lsp(CBMLanguage lang) {
|
||||
|
||||
/* Append cross-file results from `src_out` (allocated in a scratch arena
|
||||
* about to be destroyed) into `dst_calls` (lives in cache_entry->arena),
|
||||
* copying every string field into dst_arena. Skips entries whose
|
||||
* copying every string field into dst_arena. A manifest-qualified Rust
|
||||
* cross-crate result supersedes any earlier result for the exact same source
|
||||
* occurrence: the Cargo member path is stronger evidence than a same-named
|
||||
* local fallback. Skips entries whose
|
||||
* (kind, caller_qn, callee_qn, source span) is already present — avoids
|
||||
* inflating the array with cross-file duplicates without conflating distinct
|
||||
* same-named occurrences. For an exact duplicate, retain the higher-confidence
|
||||
@@ -715,6 +718,39 @@ static void pxc_append_results(CBMArena *dst_arena, CBMResolvedCallArray *dst_ca
|
||||
cbm_arena_init(&keys);
|
||||
CBMHashTable *seen = cbm_ht_create((uint32_t)(dst_calls->count + src_out->count + 1));
|
||||
|
||||
/* Per-file Rust resolution may already have confidently matched the tail
|
||||
* of `member::call()` to a same-named local function. Once the cross pass
|
||||
* proves that `member` is a declared Cargo workspace member, replace only
|
||||
* records for that exact parser occurrence before constructing the dedup
|
||||
* table. This preserves distinct same-named calls at other spans while
|
||||
* preventing the stale local result from out-ranking manifest evidence. */
|
||||
for (int j = 0; j < src_out->count; j++) {
|
||||
const CBMResolvedCall *src = &src_out->items[j];
|
||||
if (!src->strategy || strcmp(src->strategy, "lsp_cross_crate") != 0 || !src->caller_qn ||
|
||||
!src->callee_qn || src->site_end_byte <= src->site_start_byte) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < dst_calls->count; i++) {
|
||||
CBMResolvedCall *dst = &dst_calls->items[i];
|
||||
if (!dst->caller_qn || dst->kind != src->kind ||
|
||||
dst->site_start_byte != src->site_start_byte ||
|
||||
dst->site_end_byte != src->site_end_byte ||
|
||||
dst->source_origin != src->source_origin ||
|
||||
strcmp(dst->caller_qn, src->caller_qn) != 0) {
|
||||
continue;
|
||||
}
|
||||
dst->caller_qn = cbm_arena_strdup(dst_arena, src->caller_qn);
|
||||
dst->callee_qn = cbm_arena_strdup(dst_arena, src->callee_qn);
|
||||
dst->strategy = cbm_arena_strdup(dst_arena, src->strategy);
|
||||
dst->confidence = src->confidence;
|
||||
dst->reason = src->reason ? cbm_arena_strdup(dst_arena, src->reason) : NULL;
|
||||
dst->kind = src->kind;
|
||||
dst->site_start_byte = src->site_start_byte;
|
||||
dst->site_end_byte = src->site_end_byte;
|
||||
dst->source_origin = src->source_origin;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < dst_calls->count; i++) {
|
||||
const CBMResolvedCall *rc = &dst_calls->items[i];
|
||||
if (rc->caller_qn && rc->callee_qn) {
|
||||
@@ -1191,8 +1227,8 @@ void cbm_pxc_dispatch_file(CBMLanguage lang, CBMFileResult *result, const char *
|
||||
free(filtered);
|
||||
}
|
||||
|
||||
static bool pxc_build_rust_manifest(const cbm_pipeline_ctx_t *ctx, CBMArena *marena,
|
||||
CBMCargoManifest *out_m) {
|
||||
bool cbm_pxc_build_rust_manifest(const cbm_pipeline_ctx_t *ctx, CBMArena *marena,
|
||||
CBMCargoManifest *out_m) {
|
||||
if (!ctx || !ctx->repo_path || !marena || !out_m)
|
||||
return false;
|
||||
char path[1024];
|
||||
@@ -1234,7 +1270,7 @@ int cbm_pipeline_pass_lsp_cross(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *
|
||||
bool have_manifest = false;
|
||||
if (have_rust) {
|
||||
cbm_arena_init(&cargo_arena);
|
||||
have_manifest = pxc_build_rust_manifest(ctx, &cargo_arena, &cargo_manifest);
|
||||
have_manifest = cbm_pxc_build_rust_manifest(ctx, &cargo_arena, &cargo_manifest);
|
||||
cbm_pxc_set_rust_manifest(have_manifest ? &cargo_manifest : NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -169,10 +169,14 @@ static inline CBMTypeRegistry *cbm_pxc_registry_for_lang(const CBMCrossLspRegist
|
||||
}
|
||||
}
|
||||
|
||||
/* Borrow the (thread-local) Rust Cargo manifest the cross-file LSP pass set for
|
||||
* cross-crate (#56) routing. The Tier-2 prebuilt Rust resolve reads it so it sees
|
||||
* exactly what the per-file fallback (cbm_pxc_run_one) would on the same thread. */
|
||||
/* Build and borrow the Rust Cargo manifest used for cross-crate (#56) routing.
|
||||
* The manifest owns strings in manifest_arena; callers keep that arena alive
|
||||
* until every resolver worker has joined. Each worker must install the shared
|
||||
* immutable pointer in its own TLS slot before dispatch and clear it afterward. */
|
||||
struct CBMCargoManifest;
|
||||
bool cbm_pxc_build_rust_manifest(const cbm_pipeline_ctx_t *ctx, CBMArena *manifest_arena,
|
||||
struct CBMCargoManifest *out_manifest);
|
||||
void cbm_pxc_set_rust_manifest(const struct CBMCargoManifest *manifest);
|
||||
const struct CBMCargoManifest *cbm_pxc_get_rust_manifest(void);
|
||||
|
||||
/* Run the cross-file LSP resolver for non-TS languages. Appends
|
||||
|
||||
@@ -70,6 +70,7 @@ enum { PP_CSHARP_M_PREFIX_LEN = 2 };
|
||||
#include "pipeline/pipeline_internal.h"
|
||||
#include "pipeline/pass_lsp_cross.h" /* cbm_pxc_* helpers for fused cross-file LSP */
|
||||
#include "pipeline/lsp_resolve.h"
|
||||
#include "lsp/rust_cargo.h"
|
||||
#include "helpers.h" /* cbm_kind_in_set_free_cache — per-worker-thread cache teardown */
|
||||
#include "pipeline/worker_pool.h"
|
||||
#include "foundation/compat.h"
|
||||
@@ -1398,6 +1399,11 @@ typedef struct {
|
||||
* Stored as CBMCrossLspRegistries* (typedef from pass_lsp_cross.h). */
|
||||
CBMCrossLspRegistries *cross_registries;
|
||||
|
||||
/* Parsed once on the coordinator thread and borrowed read-only by resolve
|
||||
* workers. The pointer is installed into each worker's TLS slot so Rust's
|
||||
* manifest-aware cross-file resolver sees the same Cargo context. */
|
||||
const CBMCargoManifest *rust_manifest;
|
||||
|
||||
/* F4: LAZILY-built shared Rust registry (built ONCE, on the first NULL-filter
|
||||
* rust file — the ~all_defs amplifier files). Not eager: repos whose rust files
|
||||
* all filter to subsets never pay the O(all_defs) build + multi-GB RSS. Built
|
||||
@@ -2944,6 +2950,8 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
|
||||
resolve_ctx_t *rc = ctx_ptr;
|
||||
resolve_worker_state_t *ws = &rc->workers[worker_id];
|
||||
|
||||
cbm_pxc_set_rust_manifest(rc->rust_manifest);
|
||||
|
||||
if (!ws->local_edge_buf) {
|
||||
ws->local_edge_buf =
|
||||
cbm_gbuf_new_shared_ids(rc->project_name, rc->repo_path, rc->shared_ids);
|
||||
@@ -3009,6 +3017,8 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
|
||||
* a mixed-source-root Java↔Kotlin site remains unresolved, so JVM
|
||||
* callers run whenever either kind of site exists. */
|
||||
bool jvm_cross_lsp = (lang == CBM_LANG_JAVA || lang == CBM_LANG_KOTLIN);
|
||||
bool rust_workspace_cross_lsp =
|
||||
(lang == CBM_LANG_RUST && rc->rust_manifest && rc->rust_manifest->member_count > 0);
|
||||
int call_reference_sites = pp_call_reference_site_count(result, lang);
|
||||
int semantic_sites = result->calls.count + call_reference_sites;
|
||||
int qualified_lsp_sites = pp_qualified_lsp_site_count(result);
|
||||
@@ -3016,7 +3026,8 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
|
||||
bool cross_lsp_eligible =
|
||||
(rc->all_defs && rc->def_count > 0 && cbm_pxc_has_cross_lsp(lang) &&
|
||||
(semantic_sites > 0 || pending_lsp_site) &&
|
||||
(jvm_cross_lsp || pending_lsp_site || qualified_lsp_sites < semantic_sites) &&
|
||||
(jvm_cross_lsp || rust_workspace_cross_lsp || pending_lsp_site ||
|
||||
qualified_lsp_sites < semantic_sites) &&
|
||||
!is_generated);
|
||||
|
||||
/* Skip files with nothing else to resolve and no cross-LSP work. */
|
||||
@@ -3187,6 +3198,7 @@ static void resolve_worker(int worker_id, void *ctx_ptr) {
|
||||
* into dead TLS and are never retired, so a later cross-thread free can
|
||||
* never bring their refcount to zero (leak). Retiring them here releases
|
||||
* each page as its final chunk returns. */
|
||||
cbm_pxc_set_rust_manifest(NULL);
|
||||
cbm_destroy_thread_parser();
|
||||
cbm_slab_destroy_thread();
|
||||
cbm_service_pattern_cache_end();
|
||||
@@ -3213,6 +3225,25 @@ int cbm_parallel_resolve(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *files,
|
||||
}
|
||||
memset(workers, 0, (size_t)worker_count * sizeof(resolve_worker_state_t));
|
||||
|
||||
bool have_rust = false;
|
||||
for (int i = 0; i < file_count; i++) {
|
||||
if (result_cache[i] && files[i].language == CBM_LANG_RUST) {
|
||||
have_rust = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CBMArena rust_manifest_arena;
|
||||
CBMCargoManifest rust_manifest;
|
||||
bool rust_manifest_arena_live = false;
|
||||
const CBMCargoManifest *rust_manifest_ptr = NULL;
|
||||
if (have_rust) {
|
||||
cbm_arena_init(&rust_manifest_arena);
|
||||
rust_manifest_arena_live = true;
|
||||
if (cbm_pxc_build_rust_manifest(ctx, &rust_manifest_arena, &rust_manifest)) {
|
||||
rust_manifest_ptr = &rust_manifest;
|
||||
}
|
||||
}
|
||||
|
||||
resolve_ctx_t rc = {
|
||||
.files = files,
|
||||
.file_count = file_count,
|
||||
@@ -3230,6 +3261,7 @@ int cbm_parallel_resolve(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *files,
|
||||
.def_modules = def_modules,
|
||||
.module_def_index = module_def_index,
|
||||
.cross_registries = cross_registries,
|
||||
.rust_manifest = rust_manifest_ptr,
|
||||
};
|
||||
atomic_init(&rc.next_file_idx, 0);
|
||||
atomic_init(&rc.lsp_cross_processed, 0);
|
||||
@@ -3255,6 +3287,9 @@ int cbm_parallel_resolve(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *files,
|
||||
rc.rust_shared_arena_live = false;
|
||||
}
|
||||
cbm_mutex_destroy(&rc.rust_shared_mu);
|
||||
if (rust_manifest_arena_live) {
|
||||
cbm_arena_destroy(&rust_manifest_arena);
|
||||
}
|
||||
|
||||
/* Sub-phase: Merge all local edge bufs into main gbuf (SEQUENTIAL) */
|
||||
CBM_PROF_START(t_resolve_merge);
|
||||
|
||||
Reference in New Issue
Block a user