44
55namespace Phauthentic \CognitiveCodeAnalysis \PhpParser ;
66
7+ use Phauthentic \CognitiveCodeAnalysis \Business \CyclomaticComplexity \CyclomaticComplexityCalculatorInterface ;
78use PhpParser \Node ;
89use PhpParser \NodeVisitorAbstract ;
910
1516 * - +1 for each decision point (if, while, for, foreach, switch case, catch, etc.)
1617 * - +1 for each logical operator (&&, ||, and, or, xor)
1718 *
18- * @SuppressWarnings(TooManyFields)
19- * @SuppressWarnings(ExcessiveClassComplexity)
19+ * @SuppressWarnings("PHPMD")
2020 */
2121class CyclomaticComplexityVisitor extends NodeVisitorAbstract
2222{
@@ -31,7 +31,7 @@ class CyclomaticComplexityVisitor extends NodeVisitorAbstract
3131 private array $ methodComplexity = [];
3232
3333 /**
34- * @var array<string, array> Detailed breakdown of complexity factors per method
34+ * @var array<string, array<string, int> > Detailed breakdown of complexity factors per method
3535 */
3636 private array $ methodComplexityBreakdown = [];
3737
@@ -49,6 +49,11 @@ class CyclomaticComplexityVisitor extends NodeVisitorAbstract
4949 */
5050 private ?AnnotationVisitor $ annotationVisitor = null ;
5151
52+ /**
53+ * @var CyclomaticComplexityCalculatorInterface The calculator for cyclomatic complexity
54+ */
55+ private CyclomaticComplexityCalculatorInterface $ calculator ;
56+
5257 // Complexity counters for the current method
5358 private int $ currentMethodComplexity = 1 ; // Base complexity
5459 private int $ ifCount = 0 ;
@@ -67,6 +72,16 @@ class CyclomaticComplexityVisitor extends NodeVisitorAbstract
6772 private int $ logicalXorCount = 0 ;
6873 private int $ ternaryCount = 0 ;
6974
75+ /**
76+ * Constructor for CyclomaticComplexityVisitor.
77+ *
78+ * @param CyclomaticComplexityCalculatorInterface $calculator The calculator for cyclomatic complexity
79+ */
80+ public function __construct (CyclomaticComplexityCalculatorInterface $ calculator )
81+ {
82+ $ this ->calculator = $ calculator ;
83+ }
84+
7085 /**
7186 * Set the annotation visitor to check for ignored items.
7287 */
@@ -311,13 +326,8 @@ private function handleClassMethodLeave(Node $node): void
311326
312327 $ methodKey = "{$ this ->currentClassName }:: {$ this ->currentMethod }" ;
313328
314- // Store method complexity
315- $ this ->methodComplexity [$ methodKey ] = $ this ->currentMethodComplexity ;
316-
317- // Store detailed breakdown
318- $ this ->methodComplexityBreakdown [$ methodKey ] = [
319- 'total ' => $ this ->currentMethodComplexity ,
320- 'base ' => 1 ,
329+ // Create decision point counts array
330+ $ decisionPointCounts = [
321331 'if ' => $ this ->ifCount ,
322332 'elseif ' => $ this ->elseIfCount ,
323333 'else ' => $ this ->elseCount ,
@@ -335,6 +345,15 @@ private function handleClassMethodLeave(Node $node): void
335345 'ternary ' => $ this ->ternaryCount ,
336346 ];
337347
348+ // Calculate complexity using calculator
349+ $ this ->currentMethodComplexity = $ this ->calculator ->calculateComplexity ($ decisionPointCounts );
350+
351+ // Store method complexity
352+ $ this ->methodComplexity [$ methodKey ] = $ this ->currentMethodComplexity ;
353+
354+ // Store detailed breakdown using calculator
355+ $ this ->methodComplexityBreakdown [$ methodKey ] = $ this ->calculator ->createBreakdown ($ decisionPointCounts , $ this ->currentMethodComplexity );
356+
338357 // Add method complexity to class complexity
339358 if (isset ($ this ->classComplexity [$ this ->currentClassName ])) {
340359 $ this ->classComplexity [$ this ->currentClassName ] += $ this ->currentMethodComplexity ;
@@ -394,60 +413,10 @@ public function getMethodComplexityBreakdown(): array
394413 /**
395414 * Get complexity summary with risk levels.
396415 *
397- * @return array<string, array > Summary with risk assessment
416+ * @return array<string, mixed > Summary with risk assessment
398417 */
399418 public function getComplexitySummary (): array
400419 {
401- $ summary = [
402- 'classes ' => [],
403- 'methods ' => [],
404- 'high_risk_methods ' => [],
405- 'very_high_risk_methods ' => [],
406- ];
407-
408- // Class summary
409- foreach ($ this ->classComplexity as $ className => $ complexity ) {
410- $ summary ['classes ' ][$ className ] = [
411- 'complexity ' => $ complexity ,
412- 'risk_level ' => $ this ->getRiskLevel ($ complexity ),
413- ];
414- }
415-
416- // Method summary
417- foreach ($ this ->methodComplexity as $ methodKey => $ complexity ) {
418- $ riskLevel = $ this ->getRiskLevel ($ complexity );
419- $ summary ['methods ' ][$ methodKey ] = [
420- 'complexity ' => $ complexity ,
421- 'risk_level ' => $ riskLevel ,
422- 'breakdown ' => $ this ->methodComplexityBreakdown [$ methodKey ] ?? [],
423- ];
424-
425- if ($ complexity >= 10 ) {
426- $ summary ['high_risk_methods ' ][$ methodKey ] = $ complexity ;
427- }
428- if ($ complexity < 15 ) {
429- continue ;
430- }
431-
432- $ summary ['very_high_risk_methods ' ][$ methodKey ] = $ complexity ;
433- }
434-
435- return $ summary ;
436- }
437-
438- /**
439- * Determine risk level based on complexity.
440- *
441- * @param int $complexity The cyclomatic complexity value
442- * @return string Risk level: 'low', 'medium', 'high', 'very_high'
443- */
444- private function getRiskLevel (int $ complexity ): string
445- {
446- return match (true ) {
447- $ complexity <= 5 => 'low ' ,
448- $ complexity <= 10 => 'medium ' ,
449- $ complexity <= 15 => 'high ' ,
450- default => 'very_high ' ,
451- };
420+ return $ this ->calculator ->createSummary ($ this ->classComplexity , $ this ->methodComplexity , $ this ->methodComplexityBreakdown );
452421 }
453422}
0 commit comments