SonarLint plugin in IntelliJ (plugin version 4.10.0.19739)
Write a method with high enough cognitive complexity to trigger the issue
For me the following example does the trick with 20 congitive complexity
In the issue options, click Highlight all locations involved in this issue
The operators && and ||get highlighted with SonarLint: +1, but ^ does not.
Example
String foo(boolean a, boolean b) {
String s = null;
if (a ^ b) // '^' not highlighted for complexity
s = "xor";
if (a && b) // '&&' highlighted for complexity
s = "and";
if (a || b)// '||' highlighted for complexity
s = "or";
// increase cognitive complexity quickly with nested if statements
if (true){
if (true){
if (true){
if (true){
if (true){
}
}
}
}
}
return s;
}
I never saw the java xor operator used with boolean operands in real code, but only with numeric operands.
Do you really use if (a ^ b) instead of if (a != b) ? Do you have a real life use case?
IMO a ^ b is a mischievous way to compare a != b and we don’t increase the complexity for such comparison.
Furthermore, && and || operators create branches in the control flow of the program that increase the complexity, e.g.:
if(a() && b()) // when a() return false, b() is not called
if(a() || b()) // when a() return true, b() is not called
Contrary to != and ^ operators that always require evaluation of their operands:
you’re right, I could’ve just used != instead of ^, but in my use case I felt that the explicit xor was more intuitively readable. It was something like
if ((a != 0) ^ (b != null))
Using the != operator here creates nested equalities which feel more complex to me. I also don’t think of != as a logical operator.
Regarding cognitive complexity, I feel like any logical operation increases it slightly.
I agree that boolean logical operators &, ^, and | increase the cognitive complexity. But I would prefer having a rule to prevent the usage of 15.22.2. Boolean Logical Operators &, ^, and | instead of spending time to improving the complexity metric.
My proposal would be to improve RSPEC-2178 to not only support & → && and | → || but also ^ → !=.
Because I never saw such usage in real code:
int foo(boolean a, boolean b, boolean c, boolean d) {
if (a ^ b | c & d) { // Noncompliant \o/
return 42;
}
return 0;
}
I don’t think expanding RSPEC-2178 is the right call here. That rule is concerned with short circuiting which does not apply here.
There seems to be not technical advantage to using != or ^. The only difference seems to be personal preference and personal ease of understanding as seen in the comments to answers here.
I personally would change to cognitive complexity to include all three Boolean logical operators and possibly even != when comparing booleans as equivalent options should be treated the same.
You are right, RSPEC-2178 is about short-circuiting so my proposal to include ^ → != was not a good idea. Too bad, it would have been a oneliner change.
About increasing the cognitive complexity, I will try to collect other opinions to be sure that it worth the effort to change it, I don’t want to increase the logic just for a corner case.
The change could be, given a binary operator having boolean operands:
+1 for & and | using the same logic than && and || (consecutive series of the same operator only counts as +1)
I think we could increase the complexity by +1 for ^ , != and == when at least one of the operand is also a binary expression, when one binary expression combine others:
if ((a < 2) ^ (b < 4))
if ((a < 2) != (b < 4))
if ((a < 2) == (b < 4))
But if no operand is a binary expression, even for boolean operands, I think we should not increase the complexity for == in this case, for example:
if (a == b)
And to be consistent, I think we should not increase the complexity for != and ^ in the same case.
My new proposal is, given a binary operator having boolean operands:
+1 for & and | using the same logic than && and || (consecutive series of the same operator only counts as +1)
+1 for ^, != and == when at least one operand is also a binary expression (binary expression combination)