如何使用emacs重构C++源代码?

51

我主要对C++和方法/类名称/签名的自动更改感兴趣。

9个回答

34

在最近的Emacs版本(24)中,Semantic可以做到这一点。

  1. 可能需要激活语义模式 M-x semantic-mode RET
  2. 使用 C-c , g 快捷键打开Symref缓冲区。
  3. 按下 C-c C-e 将打开所有引用。
  4. 使用 R 进行重命名。

6
我认为正确的是 C-c , g,而不是你所得到的内容。 - lfxgroove
很不幸,它需要 POSIX 环境。在没有安装 Cygwin 或 minGw 的 MS Windows 7 上尝试使用它时,运行 C-c , g 后会出现 "semantic-symref-tool-grep: Searching for program: no such file or directory, sh" 的错误提示。 - Jakub Narębski
1
@JakubNarębski 你可能会对下载一些GnuWin32软件包感兴趣。这些软件包不需要Cygwin或MinGW的开销。你可以下载单独的工具,并将它们的bin目录添加到你的路径变量中。我把所有的软件都安装在C:\Dev\Gnu32下。 - Kevin Tindall
这很酷,但它并不完全理解C++的工作原理;它似乎假定在方法中最多只能有一个具有名称的变量,而C++允许在for循环初始化器中声明变量。 - kqr
太棒了!感谢分享这个不容易发现的技巧。 - Apteryx

26
如果您可以编写elisp程序,您可以考虑使用CEDET库中的cedet + srecode组合 - 它提供了所有此任务所需的工具 - 查找函数调用者、获取函数签名等。但您需要自己使用这些工具创建重构工具。

2
仅仅浏览CEDET页面,这个看起来比被选中的答案好多了... - Jared Oberhaus
2
我不确定我是否不同意Jared,但我必须尝试一下。然而,“你需要自己创建重构工具”这一部分看起来有点不祥。 - T.E.D.

13

我经常这样做,所以我也非常期待其他人的回复。

我知道的唯一诀窍都很基本。在重构代码时,以下是我的Emacs中最好的朋友:

M-x query-replace

这让你可以进行全局搜索和替换。当你将方法和常用数据移动到其他类或命名空间时,你会大量使用它。

C-x 3

这将为您提供一个并排显示两个缓冲区的界面。然后,您可以在它们中加载不同的文件,并使用C-x o将光标从一个移动到另一个。 这是非常基础的内容,但由于它使下一个步骤变得更加强大,所以我要提一下...

C-x (
(type any amount of stuff and/or emacs commands here)
C-x )
这是在emacs中定义宏的方法。每当你需要对一堆代码执行相同的操作(而且这个操作太复杂了,无法使用query-replace来完成),这就是一个救命稻草。如果出现错误,你可以按下C-g来停止宏定义,然后撤销(C-_),直到回到开始的位置。调用该宏的键是C-x e。如果你想多次执行它,可以先按Esc再输入数字。例如:Esc 100 C-x e将尝试调用你的宏100次。
(注:在Windows上,您可以通过按Esc键或按住Alt键来获取“ Meta”)。

2
还有很多其他好的工具。请参考提到CEDET的答案。此外,我经常使用TAGS和M-x tags-query-replace来将所有匹配项重命名为标签搜索,这可以跨源文件进行。另请参阅M-x grep-find,它可以轻松查找要替换的符号的所有出现。 - slacy
我以前尝试过更改标签。这似乎比它值得的麻烦多了。不过,也许在重构期间这样做会更值得? - T.E.D.
31
但这并不是重构。这是手动逐步编辑整个程序。 - vy32
1
@vy32 - 我同意这似乎不是原问题所要求的。但如果你知道一种在不编辑程序的情况下重构代码的方法,我非常希望听听你的想法。这可能会让你得到图灵奖... - T.E.D.
2
重构与手动编辑程序不同。重构是告诉编辑器“无论在哪里看到变量FOO,都将其更改为BAR。”这将更改变量FOO而不是方法调用FOO。 - vy32
7
“重构”是一个人对源代码所做的操作,工具当然会有帮助,但无论这些工具如何帮忙,最终还是人在进行“重构”,而非工具本身。 - T.E.D.

9
目前(2022年),我认为最先进的方法是使用emacs lsp-mode 与适当的语言服务器。
通过clangdccls,这些提供了“语言服务器协议”(lsp)并连接到 lsp-mode ,你可以进行重命名操作: M-x lsp-rename 为了简化此设置,我建议使用Spacemacs,并使用c-c++lsp层(并使用clangd)。

8

自从Emacs 22版本以来,您可以在替换文本中嵌入任意elisp表达式,这使得您能够进行非常强大的文本操作,介于重构工具和简单正则表达式之间。 Steve Yegge曾经写过一个很好的文章(在此)。


哇,这真的很棒。我已经使用Emacs很长一段时间了,我从来没有意识到它们添加了那个功能。 - T.E.D.
6
可以,但这不是重构。 - vy32

7

我的一个朋友在使用xrefactory,并表示它的效果很好。但它的价格不便宜。


10
这并不是免费或自由的。 :( - ashawley
虽然这是非常正确的,但 OP 没有要求免费解决方案。:) 话虽如此,xrefactory 自 2007 年以来就没有更新过了,因此它可能会在重构现代 C++11 及其后代时遇到问题。 - mzuther
有一个免费版本适用于C/Java,还有一个在2009年发布的GPL'd版本。GPL'd版本仍然存在于https://github.com/thoni56/c-xrefactory,并且比semantic-refactor更完整。但是它不支持C++。 - thoni56

4

生成cscope符号。

查找要重构的符号。

进入cscope窗口,在第一次出现光标后开始宏录制

  • 回车
  • c-f 输入你的符号开始位置
  • 导航到你的符号开头
  • 修改单词
  • c-x o(返回cscope)
  • n(下一个cscope符号)

现在只需执行c-x c-e即可。


3

我完全同意查找和替换的功能是有效的。然而,CEDT还有一个非常好用的功能——“semantic-symref-list”。只需将光标放在方法上,运行此命令,您将会看到一个缓冲区,其中列出了代码中引用此标签的所有位置。

您仍然可以使用查找和替换技巧,并确认您已更改所有引用。


2
我一直在使用cquery作为我的C++自动补全工具,它使用Microsoft LSP进行IDE和工具之间的通信。 cquery服务器使用clang后端满足LSP协议的请求。 lsp-emacs是介于emacs和cquery后端(cquery-emacs)之间的包,它公开了一个lsp-rename函数。作为一个自动补全系统,顺便说一下,cquery非常可靠和快速,强烈推荐。
试试吧,在cquery的github上按照入门指南进行操作: https://github.com/cquery-project/cquery/wiki/Emacs 一旦你设置好了cquery:
  1. 将光标悬停在你想重命名的标识符(类、变量等)上。
  2. M-x lsp-rename
  3. 输入标识符的名称。
  4. 执行C-x s(保存某些缓冲区),这将提示你保存被重构影响的所有缓冲区。
您应该检查修改后的所有缓冲区,并检查任何工具/语言重构后的结果。

是的,这是2018年的现代方式。 - zwy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接