是否有很好的工具可以自动检查C ++项目的编码约定,例如:
所有抛出的对象都必须是从std :: exception派生的类(即throw 42;
或throw "runtime error";
将被标记为错误,就像throw std::string("another runtime error");
或抛出任何其他类型一样不是从std :: exception派生的
最后,我正在寻找像Cppcheck这样的东西,但是添加新检查的方法比攻击检查工具的源代码更简单...甚至可以使用一个很好的小GUI来实现您可以设置规则,将它们写入磁盘并使用Eclipse中的规则集或像Jenkins这样的持续集成服务器。
答案 0 :(得分:9)
我在当前项目中运行了许多静态分析工具,以下是一些关键要点:
我使用Visual Lint作为运行所有这些工具的单一入口点。 VL是VS的插件,用于运行第三方静态分析工具,并允许从报告到源代码的单击路由。除了支持用于在报告的不同级别的错误之间进行选择的GUI之外,它还提供自动背景分析(告诉您已经修复了多少错误),单个文件的手动分析,颜色编码的错误显示和图表设施。当您尝试添加新的静态分析工具时,VL安装程序非常漂亮且非常有用(如果您想使用Google cpplint并且没有预先安装Python,它甚至可以帮助您从ActiveState下载Python!)。您可以在此处了解有关VL的更多信息:http://www.riverblade.co.uk/products/visual_lint/features.html
在可以使用VL运行的众多工具中,我选择了三个可以使用本机C ++代码的工具:cppcheck,Google cpplint和Inspirel Vera ++。这些工具具有不同的功能。
Cppcheck:这可能是最常见的一个,我们都使用过它。所以,我会掩饰细节。可以说它捕获了诸如对非原始类型使用后缀增量的错误,在使用empty()时使用size()时警告,变量的范围缩小,类定义中成员的名称限定不正确,初始化顺序不正确类成员,缺少初始化,未使用的变量等。对于我们的代码库,cppcheck报告了大约6K错误。有一些误报(例如未使用的功能),但这些都被扼杀了。您可以在此处了解有关cppcheck的更多信息:http://cppcheck.sourceforge.net/manual.pdf
Google cpplint:这是一个基于python的工具,用于检查您的来源是否存在违规风格。可以在此处找到完成此验证的样式指南:http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml(这基本上是Google的C ++样式指南)。 Cpplint在我们的代码库中产生~104K错误,其中大多数错误与空白(缺失或额外),制表符,支撑位置等有关。一些可能值得修复的错误是:C风格的强制转换,缺少标题。
< / LI>Inspirel Vera++:这是一个用于验证,分析和转换C ++源代码的可编程工具。这类似于cpplint的功能。可在此处找到可用规则的列表:http://www.inspirel.com/vera/ce/doc/rules/index.html,可在此处找到类似的可用转换列表:http://www.inspirel.com/vera/ce/doc/transformations/index.html。有关如何添加自己的规则的详细信息,请访问:http://www.inspirel.com/vera/ce/doc/tclapi.html。对于我们的项目,Vera ++发现了大约90K的问题(针对20多条规则)。
答案 1 :(得分:5)
在即将推出的州:来自Google的Manuel Klimek正在整合Clang主线,这是一种在Google上开发的用于查询和转换C ++代码的工具。
工具基础设施已经布局,它可能已经填满,但它已经正常运行。主要思想是它允许您定义操作并在选定文件上运行这些操作。
Google创建了一组简单的C ++类和方法,允许以友好的方式查询AST:AST Matcher框架,它正在开发中,最终将允许非常精确的匹配。
此刻需要创建可执行文件,但代码以库的形式提供,因此无需编辑它,并且可以在单个源文件中处理一次性转换工具。
匹配器的示例(found in this thread):目标是查找对std::string
(使用默认分配器)的结果形成的std::string::c_str()
的构造函数重载的调用,因为它可以用简单的副本代替。
ConstructorCall(
HasDeclaration(Method(HasName(StringConstructor))),
ArgumentCountIs(2),
// The first argument must have the form x.c_str() or p->c_str()
// where the method is string::c_str(). We can use the copy
// constructor of string instead (or the compiler might share
// the string object).
HasArgument(
0,
Id("call", Call(
Callee(Id("member", MemberExpression())),
Callee(Method(HasName(StringCStrMethod))),
On(Id("arg", Expression()))
))
),
// The second argument is the alloc object which must not be
// present explicitly.
HasArgument(1, DefaultArgument())
)
与ad-hoc工具相比,它非常有前景,因为它使用了Clang编译器AST库,因此不管它使用的宏和模板内容有多复杂,只要你的代码编译它就可以保证进行分析;但它也意味着可以表达依赖于重载决策结果的错综复杂的查询。
此代码返回Clang库中的实际AST节点,因此程序员可以在源文件中精确定位位和nits,并根据需要进行编辑以进行调整。
有人谈到使用文本匹配规范,但是从C ++ API开始被认为是更好的,因为它会增加很多复杂性(和自行车脱落)。我希望能够出现一个Python API。
答案 2 :(得分:3)
&#34;样式检查器的关键问题&#34;这种风格就像艺术:每个人对什么是好风格和什么不是什么有不同的看法。这意味着风格检查器总是需要根据当地艺术品味进行定制。
要做到这一点,需要一个完整的C ++解析器,可以访问符号定义,作用域规则以及理想的各种流分析。 AFAIK,CppCheck不提供准确的解析或符号表定义,因此其错误检查不能深入和正确。我认为Coverity和Fortify使用EDG前端提供了这些内容;我不知道他们的工具是否提供对符号表或数据流分析的访问。 Clang即将到来。
您还需要一种编写样式检查的方法。我认为所有工具都提供对AST和符号表的访问,你可以手工编写自己的检查代码,代价是密切了解AST,这对于像C ++这样的大语言来说很难。我认为Coverity和Fortify有一些类似DSL的方案来指定一些检查。
如果您想修复样式不正确的代码,您需要一些可以修改代码表示的代码。 Coverity和Fortify不提供此AFAIK。我相信Clang确实能够修改AST并重新生成代码;你仍然必须对AST结构有非常深入的了解,才能编写树形黑客逻辑并使其正确。
我们的DMS Software Reengineering Toolkit及其C++ front end提供了大部分功能。使用其C ++前端,DMS可以解析ANSI C ++ 11,GCC4(带有C ++ 11扩展)和MSVS 2010(带有C ++ 11扩展),构建具有完整类型信息的AST和符号表。人们还可以询问任意表达式AST节点的类型。目前,DMS计算控制流,但不计算C ++的数据流。
AST API允许您对任意检查进行程序编码;或者对AST进行更改以修复问题,然后DMS的prettyprinter可以使用注释和保留的文字格式信息(例如,数字的基数等)重新生成完整的,可编译的源文本。你必须知道AST结构,就像其他工具一样,但它更容易知道,因为它与DMS C ++语法规则是同构的。 C ++前端附带了我们的C ++语法。 [DMS使用GLR解析器使其成为可能]。
此外,可以使用DMS的规则语言编写模式和转换,使用C ++本身的表面语法。有人可能会编写OP&#34;不会抛出非STL异常&#34;如
pattern nonSTLexception(i: IDENTIFIER):statement
= " throw \i; " if ~derived_from_STD_exception(i);
(meta)引号内的东西是带有一些模式匹配转义的C ++源代码,例如&#34; \ i&#34;是指占位符变量&#34; i&#34;根据规则必须是C ++标识符;整个&#34;扔\ i;&#34;子句必须是C ++&#34;语句&#34; (C ++语法中的非终结符)。规则本身主要表示要匹配的语法,但可以调用应用于匹配子树的语义检查(例如&#34; ~is_derived_from_STD_exception&#34;)(在这种情况下,无论&#34; \ i&#34;匹配)。
在写这样的模式时,你不必知道AST的形状;模式知道它,并自动匹配。如果你曾经编写过AST步行者,那么你会很感激这是多么方便。
匹配知道AST节点,因此知道精确位置(文件/行/列),这使得生成具有精确位置信息的报告变得容易。
您需要向DMS添加自定义例程,以及#34; inherits_from_STD_exception&#34;,以验证传递给该例程的标识符树节点(如所需的OP)是从 的std ::例外。这需要找到&#34; std :: exception&#34;在符号表中, 并验证标识符树节点的符号表条目是否为类 声明和传递性地继承自其他类声明(通过跟随符号表链接),直到找到std :: exception符号表条目。
DMS转换规则本质上是一对模式,&#34;如果您看到 this ,则将其替换为 &#34;。< / p>
我们使用DMS为COBOL和C ++构建了几个自定义样式检查程序。它仍然是相当多的工作,主要是因为C ++是一种非常复杂的语言,你必须仔细考虑你的检查的确切含义。
Trickier检查和那些开始陷入深度静态分析的测试需要访问控制和数据流信息。 DMS现在计算C ++的控制流程,我们正在进行数据流分析(我们已经为Java,IBM Enterprise COBOL和各种C方言做了这个)。分析结果与AST节点相关联,因此可以使用模式查找样式检查的元素,然后根据需要跟随数据流将元素绑定在一起。
如果用DMS完成所有这些工作(或者确实使用任何其他工具以任何中途准确的方式处理C ++),那么编写额外的或复杂的样式检查是不是很方便&#34;方便&#34 34 ;.你应该希望有良好的技术背景。&#34;