5

背景

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

问题

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

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

方法

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

该过程有点难看,我预计初始编译会失败,但如果我可以拥有一组更具可读性的代码,我不介意手动解决问题。

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

4

2 回答 2

1

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

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

看看来自 clang 的 AST 转储,也许您可​​以在 XML 上编写一个脚本来为您提供一个转储,这可能会成为手动重构它的起点。

于 2013-06-16T06:10:17.963 回答
0

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

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

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

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

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

此过程适用于无需预处理的文件。

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

事实上,它接受作为输入的是一个标识符映射(可能是空的,肯定是在第一次运行时,通常取自连续的混淆运行),它会根据映射重命名它在该映射中找到的标识符,以及它没有的标识符t 找到新的打乱名称。

如果你给它一个完整的地图,你可以完全控制它重命名的名称。

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

  1. 运行混淆器,获取标识符映射。将结果源文本扔掉。
  2. 将标识符映射修改为“标识符 -> 标识符”。这是一个像 Emacs 这样体面的编辑器的 30 秒任务。如果使用这个修改后的映射没有改变,混淆器将每个符号重命名为它自己,例如,没有任何东西被重命名。仅用“identifier”替换“identifier -> foo”被工具视为“identifier -> identifier”。
  3. (然后排序)查看标识符列表。为某些标识符选择新名称。相应地修改列表:“bad_identifier_1 -> better_identifier_1”
  4. 使用修改后的地图重新运行混淆器。您的 bad_identifiers 将被替换。

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

嗯,有一个命令行开关,本质上说“不要把评论扔掉”。就格式化而言,混淆器明显包括源代码格式化程序。只需将其作为格式化程序再次运行即可。瞧,重命名的代码格式漂亮。

注意事项:

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

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

这个笨拙的过程的好处是您可以尝试正确设置重命名集;您只需要保留最终的“混淆/格式化”结果。您当然可以通过在每个阶段运行此过程来重命名一组事物。强烈建议在每个循环后重新编译:-}

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

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

不,这不是 regexp-replace-string hack;它使用完整的 C++11 词法分析器,因此不会被字符串文字或注释的内容混淆。格式化程序部分实际上使用了完整的 C++(11) 解析器。

于 2013-06-16T09:19:39.097 回答