JonasToth added a comment.

I built the patch locally, here is my output:

The Unittest failed for me: `Neither CHECK-FIXES nor CHECK-MESSAGES found in 
the input`

Script call: 
`/usr/bin/python2.7 
/home/jonas/opt/llvm/tools/clang/tools/extra/test/../test/clang-tidy/check_clang_tidy.py
 
/home/jonas/opt/llvm/tools/clang/tools/extra/test/clang-tidy/readability-function-cognitive-complexity.cpp
 readability-function-cognitive-complexity 
/home/jonas/opt/llvm/build/tools/clang/tools/extra/test/clang-tidy/Output/readability-function-cognitive-complexity.cpp.tmp
 -- -config='{CheckOptions: [{key: 
readability-function-cognitive-complexity.Threshold, value: 0}]}' -- -std=c++11`

Building the docs failed as well, i added inline comment on that.



================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:62
+    std::pair<const char *, unsigned short> Process() const {
+      assert(C != Criteria::None && "invalid criteria");
+
----------------
lebedev.ri wrote:
> JonasToth wrote:
> > You acces `Critera` always scoped. I think you could declare `Criteria` to 
> > be a `enum class`, not just a plain `enum`
> Apparently it's not as simple as that...
> Then i get:
> ```
> 1/8] Building CXX object 
> tools/clang/tools/extra/clang-tidy/readability/CMakeFiles/clangTidyReadabilityModule.dir/FunctionCognitiveComplexityCheck.cpp.o
> FAILED: 
> tools/clang/tools/extra/clang-tidy/readability/CMakeFiles/clangTidyReadabilityModule.dir/FunctionCognitiveComplexityCheck.cpp.o
>  
> /usr/local/bin/clang++  -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE 
> -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
> -Itools/clang/tools/extra/clang-tidy/readability 
> -I/build/clang-tools-extra/clang-tidy/readability -I/build/clang/include 
> -Itools/clang/include -I/usr/include/libxml2 -Iinclude -I/build/llvm/include 
> -fPIC -fvisibility-inlines-hidden -Werror=date-time 
> -Werror=unguarded-availability-new -std=c++11 -Wall -W -Wno-unused-parameter 
> -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic 
> -Wno-long-long -Wcovered-switch-default -Wnon-virtual-dtor 
> -Wdelete-non-virtual-dtor -Wstring-conversion -fcolor-diagnostics 
> -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual 
> -Wno-nested-anon-types -O3 -DNDEBUG    -fno-exceptions -fno-rtti -MD -MT 
> tools/clang/tools/extra/clang-tidy/readability/CMakeFiles/clangTidyReadabilityModule.dir/FunctionCognitiveComplexityCheck.cpp.o
>  -MF 
> tools/clang/tools/extra/clang-tidy/readability/CMakeFiles/clangTidyReadabilityModule.dir/FunctionCognitiveComplexityCheck.cpp.o.d
>  -o 
> tools/clang/tools/extra/clang-tidy/readability/CMakeFiles/clangTidyReadabilityModule.dir/FunctionCognitiveComplexityCheck.cpp.o
>  -c 
> /build/clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
> /build/clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:100:44:
>  error: invalid operands to binary expression 
> ('clang::tidy::readability::(anonymous 
> namespace)::CognitiveComplexity::Criteria' and 
> 'clang::tidy::readability::(anonymous 
> namespace)::CognitiveComplexity::Criteria')
>       } else if (C == (Criteria::Increment | Criteria::IncrementNesting)) {
>                        ~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
> /build/clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:536:9:
>  error: value of type 'CognitiveComplexity::Criteria' is not contextually 
> convertible to 'bool'
>     if (Reasons & CognitiveComplexity::Criteria::All)
>         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 2 errors generated.
> ninja: build stopped: subcommand failed.
> 
> ```
> 
> The first failure i could have explained as use-before-declaration. But not 
> the second one
> I'll keep it as is where it is for now.
AFAIK `enum class` does not behave like a 'tagged integer'. It is necessary to 
to implement all operators (which you did), but i think implicit conversion are 
not allowed as well. 
This would explain both the first and second error message. 
Leave it as is, since the usage is limited to only this file.


================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:102-114
+const std::array<const char *const, 4> CognitiveComplexity::Msgs = {{
+    // B1 + B2 + B3
+    "+%0, including nesting penalty of %1, nesting level increased to %2",
+
+    // B1 + B2
+    "+%0, nesting level increased to %2",
+
----------------
lebedev.ri wrote:
> JonasToth wrote:
> > could this initialization land in line 45? that would be directly close to 
> > the criteria. 
> It would be nice indeed, but if i do
> ```
>   // All the possible messages that can be outputed. The choice of the message
>   // to use is based of the combination of the Criterias
>   static constexpr std::array<const char *const, 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",
>   }};
> ```
> i get
> ```
> $ ninja check-clang-tools -j1 
> [1/5] Linking CXX executable bin/clang-tidy
> FAILED: bin/clang-tidy 
> : && /usr/local/bin/clang++  -fPIC -fvisibility-inlines-hidden 
> -Werror=date-time -Werror=unguarded-availability-new -std=c++11 -Wall -W 
> -Wno-unused-parameter -Wwrite-strings -Wcast-qual 
> -Wmissing-field-initializers -pedantic -Wno-long-long 
> -Wcovered-switch-default -Wnon-virtual-dtor -Wdelete-non-virtual-dtor 
> -Wstring-conversion -fcolor-diagnostics -ffunction-sections -fdata-sections 
> -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG  
> -Wl,-allow-shlib-undefined    -Wl,-O3 -Wl,--gc-sections 
> tools/clang/tools/extra/clang-tidy/tool/CMakeFiles/clang-tidy.dir/ClangTidyMain.cpp.o
>   -o bin/clang-tidy  -Wl,-rpath,"\$ORIGIN/../lib" lib/libLLVMSupport.a 
> -lpthread lib/libclangAST.a lib/libclangASTMatchers.a lib/libclangBasic.a 
> lib/libclangTidy.a lib/libclangTidyAndroidModule.a 
> lib/libclangTidyBoostModule.a lib/libclangTidyBugproneModule.a 
> lib/libclangTidyCERTModule.a lib/libclangTidyCppCoreGuidelinesModule.a 
> lib/libclangTidyGoogleModule.a lib/libclangTidyHICPPModule.a 
> lib/libclangTidyLLVMModule.a lib/libclangTidyMiscModule.a 
> lib/libclangTidyModernizeModule.a lib/libclangTidyMPIModule.a 
> lib/libclangTidyPerformanceModule.a lib/libclangTidyReadabilityModule.a 
> lib/libclangTooling.a lib/libclangToolingCore.a 
> lib/libclangTidyCppCoreGuidelinesModule.a lib/libclangTidyGoogleModule.a 
> lib/libclangTidyMiscModule.a lib/libclangTidyReadabilityModule.a 
> lib/libclangTidyUtils.a lib/libclangTidy.a lib/libclangTooling.a 
> lib/libclangFormat.a lib/libclangToolingCore.a 
> lib/libclangStaticAnalyzerFrontend.a lib/libclangFrontend.a 
> lib/libclangDriver.a lib/libLLVMOption.a lib/libclangParse.a 
> lib/libLLVMMCParser.a lib/libclangSerialization.a lib/libclangSema.a 
> lib/libclangEdit.a lib/libLLVMBitReader.a lib/libLLVMProfileData.a 
> lib/libclangStaticAnalyzerCheckers.a lib/libclangStaticAnalyzerCore.a 
> lib/libclangASTMatchers.a lib/libclangRewrite.a lib/libclangAnalysis.a 
> lib/libclangAST.a lib/libclangLex.a lib/libclangBasic.a lib/libLLVMCore.a 
> lib/libLLVMBinaryFormat.a lib/libLLVMMC.a lib/libLLVMSupport.a -lrt -ldl 
> -ltinfo -lpthread -lz -lm lib/libLLVMDemangle.a && :
> lib/libclangTidyReadabilityModule.a(FunctionCognitiveComplexityCheck.cpp.o):FunctionCognitiveComplexityCheck.cpp:function
>  
> clang::tidy::readability::FunctionCognitiveComplexityCheck::check(clang::ast_matchers::MatchFinder::MatchResult
>  const&): error: undefined reference to 'clang::tidy::readability::(anonymous 
> namespace)::CognitiveComplexity::Msgs'
> ```
> Same if `process()` returns `std::pair<unsigned, unsigned short>` and in 
> `FunctionCognitiveComplexityCheck::check()` i do `const char *IncreaseMessage 
> = Visitor.CC.Msgs[IncreaseMsgId];`
might the `static` cause that linking error?
Did you consider using `StringRef` instead of `const char*`? It is better 
behaved.

```constexpr std::array<StringRef, 4> Msgs = { /* messages */ };```


================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:116-146
+// Criteria is a bitset, thus a few helpers are needed
+static CognitiveComplexity::Criteria
+operator|(CognitiveComplexity::Criteria lhs,
+          CognitiveComplexity::Criteria rhs) {
+  return static_cast<CognitiveComplexity::Criteria>(
+      static_cast<std::underlying_type<CognitiveComplexity::Criteria>::type>(
+          lhs) |
----------------
lebedev.ri wrote:
> JonasToth wrote:
> > `Criteria` could be moved out of the `Detail` struct. That would allow 
> > closer definiton of the helper code to the `enum`.
> `enum Criteria` is in `struct CognitiveComplexity`.
> I personally think it makes most sense there, since the criteria is about 
> cognitive complexity
as said above, iam fine with that.


================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:228-234
+    // if   increases nesting level
+    ++CurrentNestingLevel;
+    ShouldContinue = TraverseStmt(Node->getThen());
+    --CurrentNestingLevel;
+
+    if (!ShouldContinue || !Node->getElse())
+      return ShouldContinue;
----------------
lebedev.ri wrote:
> JonasToth wrote:
> > line 228-234 are a pattern, existing in all traversals. i think it could be 
> > refactored into its own function with a descriptive name. Especially the 
> > increment, traverse, decrement isn't obvious immediatly, but when noting 
> > its blockyness it is.
> Macro hell, here i come!!1
> Is this any better? :)
> I did not move `if (!ShouldContinue) return ShouldContinue;` into the macro, 
> i think it would be totally bad then
I commented directly the macro on that. In my eyes the macro solution is Ok, 
but template function would be better ;)

For the `if(!ShouldContinue) ...` only a macro solution would come to mind. 
With a very descriptive name it might be acceptable, but others should decide 
on that.

Maybe `#define ReturnIfDone()...`, but idk.


================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:206
+  /// common repetitive code is factored here.
+#define TraverseWithIncreasedNestingLevel(CLASS, Node)                         
\
+  ++CurrentNestingLevel;                                                       
\
----------------
Is macro the only possible way? Its certainly the fastest to implement, but i 
think an inline template function could to it as well (more to write, thats for 
sure). This function could return `ShouldContinue`.

I think some specialization would be necessary:

```
/// Traverses Stmt Nodes, default if explicitly called with different class
template <typename T> bool TraverseWithIncreasedNestingLevel(Node) { 
  /* Traversing here, with explict Base::Traverse...(Node) call */ 
}

/// For Decl
template<> bool TraverseWithIncreasedNestingLevel<Decl>(Node) {
 // Same story, different call
}
```
Avoids the macro, produces more code. Current macro situation is already 
readable enough though.


================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:420
+  }
+
+  /// In a sequence of binary logical operators, if new operator is different
----------------
undef the macros here?


================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:441
+  }
+
+  /// It would make sense for the function call to start the new binary
----------------
undef the macros here? ( i mean after they were called)


================
Comment at: clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp:616
+  for (const auto &Detail : Visitor.CC.Details) {
+    const char *IncreaseMessage = nullptr;
+    unsigned short Increase = 0;
----------------
Actually, this could be a `StringRef` as well.


================
Comment at: docs/ReleaseNotes.rst:138
+
+  Checks function Cognitive Complexity metric, and flags the functions with
+  Cognitive Complexity exceeding the configured limit.
----------------
lebedev.ri wrote:
> JonasToth wrote:
> > How about
> > 'Applies the Cognitive Complexity metric to functions (classes?), flagging 
> > those exceeding the configured limit/threshold'
> English is hard :P 
> Reworded, maybe better?
I struggle with it as well ;D
`Calculates the Cognitive Complexity metric for each function and flags those 
with a value exceeding the configured limit.`
I am not sure about the `flags those ...` part.
Swapping the beginning would make the sentence easier to read.


================
Comment at: 
docs/clang-tidy/checks/readability-function-cognitive-complexity.rst:10
+<https://www.sonarsource.com/docs/CognitiveComplexity.pdf>`_ specification
+version 1.2 (19 April 2017), with two notable exceptions:
+   * `preprocessor conditionals` (`#ifdef`, `#if`, `#elif`, `#else`, `#endif`)
----------------
lebedev.ri wrote:
> JonasToth wrote:
> > One or two sentences for the general thought would be nice for the quick 
> > reader, who doesn't like pdfs.
> > 
> > Noting, that the metric adds additional penalties for nesting and that 
> > switch cases are not the same complexity as if/else-if chains would be 
> > enough.
> Wrote something, not sure how well it will be rendered in HTML.
The docs currently do not build for me, did you test them?

- `-DLLVM_ENABLE_SPHINX:BOOL=ON -DSPHINX_OUTPUT_HTML:BOOL=ON` in cmake
- `make docs-clang-tools-html` or ninja.


================
Comment at: 
docs/clang-tidy/checks/readability-function-cognitive-complexity.rst:30
+(by 1):
+   * Conditional operators:
+      * `if()`
----------------
readability-function-cognitive-complexity.rst:30:Unexpected indentation.

Same probably holds true on all other places here. I think if you remove the 
indenting of the list, everything plays out nicely.


Repository:
  rL LLVM

https://reviews.llvm.org/D36836



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to