massberg updated this revision to Diff 323962.
massberg added a comment.

Change option name, improve description and minor fixes.

- Change name FlagBasicIncrements to DescribeBasicIncrements.
- Improve description of this option and added an example.
- Minor code fixes.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D96281/new/

https://reviews.llvm.org/D96281

Files:
  clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
  clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.h
  
clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability-function-cognitive-complexity-flags.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability-function-cognitive-complexity-flags.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability-function-cognitive-complexity-flags.cpp
@@ -0,0 +1,94 @@
+// RUN: %check_clang_tidy %s readability-function-cognitive-complexity %t -- \
+// RUN:   -config='{CheckOptions: \
+// RUN:             [{key: readability-function-cognitive-complexity.Threshold, \
+// RUN:               value: 0}, \
+// RUN:              {key: readability-function-cognitive-complexity.DescribeBasicIncrements, \
+// RUN:               value: "false"} ]}'
+// RUN: %check_clang_tidy -check-suffix=THRESHOLD5 %s readability-function-cognitive-complexity %t -- \
+// RUN:   -config='{CheckOptions: \
+// RUN:             [{key: readability-function-cognitive-complexity.Threshold, \
+// RUN:               value: 5}, \
+// RUN:              {key: readability-function-cognitive-complexity.DescribeBasicIncrements, \
+// RUN:               value: "false"} ]}'
+// RUN: %check_clang_tidy -check-suffix=IGNORE-MACROS %s readability-function-cognitive-complexity %t -- \
+// RUN:   -config='{CheckOptions: \
+// RUN:             [{key: readability-function-cognitive-complexity.Threshold, \
+// RUN:               value: 0}, \
+// RUN:              {key: readability-function-cognitive-complexity.IgnoreMacros, \
+// RUN:               value: "true"}, \
+// RUN:              {key: readability-function-cognitive-complexity.DescribeBasicIncrements, \
+// RUN:               value: "false"} ]}'
+
+void func_of_complexity_4() {
+  // CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'func_of_complexity_4' has cognitive complexity of 4 (threshold 0) [readability-function-cognitive-complexity]
+  // CHECK-NOTES-IGNORE-MACROS: :[[@LINE-2]]:6: warning: function 'func_of_complexity_4' has cognitive complexity of 4 (threshold 0) [readability-function-cognitive-complexity]
+  if (1) {
+    if (1) {
+    }
+  }
+  if (1) {
+  }
+}
+
+#define MacroOfComplexity10 \
+  if (1) {                  \
+    if (1) {                \
+      if (1) {              \
+        if (1) {            \
+        }                   \
+      }                     \
+    }                       \
+  }
+
+void function_with_macro() {
+  // CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'function_with_macro' has cognitive complexity of 11 (threshold 0) [readability-function-cognitive-complexity]
+  // CHECK-NOTES-THRESHOLD5: :[[@LINE-2]]:6: warning: function 'function_with_macro' has cognitive complexity of 11 (threshold 5) [readability-function-cognitive-complexity]
+  // CHECK-NOTES-IGNORE-MACROS: :[[@LINE-3]]:6: warning: function 'function_with_macro' has cognitive complexity of 1 (threshold 0) [readability-function-cognitive-complexity]
+
+  MacroOfComplexity10
+
+      if (1) {
+  }
+}
+
+#define uglyfunctionmacro(name) \
+  void name() {                 \
+    if (true) {                 \
+      try {                     \
+      } catch (...) {           \
+      }                         \
+    }                           \
+  }
+
+uglyfunctionmacro(MacroFunction)
+// CHECK-NOTES: :[[@LINE-1]]:19: warning: function 'MacroFunction' has cognitive complexity of 3 (threshold 0) [readability-function-cognitive-complexity]
+
+#define noop
+
+#define SomeMacro(x) \
+  if (1) {           \
+    x                \
+  }
+
+    void func_macro_1() {
+  // CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'func_macro_1' has cognitive complexity of 2 (threshold 0) [readability-function-cognitive-complexity]
+  // CHECK-NOTES-IGNORE-MACROS: :[[@LINE-2]]:6: warning: function 'func_macro_1' has cognitive complexity of 1 (threshold 0) [readability-function-cognitive-complexity]
+
+  if (1) {
+  }
+  SomeMacro(noop;)
+}
+
+void func_macro_2() {
+  // CHECK-NOTES: :[[@LINE-1]]:6: warning: function 'func_macro_2' has cognitive complexity of 4 (threshold 0) [readability-function-cognitive-complexity]
+  // CHECK-NOTES-IGNORE-MACROS: :[[@LINE-2]]:6: warning: function 'func_macro_2' has cognitive complexity of 1 (threshold 0) [readability-function-cognitive-complexity]
+
+  if (1) {
+  }
+  // Note that if the IgnoreMacro option is set to 'true', currently also macro
+  // arguments are ignored. Optimally, macros should be treated like function
+  // calls, i.e. the arguments account to the complexity so that the overall
+  // complexity of this function is 2 (1 for the if statement above + 1 for
+  // the if statement in the argument).
+  SomeMacro(if (1) { noop; })
+}
Index: clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
@@ -17,6 +17,19 @@
    Flag functions with Cognitive Complexity exceeding this number.
    The default is `25`.
 
