【问题标题】:Suppress warnings from CPD for C/C++ code禁止来自 CPD 的 C/C++ 代码警告
【发布时间】:2016-06-03 09:08:53
【问题描述】:

我们正在使用 PMD 复制粘贴检测器 (CPD) 来分析我们的 C 和 C++ 代码。 但是,有一些代码部分非常相似,但有充分的理由,我们希望取消对这些部分的警告。

documentation of PMD CPD 只提到了一些关于注释的内容,但这不适用于我们的这些语言。

如何仍然忽略特定部分的警告?

也许有评论可以这样做吗?

[UPDATE]我正在使用以下 Groovy 脚本来运行 CPD:

@GrabResolver(name = 'jcenter', root = 'https://jcenter.bintray.com/')
@Grab('net.sourceforge.pmd:pmd-core:5.4.+')
@Grab('net.sourceforge.pmd:pmd-cpp:5.4.+')
import net.sourceforge.pmd.cpd.CPD
import net.sourceforge.pmd.cpd.CPDConfiguration
import java.util.regex.Pattern

def tokens = 60
def scanDirs = ['./path/to/scan', './scan/this/too']
def ignores = [
    './ignore/this/path',
    './this/must/be/ignored/too'
    ].collect({ it.replace('/', File.separator) })
def rootDir = new File('.')
def outputDir = new File('./reports/analysis/')

def filename_date_format = 'yyyyMMdd'
def encoding = System.getProperty('file.encoding')
def language_converter = new CPDConfiguration.LanguageConverter()
def config = new CPDConfiguration()
config.language = new CPDConfiguration.LanguageConverter().convert('c')
config.minimumTileSize = tokens
config.renderer = config.getRendererFromString 'xml', 'UTF-8'
config.skipBlocksPattern = '//DUPSTOP|//DUPSTART'
config.skipLexicalErrors = true
def cpd = new CPD(config)

scanDirs.each { path ->
    def dir = new File(path);
    dir.eachFileRecurse(groovy.io.FileType.FILES) {
        // Ignore file?
        def doIgnore = false
        ignores.each { ignore ->
            if(it.path.startsWith(ignore)) {
                doIgnore = true
            }
        }
        if(doIgnore) {
            return
        }

        // Other checks
        def lowerCaseName = it.name.toLowerCase()
        if(lowerCaseName.endsWith('.c') || lowerCaseName.endsWith('.cpp') || lowerCaseName.endsWith('.h')) {
            cpd.add it
        }
    }
}

cpd.go();

def duplicationFound = cpd.matches.hasNext()

def now = new Date().format(filename_date_format)
def outputFile = new File(outputDir.canonicalFile, "cpd_report_${now}.xml")
println "Saving report to ${outputFile.absolutePath}"

def absoluteRootDir = rootDir.canonicalPath
if(absoluteRootDir[-1] != File.separator) {
    absoluteRootDir += File.separator
}

outputFile.parentFile.mkdirs()
def xmlOutput = config.renderer.render(cpd.matches);
if(duplicationFound) {
  def filePattern = "(<file\\s+line=\"\\d+\"\\s+path=\")${Pattern.quote(absoluteRootDir)}([^\"]+\"\\s*/>)"
  xmlOutput = xmlOutput.replaceAll(filePattern, '$1$2')
} else {
  println 'No duplication found.'
}

outputFile.write xmlOutput

