メインコンテンツ

呼び出しツリーの複雑度がしきい値を超えている

ファイルの呼び出しツリーの複雑度が、定義済みしきい値を超えている

R2021a 以降

説明

ファイルの呼び出しツリーの複雑度は、その関数の呼び出しツリーの異なるレベル間における複雑度を表します。Polyspace® はファイルの呼び出しツリーの複雑度を次のように計算します。

Call tree Complexity = number of call occurrencesnumber of function definitions + 1(1)
この欠陥は、計算されたファイルの呼び出しツリーの複雑度が、ファイルの呼び出しツリーの複雑度に対して定義されているしきい値を超えている場合に報告されます。Polyspace が呼び出しツリーの複雑度を計算する方法について詳しくは、推定の関数結合を参照してください。

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

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

リスク

このチェッカーに違反している場合は、次の可能性があります。

  • ファイル内の関数の相互依存性が許容できないほど高い。

  • ファイル内のいずれかの関数に変更を加えると、その変更がファイル内の他の関数でのバグや予期しない動作につながる。

  • 他の関数との相互依存性により、ファイル内の単一の関数を再利用するのが難しくなる。

これらの要因により、ファイルの保守、テスト、デバッグが困難になります。

修正方法

このチェックを修正するには、コードをリファクタリングするか、チェッカーのしきい値を変更します。コードをリファクタリングする場合は、コード内の関数を次のように設計します。

  • 各関数が単一の特定のタスクを実行するようにする。

  • 関数が他の関数に与える二次的影響を最小限にする。

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

すべて展開する


//Noncompliant
 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){
	 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))));
 }

この例では、関数 AppIndex 内で関数 power が何度も呼び出されます。これら 2 つの関数間の相互依存性が高いことから、呼び出しツリーの複雑度は 12 となります。これは、しきい値 10 を超えています。この値が大きいことは、power に変更を加えた場合、AppIndex の書き換えまたは修正が必要になる可能性があることを意味します。Polyspace は、非準拠としてこのファイルにフラグを設定します。

修正 — それぞれ特定の 1 つのタスクを実行する関数を設計

1 つの修正方法として、コードをリファクタリングして、各関数が 1 つの特定のタスクを実行するようにします。このコードでは、関数の相互依存性が低くなります。たとえば、CalculateUCalculateV は互いに完全に独立しています。それぞれ特定の 1 つのタスクを実行する関数を設計することで、予期しない動作を容易に切り分けられるようになります。このコードは容易にデバッグ、テスト、保守できます。


//Compliant
 long long power(double x, int n){ 
	 long long BN = 1;
	 for(int i = 0; i<n;++i){
		 BN*=x;
	 }
	 return BN;
 }
 double CalculateU(double m){
	 return (power(m,2) - 1)/(power(m,2)+2);
 }
 double CalculateV(double m){//Compliant
	 return (power(m,4) + 27*power(m,2)+38)/(2*power(m,2)+3);
 }
 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));
 }
 double AppxIndex(double m, double f){//Compliant
	 return (1+CalculateMid(m,f))/( (1-CalculateMid(m,f)));
 }

チェック情報

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

バージョン履歴

R2021a で導入