Skip to content

Latest commit

 

History

History
136 lines (102 loc) · 10.4 KB

File metadata and controls

136 lines (102 loc) · 10.4 KB

CodeGraph

本文描述 diff 消费的仓库关系投影。view 直接展示共享 CodeGraph 的完整事实,见 代码图浏览。

CodeGraph 构建并查询带证据的局部代码关系图。业务与构图的职责边界、内容版本隔离和通用完整性约定 见 项目内核;本文描述图内部的概念、流程和查询语义。

repocli 通过共享 compforge/codegraph 获取跨语言声明类别、 源码范围和静态调用,再适配为现有报告与影响查询使用的节点身份。仓库级 import、配置继承、 Go package 关系和测试候选仍由 repocli 负责。

概念

File 表示某一版本中的仓库相对路径。Symbol 表示文件中的具名声明,包含所属作用域和该版本的源码范围。 同名方法通过 owner 区分,例如 A.work 与 B.work。行号用于定位,不充当跨版本身份。 显式 import 指向的名字可以先作为 binding 节点存在;这证明引用了该名字,不证明已经找到其声明。 Module 节点表达语言层面的聚合,例如 Python 模块的整体引用、Go 的 package。

Relation 是有方向的语法关系,记录关系种类和证据位置。依赖方向为引用方到被引用方。 关系种类与确信度独立。confidence 为空表示有确定关系(JSON 省略该字段),strong 表示强推断, weak 表示弱推断。共享 CodeGraph 的调用边保留原生 exact / scoped / name_only / heuristic、relation ID、完整 Evidence 数组和发生位置。 Evidence 记录各自的 basis、confidence 和可选支撑位置;仓库解析规则继续使用关系上的 basis。这里的确定性针对受支持的静态关系,不表示运行时一定执行;强弱档位不是概率。 解析器以 basis 记录解析依据。Python 的可见但未证明优先级的路径提供强推断; 仅从文件目录匹配模块名提供弱推断,即使只有一个匹配也不升级为确定关系。

关系按用途区分,查询必须显式选择:

关系 含义 可用于影响传播
imports、reexports 明确解析的本地 import、导出别名 是
calls 共享 CodeGraph 支持的静态调用 是
package_member Go 编译单元的隐式依赖 是,按 package 粒度
config_extends 显式配置继承 是
contains 文件或声明拥有子声明 反向投影已到达的声明至所属文件,不访问兄弟声明
config_scope 目录暗示的配置适用范围 仅定位分析缺口

Graph 持有单个版本的节点和关系。Path 是查询得到的关系证据链。 Diagnostic 记录实际提取、配置解析和探索预算的缺口。未知依赖目标不生成边;共享图报告的未解析调用保留为局部诊断。 QueryResult 给出候选节点到查询起点的置信度优先关系路径,路径保留关系的原生 confidence、仓库推断 basis 和源码 Evidence。

流程

可读文件目录 + 关系种类 + 扩展上限
  → 创建空图和解析所需的目录元数据
  → 调用方加入待探索文件
  → 将已知且在预算内的文件批量提交共享 CodeGraph,并按队列顺序等候提取结果,解析仓库内目标
  → 按需展开确定目标、有限歧义候选和 Go package 成员,继续提交新发现的文件
  → 等待共享 CodeGraph 异步构图完成,再读取已发布的图
  → 从共享图取得声明和静态调用,组合仓库上下文关系
  → 返回局部 Graph、实际解析文件及 Diagnostic
  → 沿有目标的关系反向查询,返回候选节点的稳定置信度优先 Path

Go 的 _test.go 分组属于语言编译语义,与调用方是否将它作为候选无关。

关键设计

局部构图由业务范围驱动

调用方加入的文件沿 import 展开中间入口、re-export 和有限候选目标。文件目录为解析提供候选, 未进入 workset 的源码无需建立 AST;局部范围的设计理由见 项目内核。

构图和查询有不同的生命周期。NewBuilder 接受单个版本的文件目录和构建选项,创建空图; Add 接受一批入口,批量提交已知文件的提取任务,按入口和依赖队列顺序有界展开,最后等待共享图发布。随后 Result 提供图、声明、解析范围及缺口, 其 Query 只查询这些关系,不读取源码。Build 是已知探索文件列表时的批量入口,使用同一个 Builder。 构图入口没有 test dir 或 diff 参数;查询中的起点和候选是普通节点身份。

diff 将 changeset 和 testset 一起作为入口;未指定测试目录时使用全部受支持源码作为候选入口,展开为有界 workset;变更声明与关系查询复用该版本的同一共享图。 这里的“增量”是同一次分析里逐步扩展局部图,前后版本使用独立 Builder。 Result 重新组合仓库关系和当前共享图事实,避免增量解析后的旧诊断或关系残留到新结果。

包与模块解析需要文件名及 manifest/config 元数据索引;这些与源码 AST 解析分开。 扩展深度和文件数受请求约束,达到边界时保留已经证明的引用,并输出 Diagnostic。 workset 内所有源码都提供声明;查询种类决定是否消费本地调用关系及相应缺口,而非另设详细文件范围。

