用途
本技能提供关于 GitNexus 中 pdg_query MCP 工具及其读取的控制/数据依赖边的专家知识。这些边属于可选的 --pdg 程序依赖层。在修改 gitnexus/src/mcp/local/local-backend.ts(_pdgQueryImpl)或 pdg_query 工具定义之前,或在解释 pdg_query 结果时,应先阅读本技能。
适用场景
- “这条语句在什么条件下运行?”(守卫谓词)。
- “这个变量在函数内流向哪里?”(定义→使用)。
- 守卫子句发现(提前返回守卫,涵盖 #559 启发式)。
- 扩展或审查 pdg_query / CDG / REACHING_DEF 读取路径。
- 调试空或异常的 pdg_query 结果。
分层基础(构建顺序)
pdg_query 运行在与污点分析相同的图上。每一层都通过 --pdg 显式启用;默认的 analyze 运行不记录任何这些层(字节级一致)。
- L1 CFG:每函数基本块 + 控制流边(M1 #2081)
- L2 REACHING_DEF:GEN/KILL 定义→使用数据依赖(纯求解器)(M2 #2082)
- L5 CDG:Ferrante 控制依赖(后支配者)(M5 #2085)
这三者都是单一 CodeRelation 表中的 BasicBlock → BasicBlock 边(以 type 属性为键)。不存在 Function → BasicBlock 边。
两种模式
- pdg_query({ mode: 'controls', target }) — CDG。对于锚定函数,每条边为:控制谓词块 → 依赖块,分支方向在 reason 中('T' = 谓词的真/进入分支,'F' = 假/落空分支)。进入提前返回/抛出块的边会标记 guard: true。
- pdg_query({ mode: 'flows', target, variable? }) — REACHING_DEF 定义→使用边;variable 过滤到单个绑定。
target 为必填项——文件路径或符号/函数名(解析方式类似 context())。没有无锚点模式(见下文)。
修正后的守卫子句 Cypher
RFC #567 §2 的形式([:CDG {label:'F'}])无法按原样运行。边是单一 CodeRelation 表 type 属性的值,分支方向在 reason 中,而不是 label 列:
MATCH (pred:BasicBlock)-[r:CodeRelation {type: 'CDG'}]->(dep:BasicBlock) WHERE dep.text STARTS WITH 'return' OR dep.text STARTS WITH 'throw' RETURN pred.startLine, r.reason AS branch, dep.startLine, dep.text
r.reason 是谓词到达提前退出时所取的方向。对于 if (!ok) return;,return 走谓词的真分支('T'),受保护的主体走假分支('F')——极性取决于守卫,因此不要硬编码某一种方向。
关键注意事项
- 始终锚定 + LIMIT 限制。LadybugDB 没有关系属性索引,因此无锚点的 [:CDG*]/[:REACHING_DEF*] 路径扫描是无界的。pdg_query 要求 target 并限制分页;原始 cypher 调用者必须自行锚定文件 id 前缀或符号范围。
- BasicBlock↔符号连接是重建的。没有 Function→BasicBlock 边:块通过其 id 前缀(BasicBlock:<file>:<fnStartLine>:…)加上符号范围内的 startLine 来匹配。BasicBlock 的 startLine 是 1 基,而符号节点的 startLine/endLine 是 0 基,因此两个边界都偏移 +1([symStart+1, symEnd+1]):上界 +1 保留函数最后一行的守卫/定义/使用,下界 +1 排除紧邻上一行相邻函数的块。同行/嵌套函数锚定较粗。
- 无 PDG 层 ⇒ 返回提示而非错误。如果仓库未用 --pdg 索引,工具返回 { results: [], note: "no PDG layer …" }(对 RepoMeta.pdg.maxCdgEdgesPerFunction / maxReachingDefEdgesPerFunction 的廉价元探测)。
- CDG 标签在 M5/M6 中是二元的。每个 switch-case 分支都是 'T';每个 case 的条件尚未区分。
- 仅过程内。跨函数流是污点分析的领域(explain)。
镜像而非分叉
_pdgQueryImpl 是 _explainImpl 的前半部分(WAL 包装器、元无层探测、限制验证、resolveSymbolCandidates 锚定),只是用 CDG/REACHING_DEF 替代 TAINTED——并且没有污点分析的路径编解码 / 过程间 TAINT_PATH 机制。复用这些共享辅助函数;不要重新实现它们。