fix(pipeline): exclude project identity from service patterns

Signed-off-by: DavidHLP <lysf15520112973@163.com>
This commit is contained in:
DavidHLP
2026-11-09 20:55:52 -08:00
parent f25f8b3dcd
commit cdb7a293b0
6 changed files with 55 additions and 24 deletions
+11
View File
@@ -1170,6 +1170,17 @@ cbm_svc_kind_t cbm_service_pattern_match(const char *resolved_qn) {
return result;
}
cbm_svc_kind_t cbm_service_pattern_match_in_project(const char *resolved_qn, const char *name,
const char *project_name) {
if (resolved_qn && project_name && project_name[0]) {
size_t len = strlen(project_name);
if (strncmp(resolved_qn, project_name, len) == 0 && resolved_qn[len] == '.') {
resolved_qn += len + 1;
}
}
return cbm_service_pattern_match_named(resolved_qn, name);
}
cbm_svc_kind_t cbm_service_pattern_match_named(const char *resolved_qn, const char *name) {
if (!resolved_qn || !name) {
return cbm_service_pattern_match(resolved_qn);
+3
View File
@@ -35,6 +35,9 @@ void cbm_service_patterns_init(void);
* "project.venv.requests.api.get"). Import-alias transparent. */
cbm_svc_kind_t cbm_service_pattern_match(const char *resolved_qn);
cbm_svc_kind_t cbm_service_pattern_match_named(const char *resolved_qn, const char *name);
/* For graph-qualified symbols: project identity is not library evidence. */
cbm_svc_kind_t cbm_service_pattern_match_in_project(const char *resolved_qn, const char *name,
const char *project_name);
/* True for a bare, unqualified call to the native `fetch()` API. Deliberately
* NOT part of the substring tables above: those are matched unconditionally
+11 -5
View File
@@ -852,8 +852,11 @@ static bool emit_classified_edge(cbm_pipeline_ctx_t *ctx, const CBMCall *call,
const char **imp_keys, const char **imp_vals, int imp_count,
bool suppress_plain_calls, const char *route_mount,
CBMLanguage lang) {
cbm_svc_kind_t svc =
cbm_service_pattern_match_named(res->qualified_name, target ? target->name : NULL);
cbm_svc_kind_t svc = cbm_service_pattern_match_in_project(
res->qualified_name, target ? target->name : NULL,
target && res->qualified_name && strcmp(target->qualified_name, res->qualified_name) == 0
? ctx->project_name
: NULL);
if (svc == CBM_SVC_ROUTE_REG && route_reg_path(call, lang) != NULL) {
return handle_route_registration(ctx, call, source, module_qn, imp_keys, imp_vals,
imp_count, route_mount, lang);
@@ -1387,12 +1390,15 @@ static int resolve_single_call(cbm_pipeline_ctx_t *ctx, CBMCall *call, const CBM
* the missing target must NOT drop the call — otherwise no HTTP_CALLS edge
* is written and cross-repo matching finds nothing (#523). Emit directly
* when the call carries a URL/topic first argument. */
if (calls_emit_service_call(ctx, call, source_node,
cbm_service_pattern_match(res.qualified_name), &res, evidence)) {
const cbm_gbuf_node_t *target_node = cbm_gbuf_find_by_qn(ctx->gbuf, res.qualified_name);
if (calls_emit_service_call(
ctx, call, source_node,
cbm_service_pattern_match_in_project(res.qualified_name, NULL,
target_node ? ctx->project_name : NULL),
&res, evidence)) {
return SKIP_ONE;
}
const cbm_gbuf_node_t *target_node = cbm_gbuf_find_by_qn(ctx->gbuf, res.qualified_name);
if (!target_node || source_node->id == target_node->id) {
return 0;
}
+23 -18
View File
@@ -2866,12 +2866,15 @@ static void emit_trpc_edge(cbm_gbuf_t *gbuf, const cbm_gbuf_node_t *source, cons
static bool emit_service_edge(cbm_gbuf_t *gbuf, const cbm_gbuf_node_t *source,
const cbm_gbuf_node_t *target, const CBMCall *call,
const cbm_resolution_t *res, const char *module_qn,
const cbm_registry_t *registry, const cbm_gbuf_t *main_gbuf,
const char **imp_keys, const char **imp_vals, int imp_count,
bool suppress_plain_calls, const char *route_mount,
CBMLanguage lang) {
cbm_svc_kind_t svc =
cbm_service_pattern_match_named(res->qualified_name, target ? target->name : NULL);
const char *project_name, const cbm_registry_t *registry,
const cbm_gbuf_t *main_gbuf, const char **imp_keys,
const char **imp_vals, int imp_count, bool suppress_plain_calls,
const char *route_mount, CBMLanguage lang) {
cbm_svc_kind_t svc = cbm_service_pattern_match_in_project(
res->qualified_name, target ? target->name : NULL,
target && res->qualified_name && strcmp(target->qualified_name, res->qualified_name) == 0
? project_name
: NULL);
const char *arg = call->first_string_arg;
/* Also detect route registration by callee name suffix alone (handles unresolved
@@ -3620,8 +3623,8 @@ static void resolve_file_calls(resolve_ctx_t *rc, resolve_worker_state_t *ws, CB
.strategy = "service_pattern"};
site_evidence->calls_emitted |=
emit_service_edge(ws->local_edge_buf, source_node, source_node, call, &svc_res,
module_qn, rc->registry, rc->main_gbuf, imp_keys, imp_vals,
imp_count, false, route_mount, lang);
module_qn, rc->project_name, rc->registry, rc->main_gbuf,
imp_keys, imp_vals, imp_count, false, route_mount, lang);
continue;
}
}
@@ -3643,8 +3646,8 @@ static void resolve_file_calls(resolve_ctx_t *rc, resolve_worker_state_t *ws, CB
site_evidence->candidate_qn = count == SKIP_ONE ? target->qualified_name : NULL;
site_evidence->calls_emitted |=
emit_service_edge(ws->local_edge_buf, source_node, target, call, &selected,
module_qn, rc->registry, rc->main_gbuf, imp_keys,
imp_vals, imp_count, false, route_mount, lang);
module_qn, rc->project_name, rc->registry, rc->main_gbuf,
imp_keys, imp_vals, imp_count, false, route_mount, lang);
ws->calls_resolved++;
}
continue;
@@ -3680,8 +3683,8 @@ static void resolve_file_calls(resolve_ctx_t *rc, resolve_worker_state_t *ws, CB
* route/HTTP/service classification is unchanged. */
site_evidence->calls_emitted |=
emit_service_edge(ws->local_edge_buf, source_node, source_node, call, &fake_res,
module_qn, rc->registry, rc->main_gbuf, imp_keys, imp_vals,
imp_count, true, route_mount, lang);
module_qn, rc->project_name, rc->registry, rc->main_gbuf,
imp_keys, imp_vals, imp_count, true, route_mount, lang);
} else if (cbm_service_pattern_is_global_fetch(call->callee_name)) {
/* Native `fetch()` (#856): only the global API once resolution
* has failed to find a local/imported `fetch`. Call the low-level
@@ -3790,9 +3793,10 @@ static void resolve_file_calls(resolve_ctx_t *rc, resolve_worker_state_t *ws, CB
(u[0] == '/' || strstr(u, "://") != NULL ||
(psvc == CBM_SVC_ASYNC && strlen(u) > PP_ESC_SPACE));
if (url_or_topic) {
site_evidence->calls_emitted |= emit_service_edge(
ws->local_edge_buf, source_node, NULL, call, &res, module_qn, rc->registry,
rc->main_gbuf, imp_keys, imp_vals, imp_count, false, route_mount, lang);
site_evidence->calls_emitted |=
emit_service_edge(ws->local_edge_buf, source_node, NULL, call, &res,
module_qn, rc->project_name, rc->registry, rc->main_gbuf,
imp_keys, imp_vals, imp_count, false, route_mount, lang);
ws->calls_resolved++;
}
}
@@ -3800,9 +3804,10 @@ static void resolve_file_calls(resolve_ctx_t *rc, resolve_worker_state_t *ws, CB
}
site_evidence->candidate_qn = target_node->qualified_name;
_rc_t0 = extract_now_ns();
site_evidence->calls_emitted |= emit_service_edge(
ws->local_edge_buf, source_node, target_node, call, &res, module_qn, rc->registry,
rc->main_gbuf, imp_keys, imp_vals, imp_count, drop_plain_call, route_mount, lang);
site_evidence->calls_emitted |=
emit_service_edge(ws->local_edge_buf, source_node, target_node, call, &res, module_qn,
rc->project_name, rc->registry, rc->main_gbuf, imp_keys, imp_vals,
imp_count, drop_plain_call, route_mount, lang);
atomic_fetch_add_explicit(&rc->time_ns_rc_emit, extract_now_ns() - _rc_t0,
memory_order_relaxed);
ws->calls_resolved++;
+6
View File
@@ -184,6 +184,12 @@ TEST(infrascan_service_pattern_match_rejects_ids_inside_words) {
};
ASSERT_EQ(svc_case_mismatches(cases), 0);
ASSERT_EQ(cbm_service_pattern_match_named("proj.worker.run(_:Alamofire)", "run"), CBM_SVC_NONE);
ASSERT_EQ(cbm_service_pattern_match_in_project("Dio.src.nav.navigateTo", "navigateTo", "Dio"),
CBM_SVC_NONE);
ASSERT_EQ(cbm_service_pattern_match_in_project("Dio.src.axios.get", "get", "Dio"),
CBM_SVC_HTTP);
ASSERT_EQ(cbm_service_pattern_match_in_project("axios.get", NULL, "Dio"), CBM_SVC_HTTP);
ASSERT_EQ(cbm_service_pattern_match_in_project("Dio.client.get", "get", "Di"), CBM_SVC_HTTP);
ASSERT_EQ(cbm_service_pattern_match_named("proj.Alamofire.request(_:String)", "request"),
CBM_SVC_HTTP);
/* A field whose name contains a call keeps its complete QN. */
+1 -1
View File
@@ -16065,7 +16065,7 @@ TEST(pipeline_arg_url_skips_client_navigation) {
free(saved_single);
FAIL("save environment");
}
char tmp[256] = "/tmp/cbm_arg_url_nav_XXXXXX";
char tmp[256] = "/tmp/cbm_arg_url_nav_Dio_XXXXXX";
if (!cbm_mkdtemp(tmp)) {
free(saved_workers);
free(saved_single);