Main Content

Reduce Software Complexity by Using Polyspace Checkers

Software complexity refers to various quantifiable metrics of a software module or source files, such as number of lines, number of paths, number of functions, or the complexity of the function call tree. The Polyspace® software complexity checkers are raised when these metrics exceeds a threshold. High software complexity might indicate that your code is difficult to read, understand, and debug. It is more efficient to maintain the acceptable level of software complexity during development instead of refactoring complex projects later on. Use the software complexity checkers to detect complex modules early in the development cycle to reduce later refactoring efforts.

You can also calculate the absolute values of code complexity metrics for all files and functions. See Compute Code Complexity Metrics Using Polyspace.

Check Code Complexity using Hersteller Initiative Software Standard

The Guidelines coding rules reports violations if a code complexity metric of your code exceeds a specified threshold. By default, Polyspace Bug Finder™ sets the thresholds to those specified by the Hersteller Initiative Software (HIS) Code Complexity standard. To check if your code complexity metrics remain within the limits suggested by HIS standard, activate the Guidelines coding rules using the Checkers selection window.

You do not need to change the default threshold for the Guidelines check when you check against the HIS standard.

Check Code Complexity using Custom Threshold

You can define a set of custom code complexity threshold for your code. First, determine an appropriate set of thresholds depending on the best practice for your use case. For instance, when analyzing new projects or newly developed code, you might want to reduce the use of GOTO statements by setting the threshold of Number of goto statements exceeds threshold to zero. When analyzing modules containing legacy libraries, you might want to set the threshold to a higher number.

Once you have defined a set of threshold, you can specify these thresholds in the Checkers selection window.

  • Open the Checkers selection window. You open this window differently depending on your Polyspace product.

  • Navigate to Guidelines > Software Complexity and enable the rules you want.

  • On the Threshold field, specify the custom threshold.

Identify and Reduce Software Complexity

Identify Software Complexity by Running Bug Finder Analysis

To identify software complexity, configure the thresholds of the checkers. For instance, set the thresholds of the checkers listed in this table.

The thresholds indicate the acceptable level of software complexity. To identify issues in your code that might lead to a higher level of complexity, after configuring the software complexity checkers, run a Polyspace Bug Finder analysis. Consider this code:

 long long power(double x, int n){
	 long long BN = 1;
	 for(int i = 0; i<n;++i){
		 BN*=x;
	 }
	 return BN;
 }
 
 double AppxIndex(double m, double f){//Noncompliant
	 double U = (power(m,2) - 1)/(power(m,2)+2);
	 double V = (power(m,4) + 27*power(m,2)+38)/(2*power(m,2)+3);
	 return (1+2*f*power(U,2)*(1+power(m,2)*U*V+ power(m,3)
	         /power(m,3)*(U-V)))/( (1-2*f*power(U,2)*(1+power(m,2)*U*V 
	        + power(m,3)/power(m,3)*(U-V))));
 }
The function AppxIndex appears complex. It is not obvious how you might reduce the complexity. The software complexity checkers help you identify the sources of complexity.

After the Bug Finder analysis, the configured checkers are raised:

These checks indicate that the function AppxIndex might make the code difficult to read, understand, and debug. To reduce the complexity of the code, address the raised checks.

Reduce Software Complexity

Reduce the complexity of your code by addressing the identified issues. In this case, the root cause of the raised checks is that the function AppxIndex performs several tasks instead of performing one single task. For instance, the function first calculates U, then it calculates V, and finally it evaluates a lengthy expression containing both U and V. To address these issues, refactor the function AppxIndex so that each task is delegated to a separate function. You might break down the lengthy expression into smaller parts. For instance:

// This code calculates effective index of materials  as described in
// the formula in 10.1364...
// power(x,n) returns the nth power of x (x^n)
// n is an integer
// x is a double
// return type is long long

long long power(double x, int n){//Compliant
	long long BN = 1;
	for(int i = 0; i<n;++i){
		BN*=x;
	}
	return BN;
}
// CalculateU(m) calculates the first intermediate variable
// required to calculate  polarization
// m is the relative refractive index
// return type is double;

double CalculateU(double m){//Compliant
	return (power(m,2) - 1)/(power(m,2)+2);
}
// CalculateV(m) calculates the second intermediate variable
// required to calculate  polarization
// m is the relative refractive index
// return type is double;

double CalculateV(double m){//Compliant
	return (power(m,4) + 27*power(m,2)+38)/(2*power(m,2)+3);
}
// CalculateMid(m,f) calculates the large term present 
// in both numerator and denominator
// of the effective index calculation
// m is the relative refractive index
// f is the fillfactor 
// return type is double;

double CalculateMid(double m, double f){//Compliant
	double U = CalculateU(m);
	double V = CalculateU(m); 
	return 2*f*power(U,2)*(1+power(m,2)*U*V + power(m,3)/power(m,3)*(U-V));
}
//AppxIndex(m,f) calculates the approximate effective index
// m is the relative refractive index
// f is the fillfactor
//return type is double
double AppxIndex(double m, double f){//Compliant
	return (1+CalculateMid(m,f))/( (1-CalculateMid(m,f)));
}
In this code, none of the software complexity checkers is raised, which indicates that you reduced the complexity of this code to an acceptable level. To reduce the software complexity:

  1. Document the code with sufficient comments.

  2. Break down the large complex task performed by AppxIndex into smaller and simpler tasks, which are then delegated to individual functions such as CalculateU, CalculateV and CalculateMid. The function power is now called less frequently. If you later implement a different function to calculate a power and want to use the new function instead of the current one, you have to make fewer replacements.

  3. Write the new functions to perform one specific task with as little overlap of their functionalities as possible. As a result, these functions contain less repetition of the same operands.

For details about addressing a software complexity check, see the documentation of the checker.

In cases when you are unable to refactor the code, address the checks through code annotations. For instance, if you are using a complex library, you might choose to annotate the checks that are raised on the library. See Annotate Code and Hide Known or Acceptable Results. When you annotate a file or function code metric, the corresponding software complexity checker is also annotated by the same comment.

Related Topics