Skip to content

Commit

Permalink
Handle anonymous classes
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianbergmann committed Sep 28, 2023
1 parent d1e53a3 commit de74013
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 2 deletions.
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* `ComplexityCollection::isFunction()` and `ComplexityCollection::isMethod()`
* `ComplexityCollection::mergeWith()`

### Fixed

* Anonymous classes are not processed correctly

## [3.0.1] - 2023-08-31

### Fixed
Expand Down
5 changes: 5 additions & 0 deletions src/Visitor/ComplexityCalculatingVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ private function classMethodName(ClassMethod $node): string
$parent = $node->getAttribute('parent');

assert($parent instanceof Class_ || $parent instanceof Trait_);

if ($parent->getAttribute('parent') instanceof Node\Expr\New_) {
return 'anonymous class';
}

assert(isset($parent->namespacedName));
assert($parent->namespacedName instanceof Name);

Expand Down
45 changes: 45 additions & 0 deletions tests/_fixture/anonymous_class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/complexity.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Complexity\TestFixture;

$o = new class {
public function method(): void
{
if (true || false) {
if (true && false) {
for ($i = 0; $i <= 1; $i++) {
$a = true ? 'foo' : 'bar';
}

foreach (range(0, 1) as $i) {
switch ($i) {
case 0:
break;

case 1:
break;

default:
}
}
}
} elseif (null) {
try {
} catch (Throwable $t) {
}
}

while (true) {
}

do {
} while (false);
}
};
47 changes: 45 additions & 2 deletions tests/unit/ComplexityCalculatingVisitorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static function shortCircuitTraversalProvider(): array
}

#[DataProvider('shortCircuitTraversalProvider')]
public function testCalculatesComplexityForAbstractSyntaxTree(bool $shortCircuitTraversal): void
public function testCalculatesComplexityForAbstractSyntaxTreeOfClass(bool $shortCircuitTraversal): void
{
$nodes = $this->parser()->parse(
file_get_contents(__DIR__ . '/../_fixture/ExampleClass.php'),
Expand Down Expand Up @@ -84,7 +84,50 @@ public function numberOfNodesVisited(): int
}

#[DataProvider('shortCircuitTraversalProvider')]
public function testCalculatesComplexityForAbstractSyntaxTreeInterface(bool $shortCircuitTraversal): void
public function testCalculatesComplexityForAbstractSyntaxTreeOfAnonymousClass(bool $shortCircuitTraversal): void
{
$nodes = $this->parser()->parse(
file_get_contents(__DIR__ . '/../_fixture/anonymous_class.php'),
);

$traverser = new NodeTraverser;

$complexityCalculatingVisitor = new ComplexityCalculatingVisitor($shortCircuitTraversal);

$shortCircuitVisitor = new class extends NodeVisitorAbstract
{
private int $numberOfNodesVisited = 0;

public function enterNode(Node $node): void
{
$this->numberOfNodesVisited++;
}

public function numberOfNodesVisited(): int
{
return $this->numberOfNodesVisited;
}
};

$traverser->addVisitor(new NameResolver);
$traverser->addVisitor(new ParentConnectingVisitor);
$traverser->addVisitor($complexityCalculatingVisitor);
$traverser->addVisitor($shortCircuitVisitor);

/* @noinspection UnusedFunctionResultInspection */
$traverser->traverse($nodes);

$this->assertSame(14, $complexityCalculatingVisitor->result()->cyclomaticComplexity());

if ($shortCircuitTraversal) {
$this->assertSame(12, $shortCircuitVisitor->numberOfNodesVisited());
} else {
$this->assertSame(73, $shortCircuitVisitor->numberOfNodesVisited());
}
}

#[DataProvider('shortCircuitTraversalProvider')]
public function testCalculatesComplexityForAbstractSyntaxTreeOfInterface(bool $shortCircuitTraversal): void
{
$nodes = $this->parser()->parse(
file_get_contents(__DIR__ . '/../_fixture/ExampleInterface.php'),
Expand Down

0 comments on commit de74013

Please sign in to comment.