通用源码事实与消费者上下文分层

共享 CodeGraph 负责语言识别、声明具体类别、源码范围和其支持的调用关系;repocli 不复刻其声明类别 或范围算法。repocli 的适配层保留既有报告与节点身份,并继续提取 import、导出、Python 静态路径上下文和 配置事实,因为这些信息服务于仓库级解析与测试选择策略。impact 无需识别 AST;原始位置和诊断使用共享类型。

共享 CodeGraph 的语法、声明和未解析调用诊断保留 subject、location 和 outline 计数, 由 impact 输出为局部 observation。import、导出与动态加载仍由 repocli 的仓库级 resolver 处理, 共享图库在不同仓库解析上下文中的 import 缺口不能重复当成最终缺口。

声明覆盖由共享 CodeGraph 的 Capabilities(language) 决定,只有具备声明类别的 grammar 才作为源码语言。 Go、Python、JavaScript、TypeScript 和 TSX 同时具备 repocli 的依赖上下文;Java、Rust、C/C++、Ruby 等 outline 语言可以报告变更声明,但引用解析保持不完整。outline 没有报告遗漏不等于覆盖全部声明。 箭头函数通过变量声明取得身份。 多个名称共享 Go 声明范围时保留 outline 歧义诊断,不任取一个名称。Python 赋值和 JS/TS 解构等未覆盖 声明不能提供符号级起点;未被符号范围覆盖的变更由 diff 使用文件起点,Go 的影响传播始终保持 package 粒度。

Python 采用有界静态求值:跟踪受支持的变量、导入别名、文件相对路径和字面量序列,按语句顺序处理路径变更。 无条件插入到已知搜索前缀的目录可以证明查找优先级;append、未知分支和延迟执行的函数体不能证明优先级。 分支合流只保留一致的值和路径前缀,参数与局部赋值会遮蔽外部绑定,未知路径写操作使既有前缀失效。 一次 import 使用它所在位置的上下文,后续路径操作不会追溯影响它。搜索根目录自身及其祖先不会被误当成模块的包初始化依赖。

该模型不执行 Python,不模拟 import hooks、模块缓存、跨模块副作用或任意函数调用。未知目标的依赖操作不生成关系, 求值预算耗尽保留诊断;普通数据与无关控制流本身不构成依赖缺口。AST 规模、求值步数和字面量展开都有上限。

关系证据与声明归属分开

A.work 的变更不能仅沿 contains 到达 A.other。反向查询只遍历指定的关系, 不会因为两个符号属于同一个文件就创造调用关系。依赖路径可以包含中间 File、Symbol 和 Module。

对测试的直接 named import,diff 采用“导入了变更符号即相关”的粒度,不要求测试实际调用它。 本文件调用支持 Python/JavaScript/TypeScript 中指向唯一模块级函数声明的裸标识符调用; 参数、赋值、局部声明等引起的绑定冲突有明确候选时生成推测调用边;无目标时省略该关系。 方法动态分派、嵌套函数目标、箭头函数目标、赋值别名、任意值引用及完整类型推导不在此支持范围内。 箭头变量仍可作为变更声明和 import 目标。

Module/namespace/default import 保持模块粒度,Go 保持 package 粒度。 跨文件路径到达一个 importing File 后,会继续按文件粒度传播。 这些是明确的静态近似,不声称完整运行时调用图。

Best-effort 可达性

确定边和推测边都参与推荐,关系的 confidence 与 basis 保留在解释路径上。 歧义 import 与条件导出把已捕获的候选目标记录为推测边;完全未知的动态目标不记录。 这允许推荐存在误报和漏报,空结果不是独立性证明。

查询按 exact、strong、weak 三档分别寻找最短依赖路径,原生 scoped 归入 strong,name_only 与 heuristic 归入 weak;先选最强可达档位, 再比较依赖距离和关系步数。三次有界搜索保留在后续弱边处可能更优的短弱前缀,避免单标签贪心丢失解释。 contains、package_member 和 reexports 的距离为 0,其余参与影响传播的关系为 1。 声明起点不会立即扩大到它自己的整个文件;已到达的其他声明可沿 contains 投影至文件, 不反向进入同文件的兄弟声明。遍历阶段只保存通向起点的前驱边, 输出时为请求的候选恢复路径,避免为所有中间节点重复复制完整路径。 环路终止、关系过滤、版本隔离和取消检查是查询契约;文件归属不会凭空生成依赖边。

配置解析器通过独立资源目录读取同版本中显式引用的子模块 JSON。它遵循内核的输入边界; 资源不可读与文件缺失分别报告,配置变化仍影响其父仓消费者。

图是一次分析的内存结果;本包不提供持久化索引、图数据库、全仓调用图或后台服务。 CLI 的 diff 结果和参数见 diff-usage.md,业务流程见 diff.md。