对于静态分析工具,我经常使用 CPD、PMD、FindBugs 和 Checkstyle。
CPD 是 PMD“复制/粘贴检测器”工具。在我注意到PMD web page 上的"Finding Duplicated Code" link 之前,我使用了PMD 一段时间。
我想指出,这些工具有时可以扩展到它们“开箱即用”的规则集之外。不仅仅是因为它们是开源的,因此您可以重写它们。其中一些工具带有允许它们扩展的应用程序或“钩子”。例如,PMD 带有"designer" tool,允许您创建新规则。此外,Checkstyle 具有 DescendantToken 检查,该检查具有允许大量自定义的属性。
我将这些工具与an Ant-based build 集成在一起。您可以点击链接查看我评论的配置。
除了与构建的简单集成之外,我发现将工具配置为以其他几种方式进行某种“集成”很有帮助。即报告生成和警告抑制的一致性。我想在这个讨论中添加这些方面(可能也应该有“静态分析”标签):人们如何配置这些工具来创建一个“统一”的解决方案? (我已经单独问过这个问题here)
首先,对于警告报告,我转换了输出,使每个警告都具有简单的格式:
/absolute-path/filename:line-number:column-number: warning(tool-name): message
这通常被称为“Emacs 格式”,但即使您不使用 Emacs,它也是一种用于同质化报告的合理格式。例如:
/project/src/com/example/Foo.java:425:9: warning(Checkstyle):Missing a Javadoc comment.
我的警告格式转换是由我的 Ant 脚本使用 Ant filterchains 完成的。
我做的第二个“整合”是为了警告抑制。默认情况下,每个工具都支持 cmets 或注释(或两者),您可以将它们放在代码中以使您想忽略的警告静音。但是这些各种警告抑制请求并没有一致的外观,这似乎有些愚蠢。当你抑制一个警告时,你就是在抑制一个警告,那么为什么不总是写“SuppressWarning”呢?
例如,PMD 的默认配置禁止在注释中带有字符串“NOPMD”的代码行上生成警告。此外,PMD 支持 Java 的 @SuppressWarnings 注释。我将 PMD 配置为使用包含“SuppressWarning(PMD.”的 cmets 而不是 NOPMD,以便 PMD 抑制看起来相似。我填写了使用评论样式抑制时违反的特定规则:
// SuppressWarnings(PMD.PreserveStackTrace) justification: (false positive) exceptions are chained
只有“SuppressWarnings(PMD.”部分对注释很重要,但它与 PMD 对 @SuppressWarning 注释的支持一致,该注释确实通过名称识别个别规则违规:
@SuppressWarnings("PMD.CompareObjectsWithEquals") // justification: identity comparision intended
类似地,Checkstyle 禁止在成对的 cmets 之间生成警告(不提供注释支持)。默认情况下,关闭和打开 Checkstyle 的 cmets 分别包含字符串 CHECKSTYLE:OFF 和 CHECKSTYLE:ON。更改此配置(使用 Checkstyle 的“SuppressionCommentFilter”)以使用字符串“BEGIN SuppressWarnings(CheckStyle.”和“END SuppressWarnings(CheckStyle.”使控件看起来更像 PMD:
// BEGIN SuppressWarnings(Checkstyle.HiddenField) justification: "Effective Java," 2nd ed., Bloch, Item 2
// END SuppressWarnings(Checkstyle.HiddenField)
对于 Checkstyle cmets,特定的检查违规 (HiddenField) 很重要,因为每个检查都有自己的“BEGIN/END”注释对。
FindBugs 还支持使用 @SuppressWarnings 注释来抑制警告生成,因此无需进一步配置即可与其他工具实现某种程度的一致性。不幸的是,Findbugs 必须支持自定义的 @SuppressWarnings 注释,因为内置的 Java @SuppressWarnings 注释有一个 SOURCE 保留策略,它不足以将注释保留在 FindBugs 需要的类文件中。我完全限定了 FindBugs 警告抑制以避免与 Java 的 @SuppressWarnings 注释冲突:
@edu.umd.cs.findbugs.annotations.SuppressWarnings("UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR")
这些技术使各种工具看起来相当一致。请注意,让每个警告抑制都包含字符串“SuppressWarnings”可以轻松运行简单的搜索以查找整个代码库中所有工具的所有实例。