This is an archive of the discontinued LLVM Phabricator instance.

[clang-tidy] Add options to describe individual core increments to readability-function-cognitive-complexity check.
ClosedPublic

Authored by massberg on Feb 8 2021, 9:59 AM.

Details

Summary

Often you are only interested in the overall cognitive complexity of a
function and not every individual increment. Thus the flag
'DescribeBasicIncrements' is added. If it is set to 'true', each increment
is flagged. Otherwise, only the complexity of function with complexity
of at least the threshold are flagged.

By default 'DescribeBasisIncrements' is set to 'true', which is the original behavior of the check.

Added a new test for different flag combinations.

(The option to ignore macros which was original part of this patch will be added in another path)

Diff Detail

Event Timeline

massberg created this revision.Feb 8 2021, 9:59 AM
massberg requested review of this revision.Feb 8 2021, 9:59 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 8 2021, 9:59 AM
massberg retitled this revision from Add options to flag individual core increments and to ignore macros to cognitive complexity check. to [clang-tidy] Add options to flag individual core increments and to ignore macros to readability-function-cognitive-complexity check..Feb 9 2021, 5:03 AM
massberg added a project: Restricted Project.Feb 9 2021, 5:04 AM
alexfh added inline comments.Feb 10 2021, 7:50 AM
clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
227

Is a default base class constructor entry necessary in the class initializer list?

clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
22

What does "flag every basic increment" mean? Can you explain in more detail and maybe add an example?

massberg updated this revision to Diff 322921.Feb 11 2021, 1:36 AM

Clarified option FlagBasicIncrements and removed base default constructor from class initializer list of FunctionASTVisitor.

massberg marked 2 inline comments as done.Feb 11 2021, 1:46 AM

Thanks for the comments!

clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
227

You are right, that wasn't needed.

clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
22

I hope the new description explains now the flag sufficiently.

How does this handle a macro where the argument has complex code.

MACRO(if (...) {});

In this case the macro code is definitely increasing the complexity.

massberg updated this revision to Diff 323052.Feb 11 2021, 9:27 AM
massberg marked 2 inline comments as done.

Add test cases showing that when IgnoreMacros is set to 'true', also macro arguments are ignored.

How does this handle a macro where the argument has complex code.

MACRO(if (...) {});

I agree that macro arguments should account to the complexity.

However, with this change macro arguments are ignored.
Unfortunately, I do not see an easy way how to ignore the macro code, but consider the arguments during analysis.

Optimally, macro calls should be considered like function calls in code. Consider the following example:

#define noop

#define SomeMacro(x)  \
  if (1) {            \
    x                 \
  }

void f() {
  SomeMacro(if (1) { noop; })
}

With IgnoreMacros='false' the check gives the function f() a complexity of 3, while with IgnoreMacro='true' the check gives it at complexity of 0.
IMO the complexity should be 1 (and maybe the macro definition itself should be flagged to have a complexity of 1).

So there is still room for improvements. However, from the code that I have seen it is more likely that there is complexity in the macros itself and not in their arguments when being used.
So I would tend to use the option IgnoreMacros='true'. However, as this isn't perfect and others might not agree with it I decided to add the option and also default it to
the old implementation.

I have added test cases that show this problem of ignoring macro arguments and added a comment to the documentation of the option.

alexfh added inline comments.Feb 13 2021, 5:12 PM
clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.h
24–26

Thanks! Now the description contains enough information, but it was hard for me to understand it. I'd suggest to reword this a bit, for example: "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."

As mentioned earlier, an example may help understand the purpose of this option even better.

27

Trailing period is missing.

It would be better to split this into two parts.

clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.cpp
542

Drop {}

clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
20

FlagBasicIncrements is misleading, this should be DescribeBasicIncrements.

massberg updated this revision to Diff 323962.Feb 16 2021, 5:33 AM

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.
massberg marked 4 inline comments as done.Feb 16 2021, 5:37 AM

