lebedev.ri updated this revision to Diff 126682.
lebedev.ri added a comment.

Rebased.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D36836

Files:
  LICENSE.TXT
  clang-tidy/CMakeLists.txt
  clang-tidy/plugin/CMakeLists.txt
  clang-tidy/sonarsource/CMakeLists.txt
  clang-tidy/sonarsource/FunctionCognitiveComplexityCheck.cpp
  clang-tidy/sonarsource/FunctionCognitiveComplexityCheck.h
  clang-tidy/sonarsource/LICENSE.TXT
  clang-tidy/sonarsource/SONARSOURCETidyModule.cpp
  clang-tidy/tool/CMakeLists.txt
  clang-tidy/tool/ClangTidyMain.cpp
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/sonarsource-function-cognitive-complexity.rst
  test/clang-tidy/sonarsource-function-cognitive-complexity.cpp

Index: test/clang-tidy/sonarsource-function-cognitive-complexity.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/sonarsource-function-cognitive-complexity.cpp
@@ -0,0 +1,954 @@
+// RUN: %check_clang_tidy %s sonarsource-function-cognitive-complexity %t -- -config='{CheckOptions: [{key: sonarsource-function-cognitive-complexity.Threshold, value: 0}]}' -- -std=c++11 -w
+
+// any function should be checked.
+
+extern int ext_func(int x = 0);
+
+int some_func(int x = 0);
+
+static int some_other_func(int x = 0) {}
+
+template<typename T> void some_templ_func(T x = 0) {}
+
+class SomeClass {
+public:
+  int *begin(int x = 0);
+  int *end(int x = 0);
+  static int func(int x = 0);
+  template<typename T> void some_templ_func(T x = 0) {}
+  SomeClass() = default;
+  SomeClass(SomeClass&) = delete;
+};
+
+// nothing ever decreases cognitive complexity, so we can check all the things
+// in one go. none of the following should increase cognitive complexity:
+void unittest_false() {
+  {};
+  ext_func();
+  some_func();
+  some_other_func();
+  some_templ_func<int>();
+  some_templ_func<bool>();
+  SomeClass::func();
+  SomeClass C;
+  C.some_templ_func<int>();
+  C.some_templ_func<bool>();
+  C.func();
+  C.end();
+  int i = some_func();
+  i = i;
+  i++;
+  --i;
+  i < 0;
+  int j = 0 ?: 1;
+  auto k = new int;
+  delete k;
+  throw i;
+  {
+    throw i;
+  }
+end:
+  return;
+}
+
+#if 1
+#define CC100
+#else
+// this macro has cognitive complexity of 100.
+// it is needed to be able to compare the testcases with the
+// reference Sonar implementation. please place it right after the first
+// CHECK-NOTES in each function
+#define CC100 if(1){if(1){if(1){if(1){if(1){if(1){if(1){if(1){if(1){if(1){if(1){if(1){if(1){}}}}}if(1){}}}}}}}}}
+#endif
+
+//----------------------------------------------------------------------------//
+//------------------------------ B1. Increments ------------------------------//
+//----------------------------------------------------------------------------//
+// Check that every thing listed in B1 of the specification does indeed       //
+// recieve the base increment, and that not-body does not increase nesting    //
+//----------------------------------------------------------------------------//
+
+// break does not increase cognitive complexity.
+// only  break LABEL  does, but it is unavaliable in C or C++
+
+// continue does not increase cognitive complexity.
+// only  continue LABEL  does, but it is unavaliable in C or C++
+
+void unittest_b1_00() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_00' has cognitive complexity of 33 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:9: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+
+    if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:11: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    } else if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:12: note: +1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:18: note: +3, including nesting penalty of 2, nesting level increased to 3{{$}}
+    } else {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, nesting level increased to 2{{$}}
+    }
+  } else if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:10: note: +1, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:16: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+
+    if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:11: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    } else if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:12: note: +1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:18: note: +3, including nesting penalty of 2, nesting level increased to 3{{$}}
+    } else {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, nesting level increased to 2{{$}}
+    }
+  } else {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +1, nesting level increased to 1{{$}}
+
+    if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:11: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    } else if (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:12: note: +1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:18: note: +3, including nesting penalty of 2, nesting level increased to 3{{$}}
+    } else {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b1_01() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_01' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  int i = (1 ? 1 : 0) ? 1 : 0;
+// CHECK-NOTES: :[[@LINE-1]]:23: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:14: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+}
+
+void unittest_b1_02(int x) {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_02' has cognitive complexity of 9 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  switch (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:13: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+  case -1:
+    return;
+  case 1 ? 1 : 0:
+// CHECK-NOTES: :[[@LINE-1]]:10: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    return;
+  case (1 ? 2 : 0) ... (1 ? 3 : 0):
+// CHECK-NOTES: :[[@LINE-1]]:11: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:27: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    return;
+  default:
+    break;
+  }
+}
+
+void unittest_b1_03(int x) {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_03' has cognitive complexity of 7 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  for (x = 1 ? 1 : 0; x < (1 ? 1 : 0); x += 1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:14: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:30: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-4]]:47: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    break;
+    continue;
+  }
+}
+
+void unittest_b1_04() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_04' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  SomeClass C;
+  for (int i : (1 ? C : C)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:19: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    break;
+    continue;
+  }
+}
+
+void unittest_b1_05() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_05' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  while (1 ? 1 : 0) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:12: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    break;
+    continue;
+  }
+}
+
+void unittest_b1_06() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_06' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  do {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    break;
+    continue;
+  } while (1 ? 1 : 0);
+// CHECK-NOTES: :[[@LINE-1]]:14: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+}
+
+void unittest_b1_07() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_07' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  try {
+  } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+  }
+}
+
+void unittest_b1_08() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_08' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  goto end;
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1{{$}}
+end:
+  return;
+}
+
+void unittest_b1_09_00() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_09_00' has cognitive complexity of 34 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if(1 && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+  }
+  if(1 && 1 && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:13: note: +1{{$}}
+  }
+  if((1 && 1) && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:15: note: +1{{$}}
+  }
+  if(1 && (1 && 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+  }
+
+  if(1 && 1 || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:13: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:8: note: +1{{$}}
+  }
+  if((1 && 1) || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:15: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:9: note: +1{{$}}
+  }
+  if(1 && (1 || 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:14: note: +1{{$}}
+  }
+
+  if(1 || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+  }
+  if(1 || 1 || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:13: note: +1{{$}}
+  }
+  if((1 || 1) || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:15: note: +1{{$}}
+  }
+  if(1 || (1 || 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+  }
+
+  if(1 || 1 && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:13: note: +1{{$}}
+  }
+  if((1 || 1) && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:15: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:9: note: +1{{$}}
+  }
+  if(1 || (1 && 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:14: note: +1{{$}}
+  }
+}
+
+void unittest_b1_09_01() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_09_01' has cognitive complexity of 40 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if(1 && some_func(1 && 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+  if(1 && some_func(1 || 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+  if(1 || some_func(1 || 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+  if(1 || some_func(1 && 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+
+  if(1 && some_func(1 && 1) && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+  if(1 && some_func(1 || 1) && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+  if(1 || some_func(1 || 1) && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-4]]:23: note: +1{{$}}
+  }
+  if(1 || some_func(1 && 1) && 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-4]]:23: note: +1{{$}}
+  }
+
+  if(1 && some_func(1 && 1) || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-4]]:23: note: +1{{$}}
+  }
+  if(1 && some_func(1 || 1) || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-4]]:23: note: +1{{$}}
+  }
+  if(1 || some_func(1 || 1) || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+  if(1 || some_func(1 && 1) || 1) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:29: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:23: note: +1{{$}}
+  }
+}
+
+void unittest_b1_09_02() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b1_09_02' has cognitive complexity of 12 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if(1 && SomeClass::func(1 && 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:29: note: +1{{$}}
+  }
+  if(1 && SomeClass::func(1 || 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:29: note: +1{{$}}
+  }
+  if(1 || SomeClass::func(1 || 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:29: note: +1{{$}}
+  }
+  if(1 || SomeClass::func(1 && 1)) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:8: note: +1{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:29: note: +1{{$}}
+  }
+}
+
+// FIXME: each method in a recursion cycle
+
+//----------------------------------------------------------------------------//
+//---------------------------- B2. Nesting lebel -----------------------------//
+//----------------------------------------------------------------------------//
+// Check that every thing listed in B2 of the specification does indeed       //
+// increase the nesting level                                                 //
+//----------------------------------------------------------------------------//
+
+void unittest_b2_00() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_00' has cognitive complexity of 9 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  } else if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:10: note: +1, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  } else {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +1, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b2_01() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_01' has cognitive complexity of 5 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  int i = 1 ? (1 ? 1 : 0) : (1 ? 1 : 0);
+// CHECK-NOTES: :[[@LINE-1]]:13: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+// CHECK-NOTES: :[[@LINE-2]]:18: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+// CHECK-NOTES: :[[@LINE-3]]:32: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+}
+
+void unittest_b2_02(int x) {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_02' has cognitive complexity of 5 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  switch (x) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+  case -1:
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+    return;
+  default:
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+    return;
+  }
+}
+
+void unittest_b2_03() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_03' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  for (;;) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b2_04() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_04' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  SomeClass C;
+  for (int i : C) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b2_05() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_05' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  while (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b2_06() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_06' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  do {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  } while (true);
+}
+
+void unittest_b2_07() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_07' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  try {
+  } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    if(true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b2_08_00() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_08_00' has cognitive complexity of 8 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  class X {
+    X() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+    ~X() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+    void Y() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+    static void Z() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+// CHECK-NOTES: :[[@LINE-36]]:5: warning: function 'X' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-33]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+
+// CHECK-NOTES: :[[@LINE-30]]:5: warning: function '~X' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-27]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+
+// CHECK-NOTES: :[[@LINE-24]]:10: warning: function 'Y' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-21]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+
+// CHECK-NOTES: :[[@LINE-18]]:17: warning: function 'Z' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-15]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+  };
+}
+
+void unittest_b2_08_01() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_08_01' has cognitive complexity of 8 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  struct X {
+    X() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+    ~X() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+    void Y() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+    static void Z() {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: nesting level increased to 1{{$}}
+      CC100;
+
+      if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+      }
+    }
+
+// CHECK-NOTES: :[[@LINE-36]]:5: warning: function 'X' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-33]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+
+// CHECK-NOTES: :[[@LINE-30]]:5: warning: function '~X' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-27]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+
+// CHECK-NOTES: :[[@LINE-24]]:10: warning: function 'Y' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-21]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+
+// CHECK-NOTES: :[[@LINE-18]]:17: warning: function 'Z' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-15]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+  };
+}
+
+void unittest_b2_08_02() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b2_08_02' has cognitive complexity of 2 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  auto fun = []() {
+// CHECK-NOTES: :[[@LINE-1]]:14: note: nesting level increased to 1{{$}}
+    if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  };
+}
+
+//----------------------------------------------------------------------------//
+//-------------------------- B2. Nesting increments --------------------------//
+//----------------------------------------------------------------------------//
+// Check that every thing listed in B3 of the specification does indeed       //
+// recieve the penalty of the current nesting level                           //
+//----------------------------------------------------------------------------//
+
+void unittest_b3_00() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_00' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b3_01() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_01' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    int i = 1 ? 1 : 0;
+// CHECK-NOTES: :[[@LINE-1]]:15: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+  }
+}
+
+void unittest_b3_02(int x) {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_02' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    switch (x) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    case -1:
+      return;
+    default:
+      return;
+    }
+  }
+}
+
+void unittest_b3_03() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_03' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    for (;;) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b3_04() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_04' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    SomeClass C;
+    for (int i : C) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b3_05() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_05' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    while (true) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+void unittest_b3_06() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_06' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    do {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    } while (true);
+  }
+}
+
+void unittest_b3_07() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'unittest_b3_07' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  if (true) {
+// CHECK-NOTES: :[[@LINE-1]]:3: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +2, including nesting penalty of 1, nesting level increased to 2{{$}}
+    }
+  }
+}
+
+//----------------------------------------------------------------------------//
+// Check that functions are being checked                                     //
+//----------------------------------------------------------------------------//
+
+class CheckClass {
+  CheckClass(int x) {
+// CHECK-NOTES: :[[@LINE-1]]:3: warning: function 'CheckClass' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  void PrivateMemberFunction() {
+// CHECK-NOTES: :[[@LINE-1]]:8: warning: function 'PrivateMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  void PrivateConstMemberFunction() const {
+// CHECK-NOTES: :[[@LINE-1]]:8: warning: function 'PrivateConstMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  static void PrivateStaticMemberFunction() {
+// CHECK-NOTES: :[[@LINE-1]]:15: warning: function 'PrivateStaticMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+public:
+  CheckClass() {
+// CHECK-NOTES: :[[@LINE-1]]:3: warning: function 'CheckClass' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  operator bool() const {
+// CHECK-NOTES: :[[@LINE-1]]:3: warning: function 'operator bool' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  ~CheckClass() {
+// CHECK-NOTES: :[[@LINE-1]]:3: warning: function '~CheckClass' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  void PublicMemberFunction() {
+// CHECK-NOTES: :[[@LINE-1]]:8: warning: function 'PublicMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  void PublicConstMemberFunction() const {
+// CHECK-NOTES: :[[@LINE-1]]:8: warning: function 'PublicConstMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  static void PublicStaticMemberFunction() {
+// CHECK-NOTES: :[[@LINE-1]]:15: warning: function 'PublicStaticMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  void PublicFunctionDefinition();
+
+protected:
+  CheckClass(bool b) {
+// CHECK-NOTES: :[[@LINE-1]]:3: warning: function 'CheckClass' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  void ProtectedMemberFunction() {
+// CHECK-NOTES: :[[@LINE-1]]:8: warning: function 'ProtectedMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  void ProtectedConstMemberFunction() const {
+// CHECK-NOTES: :[[@LINE-1]]:8: warning: function 'ProtectedConstMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+
+  static void ProtectedStaticMemberFunction() {
+// CHECK-NOTES: :[[@LINE-1]]:15: warning: function 'ProtectedStaticMemberFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+    CC100;
+
+    try {
+    } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:7: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+    }
+  }
+};
+
+void CheckClass::PublicFunctionDefinition() {
+// CHECK-NOTES: :[[@LINE-1]]:18: warning: function 'PublicFunctionDefinition' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  try {
+  } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+  }
+}
+
+#define uglyfunctionmacro(name)                                                \
+  void name() {                                                                \
+    CC100;                                                                     \
+                                                                               \
+    if (true) {                                                                \
+      try {                                                                    \
+      } catch (...) {                                                          \
+      }                                                                        \
+    }                                                                          \
+  }
+
+uglyfunctionmacro(MacroFunction)
+// CHECK-NOTES: :[[@LINE-1]]:19: warning: function 'MacroFunction' has cognitive complexity of 3 (threshold 0) [sonarsource-function-cognitive-complexity]
+// CHECK-NOTES: :[[@LINE-2]]:1: note: +1, including nesting penalty of 0, nesting level increased to 1
+// CHECK-NOTES: :[[@LINE-10]]:5: note: expanded from macro 'uglyfunctionmacro'
+// CHECK-NOTES: :[[@LINE-4]]:1: note: +2, including nesting penalty of 1, nesting level increased to 2
+// CHECK-NOTES: :[[@LINE-10]]:9: note: expanded from macro 'uglyfunctionmacro'
+
+template<typename T>
+void templatedFunction() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'templatedFunction' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  try {
+  } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+  }
+}
+
+template<>
+void templatedFunction<bool>() {
+// CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'templatedFunction<bool>' has cognitive complexity of 1 (threshold 0) [sonarsource-function-cognitive-complexity]
+  CC100;
+
+  try {
+  } catch (...) {
+// CHECK-NOTES: :[[@LINE-1]]:5: note: +1, including nesting penalty of 0, nesting level increased to 1{{$}}
+  }
+}
+
+template void templatedFunction<int>();
+
+void functionThatCallsTemplatedFunctions() {
+  templatedFunction<int>();
+
+  templatedFunction<bool>();
+
+  templatedFunction<char>();
+
+  templatedFunction<void*>();
+}
Index: docs/clang-tidy/checks/sonarsource-function-cognitive-complexity.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/sonarsource-function-cognitive-complexity.rst
@@ -0,0 +1,144 @@
+.. title:: clang-tidy - sonarsource-function-cognitive-complexity
+
+sonarsource-function-cognitive-complexity
+=========================================
+
+Checks function Cognitive Complexity metric.
+
+The metric is implemented as per the `COGNITIVE COMPLEXITY by SonarSource
+<https://www.sonarsource.com/docs/CognitiveComplexity.pdf>`_ specification
+version 1.2 (19 April 2017).
+
+Options
+-------
+
+.. option:: Threshold
+
+   Flag functions with Cognitive Complexity exceeding this number.
+   The default is `25`.
+
+Building blocks
+---------------
+
+There are three basic building blocks of a Cognitive Complexity metric:
+
+Increment
+^^^^^^^^^
+
+The following structures increase the function's Cognitive Complexity metric
+(by `1`):
+
+* Conditional operators:
+
+   - ``if()``
+   - ``else if()``
+   - ``else``
+   - ``cond ? true : false``
+
+* ``switch()``
+* Loops:
+
+   - ``for()``
+   - C++11 range-based ``for()``
+   - ``while()``
+   - ``do while()``
+
+* ``catch ()``
+* ``goto LABEL``
+* sequences of binary logical operators:
+
+   - ``boolean1 || boolean2``
+   - ``boolean1 && boolean2``
+
+Nesting level
+^^^^^^^^^^^^^
+
+While by itself the nesting level not change the function's Cognitive Complexity
+metric, it is tracked, and is used by the next, third building block.
+The following structures increase the nesting level (by `1`):
+
+* Conditional operators:
+
+   - ``if()``
+   - ``else if()``
+   - ``else``
+   - ``cond ? true : false``
+
+* ``switch()``
+* Loops:
+
+   - ``for()``
+   - C++11 range-based ``for()``
+   - ``while()``
+   - ``do while()``
+
+* ``catch ()``
+* Nested functions:
+
+   - C++11 Lambda
+   - Nested ``class``
+   - Nested ``struct``
+
+Nesting increment
+^^^^^^^^^^^^^^^^^
+
+This is where the previous basic building block, `Nesting level`_, matters.
+The following structures increase the function's Cognitive Complexity metric by
+the current `Nesting level`_:
+
+* Conditional operators:
+
+   - ``if()``
+   - ``cond ? true : false``
+
+* ``switch()``
+* Loops:
+
+   - ``for()``
+   - C++11 range-based ``for()``
+   - ``while()``
+   - ``do while()``
+
+* ``catch ()``
+
+Examples
+--------
+
+The simplest case. This function has Cognitive Complexity of `0`.
+
+.. code-block:: c++
+
+  void function0() {}
+
+Slightly better example. This function has Cognitive Complexity of `1`.
+
+.. code-block:: c++
+
+  int function1(bool var) {
+    if(var) // +1, nesting level +1
+      return 42;
+    return 0;
+  }
+
+Full example. This function has Cognitive Complexity of `3`.
+
+.. code-block:: c++
+
+  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;
+  }
+
+Limitations
+-----------
+
+The metric is implemented with two notable exceptions:
+   * `preprocessor conditionals` (``#ifdef``, ``#if``, ``#elif``, ``#else``,
+     ``#endif``) are not accounted for.
+   * `each method in a recursion cycle` is not accounted for. It can't be fully
+     implemented, because cross-translational-unit analysis would be needed,
+     which is currently not possible in clang-tidy.
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -214,3 +214,4 @@
    readability-static-accessed-through-instance
    readability-static-definition-in-anonymous-namespace
    readability-uniqueptr-delete-release
+   sonarsource-function-cognitive-complexity
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -247,6 +247,11 @@
   <http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-emplace.html#cmdoption-arg-IgnoreImplicitConstructors>`_
   option.
 
+- New `sonarsource-function-cognitive-complexity
+  <http://clang.llvm.org/extra/clang-tidy/checks/sonarsource-function-cognitive-complexity.html>`_ check
+
+  Flags functions with Cognitive Complexity metric exceeding the configured limit.
+
 - Added aliases for the `High Integrity C++ Coding Standard <http://www.codingstandard.com/section/index/>`_ 
   to already implemented checks in other modules.
 
Index: clang-tidy/tool/ClangTidyMain.cpp
===================================================================
--- clang-tidy/tool/ClangTidyMain.cpp
+++ clang-tidy/tool/ClangTidyMain.cpp
@@ -522,6 +522,11 @@
 static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
     ReadabilityModuleAnchorSource;
 
+// This anchor is used to force the linker to link the SONARSOURCEModule.
+extern volatile int SONARSOURCEModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED SONARSOURCEModuleAnchorDestination =
+    SONARSOURCEModuleAnchorSource;
+
 // This anchor is used to force the linker to link the ObjCModule.
 extern volatile int ObjCModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED ObjCModuleAnchorDestination =
Index: clang-tidy/tool/CMakeLists.txt
===================================================================
--- clang-tidy/tool/CMakeLists.txt
+++ clang-tidy/tool/CMakeLists.txt
@@ -32,6 +32,7 @@
   clangTidyObjCModule
   clangTidyPerformanceModule
   clangTidyReadabilityModule
+  clangTidySONARSOURCEModule
   clangTooling
   clangToolingCore
   )
