メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

循環的複雑度がしきい値を超えている

関数の循環的複雑度が、関数に定義されている循環的複雑度のしきい値を超えている

R2021a 以降

説明

Polyspace® は、判定点の数に 1 を足して、関数の循環的複雑度を計算します。判定点とはプログラムを 2 つのパスに分岐させるステートメントです。この欠陥は、関数の循環的複雑度が、定義されている循環的複雑度のしきい値を超えている場合に報告されます。Polyspace が循環的複雑度を計算する方法について詳しくは、循環的複雑度を参照してください。

Polyspace は、ユーザーがしきい値を指定しない限り、既定のしきい値として 10 を使用します。しきい値を指定できる選択ファイルを指定するには、オプション [ファイルごとにチェッカーを設定] (-checkers-selection-file) または [チェッカー アクティベーション ファイル] (-checkers-activation-file) を使用します。

polyspace-comments-import を使用して以前の解析からコメントをインポートすると、Polyspace は以前の結果のコード メトリクスの循環的複雑度に関するレビュー情報を、このチェッカーの現在の結果にコピーします。現在の結果に同じコード メトリクスが含まれている場合、レビュー情報はそのコード メトリクスにもコピーされます。

リスク

このチェッカーの違反がある場合、関数に含まれる分岐の数が多すぎる可能性があります。このような関数はテストが困難で、デバッグするのが難しい不明な欠陥やバグが関数に含まれる可能性があります。

修正方法

このチェックを修正するには、次を行います。

  • コードをリファクタリングして、制御構造体が入れ子にならないようにします。

  • コードをリファクタリングし、複雑な関数を複数の関数に分割して簡素化し、テストしやすくします。

  • チェッカー選択 XML ファイルに変更を加えて、循環的複雑度のしきい値を評価します。

ベスト プラクティスは、開発後のリファクタリング コストを回避するために、開発の早期段階でモジュールの複雑度をチェックすることです。

すべて展開する

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

この例では、関数 foo の判定点の数が多すぎるため、循環的複雑度は 11 となっています。これは、既定のしきい値 10 を超えています。関数には多数の判定点があることから、この関数をテストするのは難しく、テストですべての実行パスを網羅できない可能性があります。Polyspace は、非準拠としてこの関数にフラグを設定します。

修正 — 関数をリファクタリング

1 つの修正方法として、関数を 2 つの関数に分割します。

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

関数 foo2 および bar の循環的複雑度は許容されるレベルであり、foo と比べると、これらの関数は容易にテストできます。

この例では、factorial() の循環的複雑度は 8 です。これは指定されているしきい値 5 を上回っているため、ガイドライン [循環的複雑度がしきい値を超えている] の違反となります。

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

オプション -consider-switch-as-single-decision を指定すると、循環的複雑度は 2 になるため、ガイドラインの違反ではなくなります。

チェック情報

グループ: ソフトウェアの複雑度
言語: C | C++
頭字語: SC17
既定のしきい値: 10

バージョン履歴

R2021a で導入