readability-function-cognitive-complexity

检查函数的认知复杂度指标。

该指标的实现遵循 SonarSource 的认知复杂度 规范版本 1.2 (2017 年 4 月 19 日)。

选项

Threshold

标记认知复杂度超过此值的函数。默认值为 25

DescribeBasicIncrements

如果设置为 true,则对于每个超过复杂度阈值的函数,该检查将针对每个导致该复杂度的代码段 (循环、if 语句等) 发布额外的诊断信息。另请参阅下面的示例。默认值为 true

IgnoreMacros

如果设置为 true,该检查将忽略宏内的代码。注意,任何宏参数也将被忽略,即使它们应计入复杂度。由于这将来可能会发生变化,因此此选项不能保证与将来版本兼容。默认值为 false

构建块

认知复杂度指标有三个基本构建块

增量

以下结构会增加函数的认知复杂度指标 (增加 1)

  • 条件运算符

    • if()

    • else if()

    • else

    • cond ? true : false

  • switch()

  • 循环

    • for()

    • C++11 基于范围的 for()

    • while()

    • do while()

  • catch ()

  • goto LABEL, goto *(&&LABEL)),

  • 二元逻辑运算符序列

    • boolean1 || boolean2

    • boolean1 && boolean2

嵌套级别

虽然嵌套级别本身不会改变函数的认知复杂度指标,但它会被跟踪,并被下一个第三个构建块使用。以下结构会增加嵌套级别 (增加 1)

  • 条件运算符

    • if()

    • else if()

    • else

    • cond ? true : false

  • switch()

  • 循环

    • for()

    • C++11 基于范围的 for()

    • while()

    • do while()

  • catch ()

  • 嵌套函数

    • C++11 Lambda

    • 嵌套 class

    • 嵌套 struct

  • GNU 语句表达式

  • Apple 块声明

嵌套增量

这是前面的基本构建块 嵌套级别 起作用的地方。以下结构会将函数的认知复杂度指标增加当前 嵌套级别

  • 条件运算符

    • if()

    • cond ? true : false

  • switch()

  • 循环

    • for()

    • C++11 基于范围的 for()

    • while()

    • do while()

  • catch ()

示例

最简单的例子。此函数的认知复杂度为 0

void function0() {}

稍微好一点的例子。此函数的认知复杂度为 1

int function1(bool var) {
  if(var) // +1, nesting level +1
    return 42;
  return 0;
}

完整示例。此函数的认知复杂度为 3

int function3(bool var1, bool var2) {
  if(var1) { // +1, nesting level +1
    if(var2)  // +2 (1 + current nesting level of 1), nesting level +1
      return 42;
  }

  return 0;
}

在最后一个示例中,如果选项 Threshold 设置为 2 或更小,则该检查将标记 function3。如果选项 DescribeBasicIncrements 设置为 true,它还将标记两个 if 语句,以及它们对函数复杂度和当前嵌套级别的增加量。

局限性

该指标的实现有以下两个显著例外
  • 预处理器条件 (#ifdef, #if, #elif, #else, #endif) 未计入。

  • 递归循环中的每个方法 未计入。它无法完全实现,因为需要进行跨翻译单元分析,而 clang-tidy 目前尚不支持此功能。