Index: clang-tidy/sonarsource/SONARSOURCETidyModule.cpp
===================================================================
--- /dev/null
+++ clang-tidy/sonarsource/SONARSOURCETidyModule.cpp
@@ -0,0 +1,39 @@
+//===--- SONARSOURCETidyModule.cpp - clang-tidy ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "FunctionCognitiveComplexityCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace sonarsource {
+
+class SONARSOURCEModule : public ClangTidyModule {
+public:
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<FunctionCognitiveComplexityCheck>(
+        "sonarsource-function-cognitive-complexity");
+  }
+};
+
+} // namespace sonarsource
+
+// Register the SONARSOURCEModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<sonarsource::SONARSOURCEModule>
+    X("sonarsource-module",
+      "Adds lint checks corresponding to SONARSOURCE secure coding guidelines.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the SONARSOURCEModule.
+volatile int SONARSOURCEModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/sonarsource/LICENSE.TXT
===================================================================
--- /dev/null
+++ clang-tidy/sonarsource/LICENSE.TXT
@@ -0,0 +1,55 @@
+------------------------------------------------------------------------------
+clang-tidy SONARSOURCE Files
+------------------------------------------------------------------------------
+All clang-tidy files are licensed under the LLVM license with the following
+additions:
+
+Any file referencing a SONARSOURCE Cognitive Complexity metric:
+
+COGNITIVE COMPLEXITY A new way of measuring understandability
+as per https://www.sonarsource.com/docs/CognitiveComplexity.pdf
+
+
+From: Olivier Gaudin <olivier.gau...@sonarsource.com>
+Date: Tue, 01 Aug 2017 07:06:11 +0000
+Message-ID: <caebepr3xrhrogko8sy+uzjo9cxx-wchbp0rxnkcxresfek7...@mail.gmail.com>
+Subject: Re: A question about CognitiveComplexity.pdf legal status
+To: Roman Lebedev <lebedev...@gmail.com>, i...@sonarsource.com
+
+> Hello Roman,
+>
+> It would not, and I would be happy to be notified once done.
+>
+> Thanks
+>
+> Olivier
+
+On Fri, Jul 28, 2017 at 6:17 PM Roman Lebedev <lebedev...@gmail.com> wrote:
+> Date: Fri, 28 Jul 2017 19:17:05 +0300
+> Message-ID: <cadoyv_7f8-hjjdjsv3xwwv35n4i42keoabb8ofjsbaov4bb...@mail.gmail.com>
+> Subject: A question about CognitiveComplexity.pdf legal status
+> From: Roman Lebedev <lebedev...@gmail.com>
+> To: i...@sonarsource.com
+
+> Hi.
+>
+> I would like to know, what is the legal status of
+> https://www.sonarsource.com/docs/CognitiveComplexity.pdf ?
+>
+> If i (or someone else) is to implement the Specification described in
+> that paper,
+> which will produce the same results as the Cognitive Complexity in
+> SonarSource
+> as part of some other static analyzer, for example as a LLVM's clang-tidy
+> check,
+> would that be illegal thing to do?
+>
+> Roman.
+>
+--
+*Olivier Gaudin | **SonarSource*
+*CEO & Co-Founder*
+*+41 (0)22 510 2424*
+http://sonarsource.com
+
+Please see https://reviews.llvm.org/D36836#877642 for the full email.
Index: clang-tidy/sonarsource/FunctionCognitiveComplexityCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/sonarsource/FunctionCognitiveComplexityCheck.h
@@ -0,0 +1,44 @@
+//===--- FunctionCognitiveComplexityCheck.h - clang-tidy---------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SONARSOURCE_FUNCTION_COGNITIVE_COMPLEXITY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SONARSOURCE_FUNCTION_COGNITIVE_COMPLEXITY_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace sonarsource {
+
+/// Checks function Cognitive Complexity metric.
+///
+/// There is only one configuration option:
+///
+///   * `Threshold` - flag functions with Cognitive Complexity exceeding
+///     this number. The default is `25`.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/sonarsource-function-cognitive-complexity.html
+class FunctionCognitiveComplexityCheck : public ClangTidyCheck {
+public:
+  FunctionCognitiveComplexityCheck(StringRef Name, ClangTidyContext *Context);
+
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  const unsigned Threshold;
+};
+
+} // namespace sonarsource
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SONARSOURCE_FUNCTION_COGNITIVE_COMPLEXITY_H
Index: clang-tidy/sonarsource/FunctionCognitiveComplexityCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/sonarsource/FunctionCognitiveComplexityCheck.cpp
@@ -0,0 +1,529 @@
+//===--- FunctionCognitiveComplexityCheck.cpp - clang-tidy-----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FunctionCognitiveComplexityCheck.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace sonarsource {
+namespace {
+
+struct CognitiveComplexity final {
+  // Any increment is based on some combination of reasons.
+  // For details you can look at the Specification at
+  // https://www.sonarsource.com/docs/CognitiveComplexity.pdf
+  // or user-facing docs at
+  // http://clang.llvm.org/extra/clang-tidy/checks/sonarsource-function-cognitive-complexity.html
+  // Here are all the possible reasons:
+  enum Criteria : uint8_t {
+    None = 0U,
+
+    // B1, increases cognitive complexity (by 1)
+    // What causes it:
+    // * if, else if, else, ConditionalOperator (not BinaryConditionalOperator)
+    // * SwitchStmt
+    // * ForStmt, CXXForRangeStmt
+    // * WhileStmt, DoStmt
+    // * CXXCatchStmt
+    // * GotoStmt (but not BreakStmt, ContinueStmt)
+    // * sequences of binary logical operators (BinOpLAnd, BinOpLOr)
+    // * each method in a recursion cycle (not implemented)
+    Increment = 1U << 0,
+
+    // B2, increases current nesting level (by 1)
+    // What causes it:
+    // * if, else if, else, ConditionalOperator (not BinaryConditionalOperator)
+    // * SwitchStmt
+    // * ForStmt, CXXForRangeStmt
+    // * WhileStmt, DoStmt
+    // * CXXCatchStmt
+    // * nested CXXConstructor, CXXDestructor, CXXMethod (incl. C++11 Lambda)
+    IncrementNesting = 1U << 1,
+
+    // B3, increases cognitive complexity by the current nesting level
+    // Applied before IncrementNesting
+    // What causes it:
+    // * IfStmt, ConditionalOperator (not BinaryConditionalOperator)
+    // * SwitchStmt
+    // * ForStmt, CXXForRangeStmt
+    // * WhileStmt, DoStmt
+    // * CXXCatchStmt
+    PenalizeNesting = 1U << 2,
+
+    All = Increment | PenalizeNesting | IncrementNesting,
+  };
+
+  // The helper struct used to record one increment occurrence, with all the
+  // details nessesary.
+  struct Detail {
+    const SourceLocation Loc;     // What caused the increment?
+    const unsigned short Nesting; // How deeply nested is Loc located?
+    const Criteria C;             // The criteria of the increment
+
+    // Criteria only uses three bits, so uint8_t is used as an underlying type.
+    // We could make C a bitfield, but then we would not save anything because
+    // of the padding for alignment, and also we would have to worry about
+    // the differences between compilers.
+
+    Detail(SourceLocation SLoc, unsigned short CurrentNesting, Criteria Crit)
+        : Loc(SLoc), Nesting(CurrentNesting), C(Crit) {}
+
+    // To minimize the sizeof(Detail), we only store the minimal info there.
+    // This function is used to convert from the stored info into the usable
+    // information - what message to output, how much of an increment did this
+    // occurrence actually result in.
+    std::pair<unsigned, unsigned short> process() const {
+      assert(C != Criteria::None && "invalid criteria");
+
+      unsigned MsgId;           // The id of the message to output.
+      unsigned short Increment; // How much of an increment?
+
+      if (C == Criteria::All) {
+        Increment = 1 + Nesting;
+        MsgId = 0;
+      } else if (C == (Criteria::Increment | Criteria::IncrementNesting)) {
+        Increment = 1;
+        MsgId = 1;
+      } else if (C == Criteria::Increment) {
+        Increment = 1;
+        MsgId = 2;
+      } else if (C == Criteria::IncrementNesting) {
+        Increment = 0; // Unused in this message.
+        MsgId = 3;
+      } else
+        llvm_unreachable("should not get to here.");
+
+      return std::make_pair(MsgId, Increment);
+    }
+  };
+
+  // Limit of 25 is the "upstream"'s default.
+  static constexpr unsigned DefaultLimit = 25U;
+
+  // Based on the publicly-avaliable numbers for some big open-source projects
+  // https://sonarcloud.io/projects?languages=c%2Ccpp&size=5   we can estimate:
+  // value ~20 would result in no allocs for 98% of functions, ~12 for 96%, ~10
+  // for 91%, ~8 for 88%, ~6 for 84%, ~4 for 77%, ~2 for 64%, and ~1 for 37%.
+  static_assert(sizeof(Detail) <= 8,
+                "Since we use SmallVector to minimize the amount of "
+                "allocations, we also need to consider the price we pay for "
+                "that in terms of stack usage. "
+                "Thus, it is good to minimize the size of the Detail struct.");
+  SmallVector<Detail, DefaultLimit> Details; // 25 elements is 200 bytes.
+  // Yes, 25 is a magic number. This is the seemingly-sane default for the
+  // upper limit for function cognitive complexity. Thus it would make sense
+  // to avoid allocations for any function that does not violate the limit.
+
+  // The grand total Cognitive Complexity of the function.
+  unsigned Total = 0;
+
+  // The function used to store new increment, calculate the total complexity.
+  void account(SourceLocation Loc, unsigned short Nesting, Criteria C);
+};
+
+// All the possible messages that can be outputed. The choice of the message
+// to use is based of the combination of the CognitiveComplexity::Criteria's.
+// It would be nice to have it in CognitiveComplexity struct, but then it is
+// not static.
+static const std::array<const StringRef, 4> Msgs = {{
+    // B1 + B2 + B3
+    "+%0, including nesting penalty of %1, nesting level increased to %2",
+
+    // B1 + B2
+    "+%0, nesting level increased to %2",
+
+    // B1
+    "+%0",
+
+    // B2
+    "nesting level increased to %2",
+}};
+
+// Criteria is a bitset, thus a few helpers are needed.
+CognitiveComplexity::Criteria operator|(CognitiveComplexity::Criteria LHS,
+                                        CognitiveComplexity::Criteria RHS) {
+  return static_cast<CognitiveComplexity::Criteria>(
+      static_cast<std::underlying_type<CognitiveComplexity::Criteria>::type>(
+          LHS) |
+      static_cast<std::underlying_type<CognitiveComplexity::Criteria>::type>(
+          RHS));
+}
+CognitiveComplexity::Criteria operator&(CognitiveComplexity::Criteria LHS,
+                                        CognitiveComplexity::Criteria RHS) {
+  return static_cast<CognitiveComplexity::Criteria>(
+      static_cast<std::underlying_type<CognitiveComplexity::Criteria>::type>(
+          LHS) &
+      static_cast<std::underlying_type<CognitiveComplexity::Criteria>::type>(
+          RHS));
+}
+CognitiveComplexity::Criteria &operator|=(CognitiveComplexity::Criteria &LHS,
+                                          CognitiveComplexity::Criteria RHS) {
+  LHS = operator|(LHS, RHS);
+  return LHS;
+}
+CognitiveComplexity::Criteria &operator&=(CognitiveComplexity::Criteria &LHS,
+                                          CognitiveComplexity::Criteria RHS) {
+  LHS = operator&(LHS, RHS);
+  return LHS;
+}
+
+void CognitiveComplexity::account(SourceLocation Loc, unsigned short Nesting,
+                                  Criteria C) {
+  C &= Criteria::All;
+  assert(C != Criteria::None && "invalid criteria");
+
+  Details.emplace_back(Loc, Nesting, C);
+  const Detail &D = Details.back();
+
+  unsigned MsgId;
+  unsigned short Increase;
+  std::tie(MsgId, Increase) = D.process();
+
+  Total += Increase;
+}
+
+class FunctionASTVisitor final
+    : public RecursiveASTVisitor<FunctionASTVisitor> {
+  using Base = RecursiveASTVisitor<FunctionASTVisitor>;
+
+  // The current nesting level (increased by Criteria::IncrementNesting).
+  unsigned short CurrentNestingLevel = 0;
+
+  // Used to efficiently know the last type of binary sequence operator that
+  // was encountered. It would make sense for the function call to start the
+  // new sequence, thus it is a stack.
+  using OBO = Optional<BinaryOperator::Opcode>;
+  std::stack<OBO, SmallVector<OBO, 4>> BinaryOperatorsStack;
+
+public:
+  bool TraverseStmtWithIncreasedNestingLevel(Stmt *Node) {
+    ++CurrentNestingLevel;
+    bool ShouldContinue = Base::TraverseStmt(Node);
+    --CurrentNestingLevel;
+    return ShouldContinue;
+  }
+
+  bool TraverseDeclWithIncreasedNestingLevel(Decl *Node) {
+    ++CurrentNestingLevel;
+    bool ShouldContinue = Base::TraverseDecl(Node);
+    --CurrentNestingLevel;
+    return ShouldContinue;
+  }
+
+  bool TraverseIfStmt(IfStmt *Node, bool InElseIf = false) {
+    if (!Node)
+      return Base::TraverseIfStmt(Node);
+
+    {
+      CognitiveComplexity::Criteria Reasons;
+
+      Reasons = CognitiveComplexity::Criteria::None;
+
+      // "If" increases cognitive complexity.
+      Reasons |= CognitiveComplexity::Criteria::Increment;
+      // "If" increases nesting level.
+      Reasons |= CognitiveComplexity::Criteria::IncrementNesting;
+
+      if (!InElseIf) {
+        // "If" receives a nesting increment commensurate with it's nested
+        // depth, if it is not part of "else if".
+        Reasons |= CognitiveComplexity::Criteria::PenalizeNesting;
+      }
+
+      CC.account(Node->getIfLoc(), CurrentNestingLevel, Reasons);
+    }
+
+    // If this IfStmt is *NOT* "else if", then only the body (i.e. "Then" and
+    // "Else") is traversed with increased Nesting level.
+    // However if this IfStmt *IS* "else if", then Nesting level is increased
+    // for the whole IfStmt (i.e. for "Init", "Cond", "Then" and "Else").
+
+    if (!InElseIf) {
+      if (!TraverseStmt(Node->getInit()))
+        return false;
+
+      if (!TraverseStmt(Node->getCond()))
+        return false;
+    } else {
+      if (!TraverseStmtWithIncreasedNestingLevel(Node->getInit()))
+        return false;
+
+      if (!TraverseStmtWithIncreasedNestingLevel(Node->getCond()))
+        return false;
+    }
+
+    // "Then" always increases nesting level.
+    if (!TraverseStmtWithIncreasedNestingLevel(Node->getThen()))
+      return false;
+
+    if (!Node->getElse())
+      return true;
+
+    if (auto *E = dyn_cast<IfStmt>(Node->getElse()))
+      return TraverseIfStmt(E, true);
+
+    {
+      CognitiveComplexity::Criteria Reasons;
+
+      Reasons = CognitiveComplexity::Criteria::None;
+
+      // "Else" increases cognitive complexity.
+      Reasons |= CognitiveComplexity::Criteria::Increment;
+      // "Else" increases nesting level.
+      Reasons |= CognitiveComplexity::Criteria::IncrementNesting;
+      // "Else" DOES NOT receive a nesting increment commensurate with it's
+      // nested depth.
+
+      CC.account(Node->getElseLoc(), CurrentNestingLevel, Reasons);
+    }
+
+    // "Else" always increases nesting level.
+    return TraverseStmtWithIncreasedNestingLevel(Node->getElse());
+  }
+
+// The currently-being-processed stack entry, which is always the top.
+#define CurrentBinaryOperator BinaryOperatorsStack.top()
+
+  // FIXME: how to define  bool TraverseBinaryOperator(BinaryOperator *Op)  ?
+
+#define TraverseBinOp(CLASS)                                                   \
+  bool TraverseBin##CLASS(BinaryOperator *Op) {                                \
+    if (!Op)                                                                   \
+      return Base::TraverseBin##CLASS(Op);                                     \
+                                                                               \
+    /* Make sure that there is always at least one frame in the stack. */      \
+    if (BinaryOperatorsStack.empty())                                          \
+      BinaryOperatorsStack.emplace();                                          \
+                                                                               \
+    /* If this is the first binary operator that we are processing, or the     \
+     * previous binary operator was different, there is an increment. */       \
+    if (!CurrentBinaryOperator || Op->getOpcode() != CurrentBinaryOperator)    \
+      CC.account(Op->getOperatorLoc(), CurrentNestingLevel,                    \
+                 CognitiveComplexity::Criteria::Increment);                    \
+                                                                               \
+    /* We might encounter a function call, which starts a new sequence, thus   \
+     * we need to save the current previous binary operator. */                \
+    const Optional<BinaryOperator::Opcode> BinOpCopy(CurrentBinaryOperator);   \
+                                                                               \
+    /* Record the operator that we are currently processing and traverse it.   \
+     */                                                                        \
+    CurrentBinaryOperator = Op->getOpcode();                                   \
+    bool ShouldContinue = Base::TraverseBin##CLASS(Op);                        \
+    /* And restore the previous binary operator, which might be nonexistent.   \
+     */                                                                        \
+    CurrentBinaryOperator = BinOpCopy;                                         \
+                                                                               \
+    return ShouldContinue;                                                     \
+  }
+
+  // In a sequence of binary logical operators, if the new operator is different
+  // from the previous one, then the cognitive complexity is increased.
+  TraverseBinOp(LAnd);
+  TraverseBinOp(LOr);
+
+  // It would make sense for the function call to start the new binary
+  // operator sequence, thus let's make sure that it creates a new stack frame.
+  bool TraverseCallExpr(CallExpr *Node) {
+    // If we are not currently processing any binary operator sequence, then
+    // no Node-handling is needed.
+    if (!Node || BinaryOperatorsStack.empty() || !CurrentBinaryOperator)
+      return Base::TraverseCallExpr(Node);
+
+    // Else, do add [uninitialized] frame to the stack, and traverse call.
+    BinaryOperatorsStack.emplace();
+    bool ShouldContinue = Base::TraverseCallExpr(Node);
+    // And remove the top frame.
+    BinaryOperatorsStack.pop();
+
+    return ShouldContinue;
+  }
+
+#undef CurrentBinaryOperator
+
+  bool TraverseStmt(Stmt *Node) {
+    if (!Node)
+      return Base::TraverseStmt(Node);
+
+    // Three following switch()'es have huge duplication, but it is better to
+    // keep them separate, to simplify comparing them with the Specification.
+
+    CognitiveComplexity::Criteria Reasons = CognitiveComplexity::Criteria::None;
+    SourceLocation Location = Node->getLocStart();
+
+    // B1. Increments
+    // There is an increment for each of the following:
+    switch (Node->getStmtClass()) {
+    // if, else if, else are handled in TraverseIfStmt(),
+    // FIXME: "each method in a recursion cycle" Increment is not implemented.
+    case Stmt::ConditionalOperatorClass:
+    case Stmt::SwitchStmtClass:
+    case Stmt::ForStmtClass:
+    case Stmt::CXXForRangeStmtClass:
+    case Stmt::WhileStmtClass:
+    case Stmt::DoStmtClass:
+    case Stmt::CXXCatchStmtClass:
+    case Stmt::GotoStmtClass:
+      Reasons |= CognitiveComplexity::Criteria::Increment;
+      break;
+    default:
+      // break LABEL, continue LABEL increase cognitive complexity,
+      // but they are not supported in C++ or C.
+      // Regular break/continue do not increase cognitive complexity.
+      break;
+    }
+
+    // B2. Nesting level
+    // The following structures increment the nesting level:
+    switch (Node->getStmtClass()) {
+    // if, else if, else are handled in TraverseIfStmt(),
+    // Nested methods and such are handled in TraverseDecl.
+    case Stmt::ConditionalOperatorClass:
+    case Stmt::SwitchStmtClass:
+    case Stmt::ForStmtClass:
+    case Stmt::CXXForRangeStmtClass:
+    case Stmt::WhileStmtClass:
+    case Stmt::DoStmtClass:
+    case Stmt::CXXCatchStmtClass:
+    case Stmt::LambdaExprClass:
+      Reasons |= CognitiveComplexity::Criteria::IncrementNesting;
+      break;
+    default:
+      break;
+    }
+
+    // B3. Nesting increments
+    // The following structures receive a nesting increment
+    // commensurate with their nested depth inside B2 structures:
+    switch (Node->getStmtClass()) {
+    // if, else if, else are handled in TraverseIfStmt().
+    case Stmt::ConditionalOperatorClass:
+    case Stmt::SwitchStmtClass:
+    case Stmt::ForStmtClass:
+    case Stmt::CXXForRangeStmtClass:
+    case Stmt::WhileStmtClass:
+    case Stmt::DoStmtClass:
+    case Stmt::CXXCatchStmtClass:
+      Reasons |= CognitiveComplexity::Criteria::PenalizeNesting;
+      break;
+    default:
+      break;
+    }
+
+    if (Node->getStmtClass() == Stmt::ConditionalOperatorClass) {
+      // A little beautification.
+      // For conditional operator "cond ? true : false" point at the "?"
+      // symbol.
+      ConditionalOperator *COp = dyn_cast<ConditionalOperator>(Node);
+      Location = COp->getQuestionLoc();
+    }
+
+    // If we have found any reasons, let's account it.
+    if (Reasons & CognitiveComplexity::Criteria::All)
+      CC.account(Location, CurrentNestingLevel, Reasons);
+
+    // Did we decide that the nesting level should be increased?
+    if (!(Reasons & CognitiveComplexity::Criteria::IncrementNesting))
+      return Base::TraverseStmt(Node);
+
+    return TraverseStmtWithIncreasedNestingLevel(Node);
+  }
+
+  // The parameter MainAnalyzedFunction is needed to differentiate between the
+  // cases where TraverseDecl() is the entry point from
+  // FunctionCognitiveComplexityCheck::check() and the cases where it was called
+  // from the FunctionASTVisitor itself. Explanation: if we get a function
+  // definition (e.g. constructor, destructor, method), the Cognitive Complexity
+  // specification states that the Nesting level shall be increased. But if this
+  // function is the entry point, then the Nesting level should not be
+  // increased. Thus that parameter is there and is used to fall-through
+  // directly to traversing if this is the main function that is being analyzed.
+  bool TraverseDecl(Decl *Node, bool MainAnalyzedFunction = false) {
+    if (!Node || MainAnalyzedFunction)
+      return Base::TraverseDecl(Node);
+
+    // B2. Nesting level
+    // The following structures increment the nesting level:
+    switch (Node->getKind()) {
+    case Decl::Function:
+    case Decl::CXXMethod:
+    case Decl::CXXConstructor:
+    case Decl::CXXDestructor:
+      break;
+    default:
+      // If this is something else, we use early return!
+      return Base::TraverseDecl(Node);
+      break;
+    }
+
+    CC.account(Node->getLocStart(), CurrentNestingLevel,
+               CognitiveComplexity::Criteria::IncrementNesting);
+
+    return TraverseDeclWithIncreasedNestingLevel(Node);
+  }
+
+  CognitiveComplexity CC;
+};
+
+} // namespace
+
+FunctionCognitiveComplexityCheck::FunctionCognitiveComplexityCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      Threshold(Options.get("Threshold", CognitiveComplexity::DefaultLimit)) {}
+
+void FunctionCognitiveComplexityCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "Threshold", Threshold);
+}
+
+void FunctionCognitiveComplexityCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      functionDecl(
+          allOf(isDefinition(), unless(anyOf(isDefaulted(), isDeleted(),
+                                             isImplicit(), isInstantiated()))))
+          .bind("func"),
+      this);
+}
+
+void FunctionCognitiveComplexityCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+  assert(Func->hasBody() && "The matchers should only match the functions that "
+                            "have user-provided body.");
+
+  FunctionASTVisitor Visitor;
+  Visitor.TraverseDecl(const_cast<FunctionDecl *>(Func), true);
+
+  if (Visitor.CC.Total <= Threshold)
+    return;
+
+  diag(Func->getLocation(),
+       "function %0 has cognitive complexity of %1 (threshold %2)")
+      << Func << Visitor.CC.Total << Threshold;
+
+  // Output all the basic increments of complexity.
+  for (const auto &Detail : Visitor.CC.Details) {
+    unsigned MsgId;          // The id of the message to output.
+    unsigned short Increase; // How much of an increment?
+    std::tie(MsgId, Increase) = Detail.process();
+    assert(MsgId < Msgs.size() && "MsgId should always be valid");
+    // Increase, on the other hand, can be 0.
+
+    diag(Detail.Loc, Msgs[MsgId], DiagnosticIDs::Note)
+        << Increase << Detail.Nesting << 1 + Detail.Nesting;
+  }
+}
+
+} // namespace sonarsource
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/sonarsource/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-tidy/sonarsource/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidySONARSOURCEModule
+  SONARSOURCETidyModule.cpp
+  FunctionCognitiveComplexityCheck.cpp
+
+  LINK_LIBS
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangLex
+  clangTidy
+  clangTidyUtils
+  clangTooling
+  )
Index: clang-tidy/plugin/CMakeLists.txt
===================================================================
--- clang-tidy/plugin/CMakeLists.txt
+++ clang-tidy/plugin/CMakeLists.txt
@@ -20,5 +20,6 @@
   clangTidyObjCModule
   clangTidyPerformanceModule
   clangTidyReadabilityModule
+  clangTidySONARSOURCEModule
   clangTooling
   )
Index: clang-tidy/CMakeLists.txt
===================================================================
--- clang-tidy/CMakeLists.txt
+++ clang-tidy/CMakeLists.txt
@@ -42,5 +42,6 @@
 add_subdirectory(performance)
 add_subdirectory(plugin)
 add_subdirectory(readability)
+add_subdirectory(sonarsource)
 add_subdirectory(tool)
 add_subdirectory(utils)
Index: LICENSE.TXT
===================================================================
--- LICENSE.TXT
+++ LICENSE.TXT
@@ -61,3 +61,4 @@
 -------             ---------
 clang-tidy          clang-tidy/cert
 clang-tidy          clang-tidy/hicpp
+clang-tidy          clang-tidy/sonarsource
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to