Thanks for the comments!

clang-tools-extra/clang-tidy/readability/FunctionCognitiveComplexityCheck.h
24–26

Thanks for the suggested rewording!
I took you suggestion and added a comment to the existing examples below which hopefully explains the option now.

clang-tools-extra/docs/clang-tidy/checks/readability-function-cognitive-complexity.rst
20

Thanks, I renamed it as proposed.

massberg marked 2 inline comments as done.Mar 2 2021, 1:13 AM

Once again, can we please split this into two patches?
I'm quite happy with the DescribeBasicIncrements stuff, that can be merged right now.

But i'm not quite sold on the macro stuff. We don't have that for readability-function-size,
nor does the CC spec say anything about macros, nor do other implementations allow to discount them.
To take it to extreme, one potentially could wrap the entire function into a macro and instantiate it once,
and end up with a zero complexity, even though it's obviously not so..

I just wanted to upvote the Macro parameter addition !
In my team, we use macros for logging purpose. We don't have access to their implementations, and they all have (sadly) a high complexity score.
So we write a lot of functions like this one, which in my opinion *should* have a low complexity:

bool doStuff(myClass* objectPtr){
    if(objectPtr == nullptr){
        LOG_WARNING("empty object");
        return false;
    }
    if(objectPtr->getAttribute() == nullptr){
        LOG_WARNING("empty object");
        return false;
    }
    use(objectPtr->getAttribute());
}

and clang-tidy report all of our functions because LOG_WARNING has a complexity of 12 in itself, so I had to disable the whole checker.
If I could disable macros accounting in the complexity score, I could enable the checker again(which I find awesome by the way) !

massberg updated this revision to Diff 327721.Mar 3 2021, 1:58 AM

Remove IgnoreMacros option (to be added in a follow up patch) and sync to head.

massberg retitled this revision from [clang-tidy] Add options to flag individual core increments and to ignore macros to readability-function-cognitive-complexity check. to [clang-tidy] Add options to describe individual core increments to readability-function-cognitive-complexity check..Mar 3 2021, 2:01 AM
massberg edited the summary of this revision. (Show Details)

Once again, can we please split this into two patches?
I'm quite happy with the DescribeBasicIncrements stuff, that can be merged right now.

I have removed the IgnoreMacros and will add it in an independent patch.

Does the test start to fail if you undo the .cpp change?
You may want to add some // CHECK-NOTES-NOT: warning

lebedev.ri accepted this revision.Mar 3 2021, 4:49 AM

Does the test start to fail if you undo the .cpp change?
You may want to add some // CHECK-NOTES-NOT: warning

Actually, i guess it should fail then, lgtm.
If you need help committing this, please specify name <e@ma.il> to be used for git commit author field.

This revision is now accepted and ready to land.Mar 3 2021, 4:49 AM
massberg updated this revision to Diff 327746.Mar 3 2021, 4:52 AM

Add checks to ensure that notes aren't added for specific options.

lebedev.ri added inline comments.Mar 3 2021, 4:58 AM
clang-tools-extra/test/clang-tidy/checkers/readability-function-cognitive-complexity-flags.cpp
16

Note that i'm not sure if we need negative checklines, but if we do, only checking for warning:
(without @LINE stuff) should be best.

massberg updated this revision to Diff 327805.Mar 3 2021, 8:08 AM

Remove unnecessary checks.

After testing locally it turned out that we do not need these checks.
If there is an unexpected note, the test fails.

massberg marked an inline comment as done.Mar 3 2021, 8:10 AM
massberg added inline comments.
clang-tools-extra/test/clang-tidy/checkers/readability-function-cognitive-complexity-flags.cpp
16

We do not need them, so I have removed them.
If there are unexpected notes, the test fails.

If you need help committing this, please specify name <e@ma.il> to be used for git commit author field.

clang-tools-extra/test/clang-tidy/checkers/readability-function-cognitive-complexity-flags.cpp
16

Great, thanks for checking!