GitNexus PDG 查询实战:用 `pdg_query` 挖掘控制依赖与数据依赖(CDG / REACHING_DEF)

发布时间:2026/9/9 13:17:34
GitNexus PDG 查询实战:用 `pdg_query` 挖掘控制依赖与数据依赖(CDG / REACHING_DEF) GitNexus PDG 查询实战用pdg_query挖掘控制依赖与数据依赖CDG / REACHING_DEF【免费下载链接】GitNexusGitNexus: The Zero-Server Code Intelligence Engine - GitNexus is a client-side knowledge graph creator that runs entirely in your browser. Drop in a git repository (Github, Gitlab, Azure, Local) or ZIP file, and get an interactive knowledge graph with a built in Graph RAG Agent. Perfect for code exploration项目地址: https://gitcode.com/GitHub_Trending/gi/GitNexus本指南围绕 GitNexus 中由--pdg可选项构建的程序依赖图Program Dependence GraphPDG查询面展开系统讲解pdg_queryMCP 工具的两种模式controls控制依赖 /flows数据依赖、BasicBlock→BasicBlock 的边存储模型、符号锚定规则与行号偏移陷阱以及可直接复制运行的 Cypher 与命令行示例。读完你不仅能回答这条语句在什么条件下执行这个变量在函数内流向了哪里这类代码理解问题还能排查为什么pdg_query返回空结果并安全地扩展该读取路径。pdg_query与它读取的 CFG / REACHING_DEF / CDG 依赖边是 GitNexus 的 opt-in--pdg程序依赖层。本文档主体来自技能包 gitnexus-pdg-query SKILL主仓库同一份文档位于 gitnexus/skills/gitnexus-pdg-query.md并配合仓库源码、工具定义与数据模型文档给出实现级证据。适用场景什么时候该用 PDG 查询PDG 查询解决的是**单函数内部的依赖因果**问题典型问题包括守卫条件这条语句在什么条件下才会执行Under what condition does this statement run?——返回控制它的谓词块。数据流这个变量在函数内部流向哪里Where does this variable flow inside the function?——返回 def→use 链。Guard-clause 发现提前return/throw的守卫子句识别取代并涵盖了旧 #559 启发式规则。扩展或审查读取路径修改或评审pdg_query/ CDG / REACHING_DEF 的实现。排查异常结果调试空结果或不符合预期的pdg_query返回。在做这些事之前应先读完本文档再动手接触 local-backend.ts 里的_pdgQueryImpl实现约 L4925或pdg_query工具定义见 tools.ts L696 起或向用户解释某个pdg_query结果。先决条件只有--pdg索引才记录依赖层PDG 查询运行在与污点分析taint同一张图之上但每一条依赖层都是可选项opt-in默认的gitnexus analyze运行不记录任何一层输出保持字节级一致byte-identical。必须显式开启gitnexus analyze --pdg在 CLI 配置解析中pdg被建模为一个布尔开关见 analyze-config.ts 的pdg: { target: pdg, kind: boolean }并透传到run-analyze.ts的resolvePdgConfig见 run-analyze.ts。该函数会把一组默认上限写进仓库元数据RepoMeta.pdg形成该层是否存在的判定戳stampmaxReachingDefEdgesPerFunction默认DEFAULT_PDG_MAX_REACHING_DEF_EDGES_PER_FUNCTION 4000emit.tsmaxCdgEdgesPerFunction默认DEFAULT_PDG_MAX_CDG_EDGES_PER_FUNCTION 5000emit.ts。pdgStampForModepdg-impact.ts读取该戳某模式对应上限存在即认为该层已记录否则判定为无该层。由于 CDG 出现在 M5#2085而 REACHING_DEF 出现在 M2#2082pdgModeMismatch会在旧版--pdg索引上自动触发一次全量回写writeback把缺的 CDG 边补齐无需--force。分层构建次序layered substrate依赖层按既定次序逐层构建pdg_query读取的只是最终落库的三层产物层名称内容来源阶段L1CFG每函数的 BasicBlock 控制流边M1 #2081L2REACHING_DEFGEN/KILL def→use 数据依赖纯求解器M2 #2082L5CDGFerrante 式控制依赖基于后支配树 post-dominatorsM5 #2085对应的实现模块均位于 gitnexus/src/core/ingestion/cfg/ 目录cfg-builder.tsCFG 构建、reaching-defs.ts到达定义求解、control-dependence.ts与post-dominators.tsCDG。三种依赖在单张CodeRelation表中统一以BasicBlock→BasicBlock边存储靠边的type属性区分CFG/REACHING_DEF/CDG不存在Function→BasicBlock边详情见后文符号↔块连接是重建的。pdg_query工具的两种模式与参数pdg_query是控制/数据依赖的专用消费方被标记为只读工具列入 read-only-policy.ts。完整工具定义见 tools.ts参数类型必填说明modestring✅controls 控制依赖CDG什么条件门控 Xflows 数据依赖REACHING_DEF变量 Y 流向哪里targetstring✅锚点文件路径接受后缀匹配如src/handlers/run.ts或符号/函数名像context()那样解析。PDG 查询永远必须锚定variablestring否仅flows模式把 REACHING_DEF 结果限制到某个源码级变量名limitinteger否单页最大返回边数。默认PDG_QUERY_DEFAULT_LIMIT 50上限PDG_QUERY_MAX_LIMIT 200tools.ts。超出范围直接报错而非截断repostring否索引仓库名或路径只有一个仓库时可省略响应中total报告完整匹配数truncated: true表示当前页被截断。两种模式返回结构不同见_pdgQueryImpl的结果组装local-backend.tscontrols模式CDG按锚定函数返回每条边{ functionLine: 18, controller: { line: 22 }, dependent: { line: 23, text: throw new Error(...) }, label: T, guard: true }controller 控制谓词块BasicBlockdependent 被控制块。label源码里对应边上的reason 分支方向T表示谓词的真/执行臂true/taken armF表示假/落空臂false/fall-through。指向提前return/throw/continue/break块的边会被打上guard: true。实现依据_pdgQueryImpl里对dstText的正则判定/^\s*(return|throw|continue|break)\b/local-backend.ts即取代了旧 #559 guard 启发式。flows模式REACHING_DEF def→use{ functionLine: 18, variable: token, def: { line: 30 }, use: { line: 31, text: auth(token) } }def 定义块use 使用块variable名从边的reason解码得到decodeReachingDefReason。传入variable时后端会生成r.reason $variable OR r.reason STARTS WITH $variablePrefix的过滤子句local-backend.ts。注意mode的 JSON-schema enum 对 MCP 客户端只是建议后端仍会强制校验——非法mode返回Invalid mode: expected controls or flows缺少target返回pdg_query requires a targetlocal-backend.ts。limit因 LadybugDB 不支持参数化 LIMIT会被校验为整数后内插进查询local-backend.ts。正确的 Guard-Clause 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这份查询同样被 GitNexus 自己的数据模型资源文档收录为guard_clauses示例见 resources.ts。关键语义r.reason是谓词为到达该提前退出而采取的分支方向。对if (!ok) return;return挂在谓词的真臂T上而被保护的主体挂在假臂F上——极性取决于 guard 怎么写不要硬编码单一方向。M5/M6 中 CDG 标签是二值的switch的每个 case 分派臂都是T逐 case 的条件尚未被区分。锚定模型为什么永远要带 target以及行号偏移陷阱pdg_query永远锚定anchored没有无锚点模式原因是 LadybugDB 没有关系属性索引rel-property index一个未锚定的[:CDG*]/[:REACHING_DEF*]路径扫描是无界的。锚定由resolveBlockAnchorlocal-backend.ts完成分两类文件类 target含/或看起来像路径直接生成a.id STARTS WITH $idPrefix OR a.filePath $targetPath OR a.filePath ENDS WITH $targetSuffix子句其中idPrefix为BasicBlock:file:。后缀匹配使vuln.ts能命中src/vuln.ts。符号名 target先经resolveSymbolCandidates与context()同一条解析路径解析——未知名返回 not-found歧义名返回带totalCandidates的排序候选列表与candidatesTruncated标志命中后用 BasicBlock id 前缀 startLine落在符号行区间内做块级过滤。BasicBlock 的 ID 模板与行号基准BasicBlock 节点 ID 模板是emit.ts 与 resources.tsBasicBlock:filePath:fnStartLine:fnStartCol:blockIndex两个关键坑文档称之为load-bearingBasicBlock↔符号连接是重建的因为没有Function→BasicBlock边块靠 id-prefix startLine命中。BasicBlock 的startLine是 1-based而符号节点的startLine/endLine是 0-basedtree-sitter 行号因此上下界都需1即[symStart1, symEnd1]上界1保证函数最后一行上的 guard/def/use 不被丢掉下界1排除紧邻上一行的相邻函数块。实现见 local-backend.ts其中toOneBasedLine是专门的 0→1 转换器。同一行内多个函数如{ a: () x(), b: () y() }或嵌套函数因此只能粗糙锚定。列号参与消歧两个函数共享同一起始行时fnStartCol让每个函数的块索引从 0 重新编号而不冲突types.ts否则块 ID 碰撞会导致addNode的 first-writer-wins 静默丢块。此外BasicBlock 的 ID 中filePath可能自身含:如 Windows 盘符所以fnLineOf从右侧切分fnLine是倒数第 3 段见 pdg-impact.ts。无 PDG 层时的行为note不是 error如果仓库没有用--pdg索引工具不会抛错而是返回带说明的空结果{ mode: controls, results: [], total: 0, note: no PDG layer — run gitnexus analyze --pdg to record CDG edges for this repo }后端先做一次廉价元数据探测通过RepoMeta.pdg.maxCdgEdgesPerFunctioncontrols或maxReachingDefEdgesPerFunctionflows判断该层是否存在local-backend.ts存在才落库扫描。这里区分两种说明文案local-backend.ts元数据戳可读且明确缺层 → 确定性NO_PDG_NOTE上面那条元数据不可读且锚定查询 0 行 → 再做一次受限的全局探针查询若整库该边类型为 0 行返回不确定版notePDG_LAYER_UNKNOWN_NOTE——因为层真实存在但全是线性函数、确实没有边与层缺失长得一模一样不能武断断言缺失#2188 review。若探针有行则安静返回空 results 即可。同理explaintaint 消费方与pdg_query的行为是镜像的CLI 侧的 AI 上下文ai-context.ts只在索引带--pdg时才向模型广告这两个工具避免在非 pdg 索引上产生噪音。那些承重墙级别的坑Gotchas永远锚定 LIMIT 兜底LadybugDB 无关系属性索引未锚定的[:CDG*]/[:REACHING_DEF*]路径扫描无界。pdg_query强制target并做分页限制直接写裸cypher的调用方必须自己用文件 id-prefix 或符号行区间锚定。BasicBlock↔符号 join 是重建的无Function→BasicBlock边靠 ID 前缀 1-basedstartLine落在 0-based 符号区间平移1后的[symStart1, symEnd1]窗口内见上文。同行/嵌套函数锚定粗糙。无 PDG 层 ⇒ note 而非 error见上节两种文案与探针逻辑。CDG 标签在 M5/M6 是二值的switch每个 case 臂都是T逐 case 条件尚未区分。仅函数内intra-procedural跨函数流是 taint 的领域——用explainTAINTED / TAINT_PATH 边而不是pdg_query。CDG/REACHING_DEF 刻意不在impact()的遍历里pdg_query是这些边的专用消费方tools.ts。变量过滤同时匹配新旧两种 reason 编码REACHING_DEF 的reason要么是裸变量名legacy要么是name|1:def:use;...版本化注解FU-B-2格式见 reaching-def-reason-codec.ts。variable过滤子句用或STARTS WITH name|同时覆盖两者源码标识符不含|所以该前缀匹配是精确的ab|…不会误匹配abc|…。返回时统一用decodeReachingDefReason还原成裸变量名。共享实现骨架Mirror, dont fork从源码结构看_pdgQueryImpl是_explainImpl的前半段镜像SKILL.md Mirror, dont fork 一节两者共享同一组前台辅助pdgQuery公共方法与explain一样先套一层 WAL 容错包装捕获isWalCorruptionError并返回recoverySuggestion见 local-backend.ts。复用这些共享部件不要重新实现WAL wrapperpdgQuery→_pdgQueryImpl的 try/catch isWalCorruptionError恢复建议meta no-layer 探测pdgStampForMode(repo.lbugPath, mode)同一底层读取也被pdgLayerStatus用于 impactlimit 校验Number.isInteger[1, PDG_QUERY_MAX_LIMIT]与 EXPLAIN_* 上限语义一致锚定解析resolveBlockAnchor(repo, target, pdg_query)的 not-found / ambiguous 早退 anchorClause生成。区别仅在边类型CDG / REACHING_DEF 替代 TAINTED且完全没有 taint 的路径编解码与跨过程TAINT_PATH机制。声明前段这些 shared helper 同时服务着 PDG-backed 的 impact 辅助模块 pdg-impact.ts该模块负责 PDG 层探测、语句级遍历、块投影与结果组装契约。数据模型速查一条边到底长什么样落在CodeRelation表里的依赖边遵循统一模式resources.tsBasicBlock 节点列id、filePath、startLine、endLine、texttext即块内源码片段guard 判定就是正则匹配它CodeRelation 边属性typeSTRINGCFG | CDG | REACHING_DEF | ...、confidenceDOUBLE、reasonSTRINGCDG 存分支方向T|FREACHING_DEF 存变量名及可选行注解、stepINT32。pdg_query的两条实际执行语句见 local-backend.ts都限定(a:BasicBlock)-[r:CodeRelation]-(b:BasicBlock)的 BasicBlock→BasicBlock 分区外加r.type edgeType与锚定子句并同时跑LIMIT ${limit}的结果页与COUNT(*)总数统计。edgeType是按模式硬编码的字面量、target/variable只走绑定参数不存在 Cypher 注入面。端到端实操流程以--pdg建索引一次性之后的 repo 会带maxCdgEdgesPerFunction/maxReachingDefEdgesPerFunction等戳gitnexus analyze --pdg问什么门控这条语句guard / 守卫子句发现pdg_query({ mode: controls, target: src/handlers/auth.ts }) pdg_query({ mode: controls, target: validateRequest })问这个变量流向哪里pdg_query({ mode: flows, target: src/pipeline/run.ts, variable: token })查证仓库是否真的有 PDG 层任何返回都带note缺层时明说no PDG layer — run gitnexus analyze --pdg空results且带total: 0在带层仓库里意味着该锚点在该模式下确实无边线性函数是合法空结果。嫌边界粗直接落 Cypher用上面修正版 guard-clause 查询但务必自行加文件 id-prefix / 符号 span 锚定与LIMIT。如果你是想通过 CLI而非 MCP做统一 PDG 影响分析GitNexus 提供等价入口impact symbolName --direction upstream --mode pdg --line N --repo .它返回语句级affectedStatements基于 CDG REACHING_DEF与跨过程符号interproceduralByDepth/byDepth无层/降级结果以 UNKNOWN-risk note 呈现ai-context.ts。边界条件哪些答案 PDG 给不了跨函数caller→callee、跨模块不是 PDG 的领域数据依赖与控制依赖都限定在单函数内跨函数用explaintaint 的 TAINT_PATH。属性/字段级流、闭包/回调内流arr.forEach(() sink(y))双向不可见、guard 型净化器if (isValid(x))以及隐式/控制依赖流都不被 taint 模型跟踪——explain的契约明确声明缺席不等于安全。同行挤多个函数的代码会让锚定退化到文件级或粗糙块级。即便 CDG 存在switch的逐 case 条件、以及真正需要后支配关系做更细判定时都需要等后续 M5/M6 演进当前只保证二值T|F。仓库中针对该查询面的回归测试覆盖可从这些测试文件名窥见一斑test/integration 下的pdg-query.test.ts、pdg-emit-streaming-roundtrip.test.ts、impact-pdg-e2e.test.ts、impact-pdg-interproc.test.ts等PDG 影响与退化测试以impact-pdg-*为前缀成组出现cfg 基准另有cfg-bench侧的无边预算验证。阅读_pdgQueryImpl或新增 CDG 查询前让这些测试通过是底线。参考资源技能文档主副本gitnexus/skills/gitnexus-pdg-query.mdClaude 插件打包副本在 gitnexus-claude-plugin/skills/gitnexus-pdg-query/SKILL.mdCursor 集成亦含相同技能工具定义与分页常量gitnexus/src/mcp/tools.ts后端实现pdgQueryWAL 包装 _pdgQueryImplresolveBlockAnchorgitnexus/src/mcp/local/local-backend.tsPDG-backed impact 辅助与层探测gitnexus/src/mcp/local/pdg-impact.ts图数据模型与 guard-clause Cypher 示例gitnexus/src/mcp/resources.tsCFG/依赖层数据模型与各语言 walk 策略gitnexus/src/core/ingestion/cfg/types.tsBasicBlock 节点/边落库与每函数预算上限gitnexus/src/core/ingestion/cfg/emit.tsREACHING_DEF reason 编解码FU-B-2gitnexus/src/core/ingestion/cfg/reaching-def-reason-codec.ts--pdg元数据戳与全部默认上限gitnexus/src/core/run-analyze.tsCLI AI 上下文中的pdg_query/explain使用指引gitnexus/src/cli/ai-context.ts【免费下载链接】GitNexusGitNexus: The Zero-Server Code Intelligence Engine - GitNexus is a client-side knowledge graph creator that runs entirely in your browser. Drop in a git repository (Github, Gitlab, Azure, Local) or ZIP file, and get an interactive knowledge graph with a built in Graph RAG Agent. Perfect for code exploration项目地址: https://gitcode.com/GitHub_Trending/gi/GitNexus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询