任务
我正在尝试找出如何最好地添加 C++0x 的 override
< 的 /a> 已在大量 C++ 代码中覆盖的所有现有方法的标识符,无需手动执行。
(我们有很多很多数十万行代码,手动执行完全不可能。)
当前的想法
我们的编码标准表明我们应该对所有隐式添加 virtual
关键字派生类中的虚拟方法,即使完全没有必要(以帮助理解)。
因此,如果我自己编写添加脚本,我会编写一个脚本来读取所有标头,找到所有以 virtual 开头的函数,并在下面的分号之前插入 override
。然后在支持覆盖的编译器上进行编译,并修复基类中的所有错误。
但我真的不想使用这种本土方法,因为:
- 它显然会很乏味且容易出错。
- 并不是每个人都记得每次都添加 virtual 关键字,因此此方法会错过一些现有的覆盖
有现有的工具吗?
那么,是否已经有一个工具可以解析 C++ 代码、检测现有的重写方法并将 override
附加到其声明中?
(我知道诸如 PC-lint 之类的静态分析工具会警告看起来应该被覆盖的函数我所追求的是实际上会破坏我们的代码的东西,以便将来在编译时检测到覆盖中的错误,而不是稍后在静态分析中检测到)
(以防有人想指出 C++) 03 不支持“覆盖”...中实际上,我会添加一个宏,而不是实际的“覆盖”标识符,以便在不支持此功能的旧编译器上使用我们的代码,因此在添加标识符后,我会运行一个单独的脚本来替换。它与我们要使用的任何宏一起使用...)
提前致谢...
The task
I am trying to work out how best to add C++0x's override
identifier to all existing methods that are already overrides in a large body of C++ code, without doing it manually.
(We have many, many hundreds of thousands of lines of code, and doing it manually would be a complete non-starter.)
Current idea
Our coding standards say that we should add the virtual
keyword against all implicitly virtual methods in derived classes, even though strictly unnecessary (to aid comprehension).
So if I were to script the addition myself, I'd write a script that read all our headers, found all functions beginning with virtual, and insert override
before the following semi-colon. Then compile it on a compiler that supports override
, and fix all the errors in base classes.
But I'd really much rather not use this home-grown way, as:
- it's obviously going to be tedious and error-prone.
- not everyone has remembered, every time, to add the virtual keyword, so this method would miss out some existing overrides
Is there an existing tool?
So, is there already a tool that parses C++ code, detects existing methods that overrides, and appends override
to their declarations?
(I am aware of static analysis tools such as PC-lint that warn about functions that look like they should be overrides. What I'm after is something that would actually munge our code, so that future errors in overrides will be detected at compiler-time, rather than later on in static analysis)
(In case anyone is tempted to point out that C++03 doesn't support 'override'... In practice, I'd be adding a macro, rather than the actual "override" identifier, to use our code on older compilers that don't support this feature. So after the identifier was added, I'd run a separate script to replace it with whatever macro we're going to use...)
Thanks in advance...
发布评论
评论(5)
LLVM 项目正在开发一个名为“cpp11-migrate”的工具,目前具有以下功能:
NULL
或0
) 到 C++11nullptr
auto
类型说明符override
说明符添加到适用的成员函数这个工具是记录于此处,并应作为 clang 3.3 的一部分发布。
但是,您今天可以下载源代码并自行构建。
编辑
更多信息:
编辑 2:2013-09-07
“cpp11-migrate”已重命名为“clang 现代化"。对于 Windows 用户,它现在包含在新的 LLVM 快照版本中。
编辑 3:2020-10-07
“clang-modernize”已重命名为“Clang-Tidy"。
There is a tool under development by the LLVM project called "cpp11-migrate" which currently has the following features:
NULL
or0
) to C++11nullptr
auto
type specifieroverride
specifier to applicable member functionsThis tool is documented here and should be released as part of clang 3.3.
However, you can download the source and build it yourself today.
Edit
Some more info:
Edit 2: 2013-09-07
"cpp11-migrate" has been renamed to "clang-modernize". For windows users, it is now included in the new LLVM Snapshot Builds.
Edit 3: 2020-10-07
"clang-modernize" has bee renamed to "Clang-Tidy".
我们的 DMS 软件重新工程工具包及其支持 C++11 的C++ 前端 可以做到这一点。
DMS是一个用于任意编程语言的通用程序转换系统; C++ 前端允许它处理 C++。 DMS 解析、构建准确的 AST 和符号表(这对于 C++ 来说很难做到),提供对 AST 节点和树的属性查询的支持,允许在树上进行过程和源到源的转换。完成所有更改后,可以重新生成修改后的树并保留注释。
您的问题要求您找到派生的虚拟方法并更改它们。执行此操作的 DMS 源到源转换规则类似于:
此类规则与语法树匹配,因此它们不会与注释、字符串或其他内容不匹配。有趣的引号不是 C++ 字符串引号;而是 C++ 字符串引号。它们是元引号,允许规则语言知道其中的内容必须被视为目标语言(“Cpp”)语法。反斜杠是目标语言文本的转义符,允许匹配任意结构,例如,\a 表示需要“a”,它被定义为句法类别“参数”。
您需要更多规则来处理函数返回非空结果等的情况,但您不应该需要很多规则。
有趣的部分是实现控制转换应用的谓词(返回 TRUE 或 FALSE):is_implicitly_virtual。该谓词采用方法名称 n(其抽象语法树)。
该谓词将查阅完整的 C++ 符号表来确定 n 到底是什么。我们已经从其语法设置中知道它是一个方法,但我们想知道在什么类上下文中。
符号表提供了方法和类之间的联系,类的符号表信息告诉我们这个类继承自什么,对于那些类来说,它们包含哪些方法以及它们是如何声明的,最终导致发现(或不是)父类方法是虚拟的。执行此操作的代码必须作为违反 C++ 符号表 API 的过程代码来实现。然而,所有的努力都已经完成了;符号表是正确的,并且包含对所有其他所需数据的引用。 (如果您没有这些信息,您就不可能通过算法做出决定,并且任何代码更改都可能是错误的)。
过去,DMS 已被用来通过程序转换对 C++ 代码进行大规模更改。(查看网站上的论文页面以了解 C++ 重新架构主题)。
(我不是C++专家,只是DMS架构师,所以如果我有一些小细节错误,请原谅。)
Our DMS Software Reengineering Toolkit with its C++11-capable C++ Front End can do this.
DMS is a general purpose program transformation system for arbitrary programming languages; the C++ front end allows it to process C++. DMS parses, builds ASTs and symbol tables that are accurate (this is hard to do for C++), provides support for querying properties of the AST nodes and trees, allows procedural and source-to-source transformations on the tree. After all changes are made, the modified tree can be regenerated with comments retained.
Your problem requires that you find derived virtual methods and change them. A DMS source-to-source transformation rule to do that would look something like:
Such rules match against the syntax trees, so they can't mismatch to a comment, string, or whatever. The funny quotes are not C++ string quotes; they are meta-quotes to allow the rule language to know that what is inside them has to be treated as target language ("Cpp") syntax. The backslashes are escapes from the target language text, allowing matches to arbitrary structures e.g., \a indicates a need for an "a", which is defined to be the syntactic category "arguments".
You'd need more rules to handle cases where the function returns a non-void result, etc. but you shouldn't need a lot of them.
The fun part is implementing the predicate (returning TRUE or FALSE) controlling application of the transformation: is_implicitly_virtual. This predicate takes (an abstract syntax tree for) the method name n.
This predicate would consult the full C++ symbol table to determine what n really is. We already know it is a method from just its syntactic setting, but we want to know in what class context.
The symbol table provides the linkage between the method and class, and the symbol table information for the class tells us what the class inherits from, and for those classes, which methods they contain and how they are declared, eventually leading to the discovery (or not) that the parent class method is virtual. The code to do this has to be implemented as procedural code going against the C++ symbol table API. However, all the hard work is done; the symbol table is correct and contains references to all the other data needed. (If you don't have this information, you can't possibly decide algorithmically, and any code changes will likely be erroneous).
DMS has been used to carry out massive changes on C++ code in the past using program transformations.(Check the Papers page at the web site for C++ rearchitecting topics).
(I'm not a C++ expert, merely the DMS architect, so if I have minor detail wrong, please forgive.)
几个月前,我用大约 3 MB 的代码做了类似的事情,虽然你说“手动完成这件事完全不可能”,但我认为这是唯一的方法。原因是您应该将 override 关键字应用于旨在覆盖基类方法的原型。任何添加它的工具都会将其放在实际上重写基类方法的原型上。编译器已经知道这些方法是哪些,因此添加关键字不会改变任何内容。 (请注意,我对新标准不是很熟悉,并且我假设 override 关键字是可选的。Visual Studio 至少从 VS2005 开始就支持 override。)
我在头文件中搜索“virtual”来找到大部分他们,我仍然偶尔会发现另一个缺少 override 关键字的原型。
我通过这个过程发现了两个错误。
I did something like this a few months ago with about 3 MB worth of code and while you say that "doing it manually would be a complete non-starter," I think it is the only way. The reason is that you should be applying the override keyword to the prototypes that are intended to override base class methods. Any tool that adds it will put it on the prototypes that actually override base class methods. The compiler already knows which methods those are so adding the keyword doesn't change anything. (Please note that I am not terribly familiar with the new standard and I am assuming the override keyword is optional. Visual Studio has supported override since at least VS2005.)
I used a search for "virtual" in the header files to find most of them and I still occasionally find another prototype that is missing the override keyword.
I found two bugs by going through that.
Eclipse CDT 有一个可用的 C++ 解析器和语义实用程序。最新版本的 IIRC 还具有覆盖方法的标记。
不需要太多代码来编写一个基于此的插件,并在适当的情况下重写代码以包含
override
标记。Eclipse CDT has a working C++ parser and semantic utilities. The latest version IIRC also has markers for overriding methods.
It wouldn't require much code to write a plug-in which would base on that and rewrite the code to contain the
override
tags where appropriate.一种选择是
启用建议覆盖编译器警告然后编写脚本
它可以将 override 关键字插入到发出警告所指向的位置
one option is to
Enable suggest-override compiler warning And then write a script
which can insert override keyword to location pointed by the emitted warnings