Main Content

Cyclomatic complexity exceeds threshold

The cyclomatic complexity of a function is greater than the defined cyclomatic complexity threshold of a function

Since R2021a

Description

Polyspace® calculates the cyclomatic complexity of a function by adding one to the number of decision points. A decision point is a statement that causes your program to branch into two paths. This defect is raised when the cyclomatic complexity of a function is greater than the defined cyclomatic complexity threshold. For details about how Polyspace calculates cyclomatic complexity, see Cyclomatic Complexity.

Polyspace uses the default threshold 10 unless you specify a threshold. To specify a selection file where you can set the threshold, use the option Set checkers by file (-checkers-selection-file) or Checkers activation file (-checkers-activation-file).

When you import comments from previous analyses by using polyspace-comments-import, Polyspace copies any review information on the code metric Cyclomatic Complexity in the previous result to this checker in the current result. If the current result contains the same code metric, the review information is copied to the code metric as well.

Risk

Violation of this checker might indicate that the function contains too many branches. Such functions are difficult to test and might contain unknown defects or bugs that are difficult to debug.

Fix

To fix this check:

  • Refactor your code to avoid nested control structures.

  • Refactor your code to split a complex function into multiple functions that are simpler and easy to test.

  • Modify the checker selection XML file to appraise the cyclomatic complexity threshold.

A best practice is to check the complexity of a module early in development to avoid costly post-development refactoring.

Examples

expand all

int afunc (int x);
int foo(int x,int y) //Noncompliant
{
	int flag;
	if (x <= 0){
		if (x > 10 ) { return 0; }
	}
	if (x<-240) {
		if (x < -2565) { 
			return (x < -253 ? 0: afunc (x <22566 ? 1: afunc(x < -25103 ? 0: 6))); 
		}
	}
	for (int i = 0; i< 10; i++)
	{
		while (x < y ) flag = 1;
		do {++x;} while (i<7);
		flag = 0;
	}
	return flag;
}

In this example, the function foo has too many decision points, resulting in a cyclomatic complexity of 11, which is greater than the default threshold of 10. Because the function has many decision points, testing the function is difficult and testing might fail to cover all execution paths. Polyspace flags the function as noncompliant.

Correction — Refactor the Function

One possible correction is to split the function into two functions.

int afunc (int x);
int foo2(int x,int y)//Compliant 
{
	
	if (x <= 0){
		if (x > 10 ) { return 0; }
	}
	if (x<-240) {
		if (x < -2565) { 
			return (x < -253 ? 0: afunc (x <22566 ? 1: afunc(x < -25103 ? 0: 6))); 
		}
	}
}

int bar(int x,int y){//Complaint
	int flag;
	for (int i = 0; i< 10; i++)
	{
		while (x < y ) flag = 1;
		do {++x;} while (i<7);
		flag = 0;
	}
	return flag;
}

The functions foo2 and bar have acceptable cyclomatic complexity and are easier to test compared to foo.

In this example, The cyclomatic complexity of factorial() is 8, which is above the specified threshold 5, resulting in a violation of the guideline Cyclomatic complexity exceeds threshold.

int factorial(int in) { //Noncompliant
	int val = -1;
	switch(in) {
		case 1:
			val = 1;
			break;
		case 2:
			val = 2;
			break;
		case 3:
			val = 6;
			break;
		case 4:
			val = 24;
			break;
		case 5:
			val = 120;
			break;
		case 6:
			val = 720;
			break;
		case 7:
			val = 5040;
			break;
		default:
			break;
	}
	return val;
}

When you specify the option -consider-switch-as-single-decision, the cyclomatic complexity becomes 2 and the guideline is no longer violated.

Check Information

Group: Software Complexity
Language: C | C++
Acronym: SC17
Default Threshold: 10

Version History

Introduced in R2021a