Skip to content

重构 ​

概述 ​

clice refactor 根据持久化索引改写工作区的源代码,clice query 读取的也是同一份索引。整个过程不做编译,因此在大型源码树上做一次重构,耗时与一次查询相当。目前唯一的重构是 rename;编辑器里的重命名走的也是同一个引擎。

用法:clice refactor rename --to <name> (--name <query> | --symbol <id> | --path <file> --line <n>) [--workspace <dir>] [--configuration <tag>] [--dry-run] [--fresh]

重命名 ​

符号的指定方式与 clice query 相同:用名称查询、此前的答案所带的 #<hex> id,或定义它的文件和行号。多个符号叫同一个名字时,会把它们一一列出并要求改用 id。

重命名会改动索引关联到该符号的每一处声明、定义和引用,以及必须与它保持同名的那些符号:

  • 类的构造函数和析构函数——重命名构造函数也会重命名它所属的类;
  • 模板的显式特化和偏特化,以及类模板的推导指引(deduction guides);
  • 基类和派生类中与该虚函数构成覆盖关系的函数。

运算符、转换函数、用户定义字面量、宏、在系统头文件中声明的符号,以及每一处声明都由宏写出的符号,都无法重命名。新名称必须是标识符,且既不是 C 的关键字,也不是 C++ 的关键字;使用为实现保留的名称(__x、_X,以及全局作用域中的 _x)会产生警告。

答案 ​

答案与查询的一样,是一个 JSON 对象 {"result": ..., "stale": [...]}:

  • files 列出每个文件中被替换的 Token,附带行号和以字节计的列号,两者均从 1 开始。heuristic 标记的 Token 是经由索引靠启发式解析的名称找到的——例如模板中的一次调用,其被调用函数依赖模板参数——值得再看一眼。
  • unconfirmed 列出写有旧名称、但重命名不予改动的位置,因为索引说不清它们指的是什么:#define 的宏体、展开后写出该名称的宏、未激活的 #if 分支、构建中没有任何翻译单元编译的文件,以及同时也指向另一个同名符号的 Token——那个符号属于另一种构建配置,或是模板中某次调用可能选中的另一个重载。构建之前请先读一遍。
  • warnings 不会阻止重命名:新名称与同一作用域中的函数构成重载,遮蔽了同一函数中的局部变量或与之冲突,或已在某个用到被重命名名称的函数中声明,会在那里截获这处使用。
  • conflicts 会阻止重命名:新名称已在同一作用域中声明、是一个宏、是同一函数的参数名或标签名、是基类或派生类的成员名、是被重命名成员所属的类名,或是被重命名类的成员名;重命名会改动工作区之外的文件;两个命名空间会合并成一个。
  • stale 列出索引中的数据行已不是最新的文件,范围是重命名要改动的文件,以及写有旧名称或新名称的文件——它们建立索引之后又改动过,或者从未建立索引、而构建中仍有翻译单元尚未建立索引。它们同样会阻止重命名;--fresh 会先为它们重新建立索引。

重命名已写入,或在 --dry-run 下已生成计划时,退出码为 0;被冲突或过期文件阻止,或符号无法重命名时,退出码为 1,后一种情况会用 {"error": "..."} 说明原因。参数无法解析时退出码为 2。

写入 ​

不加 --dry-run 时,命令在所有新文本都算好之后才写入文件:只要有一个文件的文本在计划生成之后发生了变化,整个重命名就会在写入任何内容之前停止。每个文件都原地改写,保留原有的字节序标记(BOM)、换行符和权限;某个文件写不进去时(只读,或磁盘已满),重命名就停在那里,错误信息会列出已经改写过的文件。

命令只编辑工作区:隐藏目录、缓存目录和构建目录(含有 CMakeCache.txt 或 build.ninja 的目录)都被排除在外。搜索新旧两个名称时,按后缀名只查工作区内的源文件和头文件;索引定位到的编辑则可能落在任何后缀名的文件中。

命令读的是磁盘,看不到编辑器中尚未保存的缓冲区。请先保存,或直接在编辑器里重命名。

在编辑器中 ​

编辑器里的重命名会选中光标处的名称,或说明该处的符号为什么无法重命名。它读取已打开的缓冲区而不是磁盘,返回的编辑带有这些缓冲区的版本号。遇到冲突或过期文件时,返回一个列出它们的错误;警告、不予改动的位置以及经启发式做出的修改会显示在一条消息中。

已知限制 ​

  • 这些检查都是静态的:索引看不到的语义变化——实参依赖查找(argument-dependent lookup)找到了另一个函数、叫新名称的成员截获了其类内的某处使用、某个重载无法与重命名后的函数共存——都发现不了。重命名之后请构建一次。
  • 暂不支持重命名宏。
  • 编辑器里的重命名只通过为该文件提供服务的那个项目的索引来编辑;同一编辑器中打开的另一个项目里对该符号的使用保持不变。