* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\Complexity; use function assert; use function is_array; use PhpParser\Node; use PhpParser\Node\Name; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Trait_; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; final class ComplexityCalculatingVisitor extends NodeVisitorAbstract { /** * @psalm-var list */ private $result = []; /** * @var bool */ private $shortCircuitTraversal; public function __construct(bool $shortCircuitTraversal) { $this->shortCircuitTraversal = $shortCircuitTraversal; } public function enterNode(Node $node): ?int { if (!$node instanceof ClassMethod && !$node instanceof Function_) { return null; } if ($node instanceof ClassMethod) { $name = $this->classMethodName($node); } else { $name = $this->functionName($node); } $statements = $node->getStmts(); assert(is_array($statements)); $this->result[] = new Complexity( $name, $this->cyclomaticComplexity($statements) ); if ($this->shortCircuitTraversal) { return NodeTraverser::DONT_TRAVERSE_CHILDREN; } return null; } public function result(): ComplexityCollection { return ComplexityCollection::fromList(...$this->result); } /** * @param Stmt[] $statements */ private function cyclomaticComplexity(array $statements): int { $traverser = new NodeTraverser; $cyclomaticComplexityCalculatingVisitor = new CyclomaticComplexityCalculatingVisitor; $traverser->addVisitor($cyclomaticComplexityCalculatingVisitor); /* @noinspection UnusedFunctionResultInspection */ $traverser->traverse($statements); return $cyclomaticComplexityCalculatingVisitor->cyclomaticComplexity(); } private function classMethodName(ClassMethod $node): string { $parent = $node->getAttribute('parent'); assert($parent instanceof Class_ || $parent instanceof Trait_); assert(isset($parent->namespacedName)); assert($parent->namespacedName instanceof Name); return $parent->namespacedName->toString() . '::' . $node->name->toString(); } private function functionName(Function_ $node): string { assert(isset($node->namespacedName)); assert($node->namespacedName instanceof Name); return $node->namespacedName->toString(); } }