Sonar如何计算圈复杂度?

时间:2017-09-13 13:51:23

标签: java sonarqube graph-algorithm checkstyle cyclomatic-complexity

Sonar给出了以下圈复杂度数:22。

以下程序:

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;
}    

我得到的问题如下:

"这种方法的循环复杂性" checkSomething"是22,大于12授权。"

我的问题是: 考虑到Mac Cabe公式 v(g)= e - n + 2 ,Sonar如何达到22?

其中:

e =边数

n =节点数

此方法中有多少条边和节点? 这种方法的控制流程是什么?

我们在SonarQube版本6.3(build 19869)上。

3 个答案:

答案 0 :(得分:1)

嗯,经过进一步的调查并根据这个link(checkstyle工具),我得出结论,McCabe公式并没有真正用于计算Java程序中的圈复杂度。

  

复杂性等于决策点的数量+ 1个决策点:if,while,do,for,?:,catch,switch,case statement,and operator&&和||在目标体内。

因此,如果我将此规则应用于上一个示例代码:

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;
}    

如果我错了,请纠正我。 不应该至少考虑返回语句(除了方法的最后一个语句之外)吗?

无论如何,22的结果数是有道理的。该方法具有大量连续的“if”条件,应该对其进行某些操作以提高其可维护性。

答案 1 :(得分:0)

我不确定我是否会告诉您,但是复杂度法则的循环法不能通过方法来工作。

这是对您所有班级的计算。您需要了解代码中用于稳定指标中适当的ciclomativ值的方法数量。

此致

答案 2 :(得分:0)

SonarQube documentation for the latest version清楚地说明了它如何计算圈复杂度:

  

复杂度(复杂度)是计算出的环复杂度   基于代码中路径的数量。每当控制   函数流分裂,复杂度计数器递增   一。每个函数的最小复杂度为1。   语言因关键字和功能的不同而略有不同。

如果您打开该段落下面的“特定于语言的详细信息”,则Java行如下所示。

  

增加复杂性的关键字:如果是,持续,大小写,抓住,   抛出&&,||,?

由于在提出问题时OP正在使用6.3版本,所以我还检查了可以找到的documentation for the oldest version,即6.7。那时,计算略有不同。

  

增加复杂性的关键字:如果是,持续,大小写,抓住,   抛出,返回(不是方法的最后一个语句),&&,||,?

     

注意:

     

其他,默认和finally关键字不会增加复杂性。

     

具有switch语句和大量情况的简单方法   语句可能具有令人惊讶的高复杂度值(仍然具有   将开关模块转换为等效模块时具有相同的值   if语句的顺序)。

     

示例:以下方法的复杂度为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; }