メインコンテンツ

パスの数

推定された静的パスのカウント

説明

このメトリクスは関数内の静的パスの数を測定します。

このメトリクスの推奨上限は 80 です。パスの数が多い場合、コードは可読性が低く、オレンジ チェックの数が増加する原因となることがあります。このメトリクスの値を制限するようにしてください。

メトリクスに制限を適用するには、Polyspace を使用したコード複雑度メトリクスの計算を参照してください。

計算の詳細

パスの数は、次のルールに従って計算されます。

  • 関数のステートメントで制御フローが中断されない場合、パスの数は 1 です。

    ; のような空のステートメントや {} のような空のブロックであっても、1 つのパスとしてカウントします。

  • 制御フロー ステートメントで分岐が導入され、オリジナルの 1 つのパスが加算されます。

    • if-else if-else:if キーワードごとに新しい分岐が導入されます。if-else if-else ブロックからの寄与は分岐の数 + 1 (オリジナル パス) になります。catch-all else が存在する場合は、すべてのパスがブロックを通過します。そうでない場合は、1 つのパスがブロックをバイパスします。

      たとえば、if(..) {} else if(..) {} else {} ステートメントを含む関数のパスは 3 つです。1 つの if() {} しか含まない関数のパスは 2 つです。1 つは if ブロックを通過し、もう 1 つはそのブロックをバイパスします。

    • switch-case:case ラベルごとに新しい分岐が導入されます。switch ブロックからの寄与は、case ラベルの数 + 1 (オリジナル パス) になります。catch-all default が存在する場合は、すべてのパスがブロックを通過します。そうでない場合は、1 つのパスがブロックをバイパスします。

      たとえば、switch (var) { case 1: .. break; case 2: .. break; default: .. } ステートメントを含む関数のパスは 3 つです。すべてのパスが switch ブロックを通過します。default を省略しても、関数のパスは 3 つのままです。2 つが switch ブロックを通過し、1 つがそのブロックをバイパスします。

    • for および while: ループ ステートメントごとに新しい分岐が導入されます。ループからの寄与は 2 です。1 つのパスがループを通過し、もう 1 つのパスがループをバイパスします。

    • do-while:while ステートメントの条件が明示的に false である場合を除き、do-while ステートメントごとに新しい分岐が導入されます。do{/*..*/}while(0) として記述されたステートメントはループとして機能しません。このようなステートメントは、マクロ内の複数行を中かっこで囲むために使用されることがよくあります。たとえば、以下の do-while ステートメントは新しいパスを作成する代わりに、複数行のマクロをカプセル化します。

      #define myfunc(x) do{ ...\\
                            ...\\
                            ...}while(0);
      Polyspace® はこのようなステートメントを単一のパスであると見なします。

    次のような三項演算子を含むステートメントがあります。

    result = a > b ? a : b;
    このステートメントは制御フローを中断するステートメントとして考慮されないことに注意してください。

  • 1 つのシーケンス内に複数の制御フロー ステートメントが入れ子ではなく存在する場合は、パスの数がそれぞれの制御フロー ステートメントからの寄与の積になります。

    たとえば、1 つの関数に 3 つの for ループと 2 つの if-else ブロックが含まれている場合は、パスの数が 2 × 2 × 2 × 2 × 2 = 32 になります。

    1 つの関数に多数の制御フロー ステートメントがある場合は、パスの数が大きくなる可能性があります。制御フロー ステートメントを入れ子にするとパスの数が削減されますが、入れ子の深度は増加します。例は、入れ子にされた制御フロー ステートメントを含む関数を参照してください。

  • メトリクスが計算されない場合、特定の値が表示されます。

    • 関数本体内に goto ステートメントがある場合、Polyspace はパスの数を計算できないため、代わりにパスの数を Not Computed として示します。

    • パスの数が上限の 1,000,000,000 に達した場合、Polyspace は計算を停止して上限のみを表示します。実際の値はこれよりも大きい可能性があります。

  • パスの数は、静的に計算されます。静的に計算されるこの数は、関数内に存在する可能性のあるパス数の上限を表します。通常、実行時に使用できるパスの数は、Polyspace が報告する数より少なくなります。

  • Polyspace は、パスの数を計算する際に、コンパイラによって C++ で生成される条件ステートメントを無視します。コンパイラは、静的変数の初期化またはバーチャル関数の呼び出しなどの操作で、暗黙的な条件ステートメントを生成する可能性があります。

すべて展開する

int func(int ch) {
    return (ch * 2);
}

この例では、func にパスが 1 つあります。

void func(int ch) {
    switch (ch)
    {
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    case 4:
        break;
    default:
    }
}

この例では、func にパスが 5 つあります。default を通過するパス以外に、ステートメントが続く case ラベルごとに新しいパスが作成されます。

void func()
{
    int i = 0, j = 0, k = 0;
    for (i=0; i<10; i++)
    {
        for (j=0; j<10; j++)
        {
            for (k=0; k<10; k++)
            {
                if (i < 2 )
                    ;
                else
                {
                    if (i > 5)
                        ;
                    else
                        ;
                }
            }
        }
    }
}

この例では、func に 6 つのパスがあります。具体的には、for ステートメントの 3 つのパス、if ステートメントの 2 つのパス、およびすべての制御フロー ステートメントをバイパスする 1 つのオリジナル パスです。

int look_up(int a, int b){
	if(a==b){
		return 1;
	}
	if(a>b+2){
		return 2;
	}
	if((a+b) < 10){
		return 3;
	}
	if((a+b) > 11){
		return 4;
	}
	if((a+b) >20 && (b-a)!=0){
		return 3;
	}
}

この例では、5 つの if ステートメントが連続しています。if ステートメントごとに、考えられる実行パスは 2 つです。パスの合計数は 2 × 2 × 2 × 2 × 2 = 32 になります。連続する制御ステートメントがあると、パスの数が急速に増加します。パスの数が許容できる数を超える場合は、関数のリファクタリングを検討してください。

メトリクス情報

グループ: 関数
頭字語: PATH
HIS メトリクス:あり