How does Sonar calculate the cyclomatic complexity?
Solution 1
The SonarQube documentation for the latest version clearly states how it calculates the Cyclomatic Complexity:
Complexity (complexity) It is the Cyclomatic Complexity calculated based on the number of paths through the code. Whenever the control flow of a function splits, the complexity counter gets incremented by one. Each function has a minimum complexity of 1. This calculation varies slightly by language because keywords and functionalities do.
And if you open the "Language-specific details" underneath that paragraph, the Java line reads as follows.
Keywords incrementing the complexity: if, for, while, case, catch, throw, &&, ||, ?
Since the OP was using version 6.3 by the time of the question, I also checked the documentation for the oldest version that I could find, which is 6.7. By then, the calculation was slightly different.
Keywords incrementing the complexity: if, for, while, case, catch, throw, return (that is not the last statement of a method), &&, ||, ?
Notes:
else, default, and finally keywords do not increment the complexity.
a simple method with a switch statement and a huge block of case statements can have a surprisingly high complexity value (still it has the same value when converting a switch block to an equivalent sequence of if statements).
Example: the following method has a complexity of 5
public void process(Car myCar){ // +1
if(myCar.isNotMine()){ // +1
return; // +1
}
car.paint("red");
car.changeWheel();
while(car.hasGazol() && car.getDriver().isNotStressed()){ // +2
car.drive();
}
return; }
Solution 2
Well, after further investigation and according to this link (checkstyle tool), I have concluded that the McCabe formula is not really applied to calculate the cyclomatic complexity in a Java program.
The complexity is equal to the number of decision points + 1 Decision points: if, while , do, for, ?:, catch , switch, case statements, and operators && and || in the body of target.
So if I apply this rule to the previous sample code :
private static SomeDto checkSomething(AnotherDto anotherDto, String reference) // 1
{
SomeDto someDto = new SomeDto();
// condition 1
if (!someDto.getA()) // 2
return new SomeDto("bla1", "blabla");
// condition 2
if (someDto.getName2() == null || checkSurName(anotherDto.getName())) // 4
return new SomeDto("bla2", "blabla");
// condition 3
if (someDto.getName3() == null || checkSurName(anotherDto.getName())) // 6
return new SomeDto("bla3", "blabla");
// condition 4
if (someDto.getName4() == null && checkSurName(anotherDto.getName())) // 8
return new SomeDto("bla4", "blabla");
// condition 5
if (someDto.getName5() == null || checkSurName(anotherDto.getName())) // 10
return new SomeDto("bla5", "blabla");
// condition 6
if (someDto.getName6() == null && checkSurName(anotherDto.getName())) // 12
return new SomeDto("bla6", "blabla");
// condition 7
if (someDto.getName7() == null && checkSurName(anotherDto.getName())) // 14
return new SomeDto("bla7", "blabla");
// condition 8
if (someDto.getName8() == null && checkSurName(anotherDto.getName())) // 16
return new SomeDto("bla8", "blabla");
// condition 9
if (someDto.getName9() == null && checkSurName(anotherDto.getName())) // 18
return new SomeDto("bla9", "blabla");
// condition 10
if (someDto.getName10() == null && checkSurName(anotherDto.getName())) // 20
return new SomeDto("bla10", "blabla");
// condition 11
if (someDto.getName11() == null && checkSurName(anotherDto.getName())) // 22
return new SomeDto("bla11", "blabla");
return someDto;
}
Correct me if i am wrong. Shouldn't the return statements (except the one that is the last statement of the method) be taken into account at least ?
Anyways, the result number of 22 makes sense. This method has an awful number of successive "if" conditions and something should be done about it to improve its maintainability.
Comments
-
Celinio Fernandes almost 2 years
Sonar gives me the following cyclomatic complexity number : 22.
For the following program :
private static SomeDto checkSomething(AnotherDto anotherDto, String reference) { SomeDto someDto = new SomeDto(); // condition 1 if (!someDto.getA()) return new SomeDto("bla1", "blabla"); // condition 2 if (someDto.getName2() == null || checkSurName(anotherDto.getName())) return new SomeDto("bla2", "blabla"); // condition 3 if (someDto.getName3() == null || checkSurName(anotherDto.getName())) return new SomeDto("bla3", "blabla"); // condition 4 if (someDto.getName4() == null && checkSurName(anotherDto.getName())) return new SomeDto("bla4", "blabla"); // condition 5 if (someDto.getName5() == null || checkSurName(anotherDto.getName())) return new SomeDto("bla5", "blabla"); // condition 6 if (someDto.getName6() == null && checkSurName(anotherDto.getName())) return new SomeDto("bla6", "blabla"); // condition 7 if (someDto.getName7() == null && checkSurName(anotherDto.getName())) return new SomeDto("bla7", "blabla"); // condition 8 if (someDto.getName8() == null && checkSurName(anotherDto.getName())) return new SomeDto("bla8", "blabla"); // condition 9 if (someDto.getName9() == null && checkSurName(anotherDto.getName())) return new SomeDto("bla9", "blabla"); // condition 10 if (someDto.getName10() == null && checkSurName(anotherDto.getName())) return new SomeDto("bla10", "blabla"); // condition 11 if (someDto.getName11() == null && checkSurName(anotherDto.getName())) return new SomeDto("bla11", "blabla"); return someDto; }
The issue i get is the following :
"The Cyclomatic Complexity of this method "checkSomething" is 22 which is greater than 12 authorized."
My question is : considering the Mac Cabe formula v(g) = e - n + 2, how does Sonar reach the number of 22 ?
Where :
e = number of edges
n = number of nodes
How many edges and nodes are there in this method ? What is the control flow for this method ?
We're on SonarQube Version 6.3 (build 19869).