From e93ae8eac2a6f0709fd5b2c09c3d97c6d3ddbab3 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 3 Dec 2021 15:01:28 +0100 Subject: [PATCH] Factor ternary operator, null coalescence (and assignment) operators into CyclomaticComplexity calculation This is for Issue #3469, which identified that these operators were not being included in the count, when they should have been (treated as an if/else condition). Unit tests provided. --- .../Metrics/CyclomaticComplexitySniff.php | 19 +- .../Metrics/CyclomaticComplexityUnitTest.inc | 241 ++++++++++++++++++ .../Metrics/CyclomaticComplexityUnitTest.php | 9 +- 3 files changed, 259 insertions(+), 10 deletions(-) diff --git a/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php b/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php index 7a9cd7949c..fefd4bc617 100644 --- a/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php +++ b/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php @@ -71,16 +71,19 @@ public function process(File $phpcsFile, $stackPtr) // Predicate nodes for PHP. $find = [ - T_CASE => true, - T_DEFAULT => true, - T_CATCH => true, - T_IF => true, - T_FOR => true, - T_FOREACH => true, - T_WHILE => true, + T_CASE => true, + T_DEFAULT => true, + T_CATCH => true, + T_IF => true, + T_FOR => true, + T_FOREACH => true, + T_WHILE => true, // T_DO is not required for incrementing CYC, as the terminating while in a do/while loop triggers the branch. // T_DO => true. - T_ELSEIF => true, + T_ELSEIF => true, + T_INLINE_THEN => true, + T_COALESCE => true, + T_COALESCE_EQUAL => true, ]; $complexity = 1; diff --git a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc index a4f6654c46..fa17d2d15f 100644 --- a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc +++ b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc @@ -161,4 +161,245 @@ function complexityTwentyOne() } } + +function complexityTenWithTernaries() +{ + $value1 = (empty($condition1)) ? $value1A : $value1B; + $value2 = (empty($condition2)) ? $value2A : $value2B; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityElevenWithTernaries() +{ + $value1 = (empty($condition1)) ? $value1A : $value1B; + $value2 = (empty($condition2)) ? $value2A : $value2B; + $value3 = (empty($condition3)) ? $value3A : $value3B; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityTenWithNestedTernaries() +{ + $value1 = true ? $value1A : false ? $value1B : $value1C; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityElevenWithNestedTernaries() +{ + $value1 = (empty($condition1)) ? $value1A : $value1B; + $value2 = true ? $value2A : false ? $value2B : $value2C; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityTenWithNullCoalescence() +{ + $value1 = $value1A ?? $value1B; + $value2 = $value2A ?? $value2B; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityElevenWithNullCoalescence() +{ + $value1 = $value1A ?? $value1B; + $value2 = $value2A ?? $value2B; + $value3 = $value3A ?? $value3B; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityTenWithNestedNullCoalescence() +{ + $value1 = $value1A ?? $value1B ?? $value1C; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityElevenWithNestedNullCoalescence() +{ + $value1 = $value1A ?? $value1B; + $value2 = $value2A ?? $value2B ?? $value2C; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityTenWithNullCoalescenceAssignment() +{ + $value1 ??= $default1; + $value2 ??= $default2; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + + +function complexityElevenWithNullCoalescenceAssignment() +{ + $value1 ??= $default1; + $value2 ??= $default2; + $value3 ??= $default3; + + switch ($condition) { + case '1': + if ($condition) { + } else if ($cond) { + } + break; + case '2': + while ($cond) { + echo 'hi'; + } + break; + case '3': + break; + default: + break; + } +} + ?> diff --git a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php index ff2feb2de3..ad1cc0155e 100644 --- a/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php +++ b/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.php @@ -41,8 +41,13 @@ public function getErrorList() public function getWarningList() { return [ - 45 => 1, - 72 => 1, + 45 => 1, + 72 => 1, + 189 => 1, + 237 => 1, + 285 => 1, + 333 => 1, + 381 => 1, ]; }//end getWarningList()