生成用于大规模重构/重命名的C++符号列表

generate a list of C++ symbols for mass refactoring/renaming

本文关键字:C++ 符号 列表 重命名 用于 大规模 重构      更新时间:2023-10-16

Background

我继承了一个遗留的 60kloc g++ 项目,我想重构该项目以在整个项目中强制执行一致的命名约定。

问题

是否有一个免费/开源的静态分析工具可以生成以下列表:

  • 全局符号
  • 类名
  • 成员方法(公共/受保护/私有,如果可能(
  • 成员变量
  • 静态方法
  • 本地符号(可能会忽略这些符号(
  • 我可能错过的任何其他符号,但可能会影响代码的阅读器

方法

我的目的是使用 vim 来编辑生成的符号列表,然后使用 Ruby 脚本对符号进行非常粗略的搜索和替换/映射,以便至少命名约定是一致的。

这个过程有点丑陋,我希望初始编译会失败,但如果我可以有一组更具可读性的代码,我不介意手动完成并解决问题。

大型C++代码库的开发人员使用哪些类型的工具来执行这种重构?

C++的自动重构非常困难,部分与预处理器(宏和文件包含(有关,但主要与解析、名称查找和语义分析阶段其余部分(模板实例化、常量表达式、重载分辨率等(之间的相互依赖性有关。 在我处理过的非常大的C++代码库中,自动重构根本没有完成,并且由于固有的困难,重构工具的质量很差。

自从 clang 出现以来,它专门具有模块化前端,因此您可以以比其他工具更好的方式访问 AST,可能会有一些基于它的更好的重构工具 - 但我不会屏住呼吸。

看看 clang 中的 AST 转储,也许你可以在 XML 上编写一个脚本来给你一个转储,该转储可能构成手动重构它的起点。

Op 想要进行大规模重命名,例如,生成一个名称列表,然后在大型源代码库中重命名其中的许多名称。

擅长这一点的重构工具是一种选择,如果他能找到的话。

一个奇怪但也许有效的替代方案:C++代码源代码混淆工具。

我们公司提供其中之一,可以执行以下操作(是的,这对于任务来说似乎是错误的!

  • 条评论
  • 损坏格式
  • 用打乱的名称一致地替换标识符(答案的种子!
  • 构建标识符映射("标识符 -> scrambled_identifier"名称列表(作为结果 对于所有标识符。

此过程应用于文件,无需预处理。

因此,实际上,它是一个大规模重命名工具。 重命名为坏名字是它的目的,但是它可以被滥用以重命名为好名称。

事实上,它接受什么作为输入是一个标识符映射(可能是空的,当然在第一次运行时,通常采用从连续的模糊处理运行(,并重命名在该映射中找到的标识符根据地图,以及它找不到新的加扰名称的标识符。

如果您为其提供完整地图,则可以完全控制其重命名为的名称。

因此,要将其用于大规模重命名,以下过程应该有效:

  1. 运行混淆器,获取标识符映射。抛出结果源文本离开。
  2. 将标识符映射修改为"标识符 ->标识符"。对于像 Emacs 这样体面的编辑器来说,这是一个 30 秒的任务。 如果原封不动地使用这个修改后的地图,混淆器会将每个符号重命名为自己,例如,没有任何东西被重命名。 将"标识符 -> foo"替换为"标识符"被该工具视为"标识符 ->标识符"。
  3. (然后排序(查看标识符列表。 为某些标识符选择新名称。相应地修改列表:"bad_identifier_1 -> better_identifier_1"
  4. 使用修改后的地图重新运行混淆器。 您的bad_identifiers将被更换。

哎呀,评论和格式呢:-?

好吧,有一个命令行开关本质上说"不要扔掉评论"。就格式而言,混淆器显着地包括一个源代码格式化程序。只需作为格式化程序第二次运行它即可。 瞧,重命名的代码格式漂亮。

警告:

  • 格式化程序无法处理一些放置不当的预处理器条件;大多数C++代码都没有这个,它的内容通常可以通过一行编辑来更改。
  • 混淆器不区分范围。 给定 I -> J,它将把所有 I 实例重命名为 J。
  • 混淆器不会检测到愚蠢的重命名。 如果你重命名 I -> J,并重命名 K -> J,如果重命名会损坏你的程序,混淆器不会告诉你。(重命名可能有效;取决于您的代码以及 I 和 K 的使用位置(。 这很容易避免:不要在任何地方生成具有相同重命名名称的地图。 这意味着您不应重命名系统包含文件中出现的标识符;您可以重命名应用程序包含文件中显示的标识符。

如果有足够的兴趣,我们的小改动可以直接保留格式和注释。

这个笨拙的过程的好处是你可以尝试获得正确的重命名集;你只需要保留最终的"混淆/格式化"结果。 当然,您可以通过每个阶段运行一个流程来重命名组中的事物集。 强烈建议在每个周期后重新编译:-}

您可以使用此过程一次重命名一个标识符,但我认为常规编辑器可以很好地为您服务。

如果OP只是想要名字列表,他显然可以在第一次混淆传递后停下来,带着标识符映射逃跑。

不,它

不是正则表达式替换字符串黑客;它使用完整的C++11词法分析器,因此不会被字符串文字或注释的内容混淆。 格式化程序部分实际上使用完整的 C++(11( 解析器。