【问题讨论】:

    标签: c++ c pmd static-code-analysis cpd


    【解决方案1】:

    您可以定义自定义标记,通过--skip-blocks-pattern 选项将某些块排除在分析之外。

    --skip-blocks-pattern 模式来查找要跳过的块。以 | 分隔的开始和结束模式。默认为#if 0|#endif

    例如以下将忽略/* SUPPRESS CPD START *//* SUPPRESS CPD END */ cmets 之间的块(注释必须占据单独的行):

    $ ./run.sh cpd --minimum-tokens 100 --files /path/to/c/source --language cpp ----skip-blocks-pattern '/* SUPPRESS CPD START */|/* SUPPRESS CPD END */'
    

    但是请注意,这将导致该工具在由#if 0/#endif 分隔的代码内执行复制粘贴检测。

    【讨论】:

    • 今天晚些时候我会试试这个。我相信另一个工具已经测试了是否使用了“#if 0”,因为我们已经定义了不应该使用它。请注意,我使用自定义 Groovy 脚本来运行 CPD,因此当我从脚本中调用 CPD.go(config) 时,我需要弄清楚如何传递它。
    • 我已更新原始帖子以包含我用于运行 CPD 的脚本,包括 skipBlocksPattern 选项。不幸的是,这似乎对我不起作用(还没有?)。我希望尽快对此进行调查。
    【解决方案2】:

    在 GitHub 上搜索 PMD 的代码后,我想我可以肯定地说,目前支持此功能(当前版本为 PMD 5.5.0)。

    在他们的存储库中搜索CPD-START,不会在pmd-cpp 目录中显示任何结果(请参阅the search results on GitHub)。

    【讨论】:

    • 不幸。但 PMD 毕竟是为 Java 设计的。也许 Clang 静态分析器(或其他工具)可以为您提供更好的自定义?
    • 我不知道 Clang 中有任何代码重复/“复制粘贴检测器”,所以据我所知,这不是替代方案。
    • PMD 5.7.0 开始支持基于注释的抑制,目前支持多种语言,包括 C/C++ pmd.github.io/pmd-6.13.0/pmd_userdocs_cpd.html#suppression
    • 感谢@Johnco 的更新。我已将接受的答案更改为您的答案。
    【解决方案3】:

    我知道这是一个大约 3 年的问题,但为了完整起见,CPD 在 Java 的 PMD 5.6.0(2017 年 4 月)中开始支持此问题,并且自 6.3.0(2018 年 4 月)以来,它已扩展到许多其他C/C++ 等语言。如今,几乎所有 CPD 支持的语言都允许基于评论的抑制。

    基于评论的抑制的完整(当前)文档可在 https://pmd.github.io/pmd-6.13.0/pmd_userdocs_cpd.html#suppression 获得

    值得注意的是,如果文件有 // CPD-OFF 注释,但没有匹配的 // CPD-ON,则所有内容都将被忽略,直到文件结束。

    【讨论】:

    • 谢谢。我会把接受的答案改成你的;)
    • 这是否意味着作弊者可以通过简单的// CPD-OFF 评论来欺骗工具?
    • 这不是在欺骗工具,而是预期的行为……在每个文件之后重置标志以避免意外结果。
    【解决方案4】:

    我对 CPD 没有任何帮助。一般来说,我知道这些工具;我不明白“警告”的含义。

    我们的CloneDR tool finds exact and near-miss duplicate code。恕我直言,它找到了比 CPD 更好的克隆,因为它使用语言语法/结构作为指导。 [这一事实得到第三方研究报告的支持,您可以在网站上找到该报告]。而且它不会发出“警告”。

    如果它认为克隆中涉及代码,该工具将为涉及的克隆生成一个输出报告页面。但这不是警告。没有办法抑制举报行为。显然,如果您看过这样的克隆并认为它不感兴趣,您可以用注释标记其中一个克隆条目,说明它是无趣的克隆;该评论将显示在克隆报告中。 (此类)cmets 对 CloneDR 检测到的克隆没有任何影响,因此添加它们不会改变计算的答案。

    【讨论】:

    • 好吧,我称之为警告,但基本上 CPD 也会这样做。它只是列出了它找到的克隆,并且有一种方法可以告诉它从该列表中“排除”它(从而抑制“警告”)。该工具是否也适用于纯 C 语言?
    • 是的,它适用于多种语言,也适用于普通 C。有时(对于 C)您必须为其提供一些配置数据来处理结构不佳的预处理器指令。有关一些示例,请参阅semanticdesigns.com/Products/Formatters/…。模它工作得很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    • 2010-10-06
    • 2018-11-16
    • 1970-01-01
    相关资源
    最近更新 更多