+.. option:: DescribeBasicIncrements
+
+   If set to `true`, then for each function exceeding the complexity threshold
+   the check will issue additional diagnostics on every piece of code (loop,
+   `if` statement, etc.) which contributes to that complexity. See also the
+   examples below. Default is `true`.
+
+.. option:: IgnoreMacros
+
+   If set to `true`, the check will ignore code inside macros. Note, that also
+   any macro arguments are ignored, even if they should count to the complexity.
+   Default is `false`.
+
 Building blocks
 ---------------
 
@@ -135,6 +148,11 @@
     return 0;
   }
 
+In the last example, the check will flag `function3` if the option Threshold is
+set to `2` or smaller. If the option DescribeBasicIncrements is set to `true`,
+it will additionally flag the two `if` statements with the amounts by which they
+increase to the complexity of the function and the current nesting level.
+
 Limitations
 -----------
 
Index: clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.h
+++ clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.h
@@ -17,10 +17,17 @@
 
 /// Checks function Cognitive Complexity metric.
 ///
-/// There is only one configuration option:
+/// There are the following configuration option:
 ///
 ///   * `Threshold` - flag functions with Cognitive Complexity exceeding
 ///     this number. The default is `25`.
+///   * `DescribeBasicIncrements`- if set to `true`, then for each function
+///     exceeding the complexity threshold the check will issue additional
+///     diagnostics on every piece of code (loop, `if` statement, etc.) which
+///     contributes to that complexity.
+//      Default is `true`
+///   * `IgnoreMacros` - if set to `true`, the check will ignore code inside
+///     macros. Default is `false`.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/readability-function-cognitive-complexity.html
@@ -34,6 +41,8 @@
 
 private:
   const unsigned Threshold;
+  const bool DescribeBasicIncrements;
+  const bool IgnoreMacros;
 };
 
 } // namespace readability
Index: clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
@@ -213,6 +213,9 @@
     : public RecursiveASTVisitor<FunctionASTVisitor> {
   using Base = RecursiveASTVisitor<FunctionASTVisitor>;
 
+  // If set to true, macros are ignored during analysis.
+  const bool IgnoreMacros;
+
   // The current nesting level (increased by Criteria::IncrementNesting).
   unsigned short CurrentNestingLevel = 0;
 
@@ -223,6 +226,9 @@
   std::stack<OBO, SmallVector<OBO, 4>> BinaryOperatorsStack;
 
 public:
+  explicit FunctionASTVisitor(const bool IgnoreMacros)
+      : IgnoreMacros(IgnoreMacros){};
+
   bool traverseStmtWithIncreasedNestingLevel(Stmt *Node) {
     ++CurrentNestingLevel;
     bool ShouldContinue = Base::TraverseStmt(Node);
@@ -364,6 +370,9 @@
     if (!Node)
       return Base::TraverseStmt(Node);
 
+    if (IgnoreMacros && Node->getBeginLoc().isMacroID())
+      return true;
+
     // Three following switch()'es have huge duplication, but it is better to
     // keep them separate, to simplify comparing them with the Specification.
 
@@ -492,11 +501,15 @@
 FunctionCognitiveComplexityCheck::FunctionCognitiveComplexityCheck(
     StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
-      Threshold(Options.get("Threshold", CognitiveComplexity::DefaultLimit)) {}
+      Threshold(Options.get("Threshold", CognitiveComplexity::DefaultLimit)),
+      DescribeBasicIncrements(Options.get("DescribeBasicIncrements", true)),
+      IgnoreMacros(Options.get("IgnoreMacros", false)) {}
 
 void FunctionCognitiveComplexityCheck::storeOptions(
     ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "Threshold", Threshold);
+  Options.store(Opts, "DescribeBasicIncrements", DescribeBasicIncrements);
+  Options.store(Opts, "IgnoreMacros", IgnoreMacros);
 }
 
 void FunctionCognitiveComplexityCheck::registerMatchers(MatchFinder *Finder) {
@@ -514,7 +527,7 @@
   assert(Func->hasBody() && "The matchers should only match the functions that "
                             "have user-provided body.");
 
-  FunctionASTVisitor Visitor;
+  FunctionASTVisitor Visitor(IgnoreMacros);
   Visitor.TraverseDecl(const_cast<FunctionDecl *>(Func), true);
 
   if (Visitor.CC.Total <= Threshold)
@@ -524,6 +537,9 @@
        "function %0 has cognitive complexity of %1 (threshold %2)")
       << Func << Visitor.CC.Total << Threshold;
 
+  if (!DescribeBasicIncrements)
+    return;
+
   // Output all the basic increments of complexity.
   for (const auto &Detail : Visitor.CC.Details) {
     unsigned MsgId;          // The id of the message to output.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to