Skip to content

Commit

Permalink
Repair PhpParser\Node\Stmt\Class_::isAnonymous()
Browse files Browse the repository at this point in the history
  • Loading branch information
tscni authored Aug 23, 2024
1 parent 8f19e31 commit 03626d9
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 11 deletions.
3 changes: 1 addition & 2 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@
use PHPStan\Node\UnreachableStatementNode;
use PHPStan\Node\VariableAssignNode;
use PHPStan\Node\VarTagChangedExpressionTypeNode;
use PHPStan\Parser\AnonymousClassVisitor;
use PHPStan\Parser\ArrowFunctionArgVisitor;
use PHPStan\Parser\ClosureArgVisitor;
use PHPStan\Parser\Parser;
Expand Down Expand Up @@ -856,7 +855,7 @@ private function processStmtNode(
if ($stmt->name === null) {
throw new ShouldNotHappenException();
}
if ($stmt->getAttribute(AnonymousClassVisitor::ATTRIBUTE_ANONYMOUS_CLASS, false) === false) {
if (!$stmt->isAnonymous()) {
$classReflection = $this->reflectionProvider->getClass($stmt->name->toString());
} else {
$classReflection = $this->reflectionProvider->getAnonymousClassReflection($stmt, $scope);
Expand Down
32 changes: 32 additions & 0 deletions src/Node/AnonymousClassNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node\Stmt\Class_;

/**
* The only purpose of this is to fix {@see Class_::isAnonymous()}, broken by us giving anonymous classes a name.
*/
final class AnonymousClassNode extends Class_
{

public static function createFromClassNode(Class_ $node): self
{
$subNodes = [];
foreach ($node->getSubNodeNames() as $subNodeName) {
$subNodes[$subNodeName] = $node->$subNodeName;
}

return new AnonymousClassNode(
$node->name,
$subNodes,
$node->getAttributes(),
);
}

public function isAnonymous(): bool
{
return true;
}

}
9 changes: 5 additions & 4 deletions src/Parser/AnonymousClassVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
use PHPStan\Node\AnonymousClassNode;
use function count;

class AnonymousClassVisitor extends NodeVisitorAbstract
{

public const ATTRIBUTE_ANONYMOUS_CLASS = 'anonymousClass';
public const ATTRIBUTE_LINE_INDEX = 'anonymousClassLineIndex';

/** @var array<int, non-empty-list<Node\Stmt\Class_>> */
/** @var array<int, non-empty-list<AnonymousClassNode>> */
private array $nodesPerLine = [];

public function beforeTraverse(array $nodes): ?array
Expand All @@ -27,10 +27,11 @@ public function enterNode(Node $node): ?Node
return null;
}

$node->setAttribute(self::ATTRIBUTE_ANONYMOUS_CLASS, true);
$node = AnonymousClassNode::createFromClassNode($node);
$node->setAttribute('anonymousClass', true); // We keep this for backward compatibility
$this->nodesPerLine[$node->getStartLine()][] = $node;

return null;
return $node;
}

public function afterTraverse(array $nodes): ?array
Expand Down
5 changes: 2 additions & 3 deletions src/Type/FileTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use PHPStan\BetterReflection\Util\GetLastDocComment;
use PHPStan\Broker\AnonymousClassNameHelper;
use PHPStan\File\FileHelper;
use PHPStan\Parser\AnonymousClassVisitor;
use PHPStan\Parser\Parser;
use PHPStan\PhpDoc\PhpDocNodeResolver;
use PHPStan\PhpDoc\PhpDocStringResolver;
Expand Down Expand Up @@ -261,7 +260,7 @@ function (Node $node) use ($fileName, $lookForTrait, &$traitFound, $traitMethodA
}

$className = $this->anonymousClassNameHelper->getAnonymousClassName($node, $fileName);
} elseif ((bool) $node->getAttribute(AnonymousClassVisitor::ATTRIBUTE_ANONYMOUS_CLASS, false)) {
} elseif ($node instanceof Node\Stmt\Class_ && $node->isAnonymous()) {
$className = $node->name->name;
} else {
if ($traitFound) {
Expand Down Expand Up @@ -452,7 +451,7 @@ function (Node $node) use ($fileName, $lookForTrait, $phpDocNodeMap, &$traitFoun
}

$className = $this->anonymousClassNameHelper->getAnonymousClassName($node, $fileName);
} elseif ((bool) $node->getAttribute(AnonymousClassVisitor::ATTRIBUTE_ANONYMOUS_CLASS, false)) {
} elseif ($node instanceof Node\Stmt\Class_ && $node->isAnonymous()) {
$className = $node->name->name;
} else {
if ($traitFound) {
Expand Down
6 changes: 4 additions & 2 deletions tests/PHPStan/Reflection/AnonymousClassReflectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Parser\AnonymousClassVisitor;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Assert;
use function implode;
use function sprintf;

Expand Down Expand Up @@ -36,10 +36,12 @@ public function getNodeType(): string

public function processNode(Node $node, Scope $scope): array
{
if (!(bool) $node->getAttribute(AnonymousClassVisitor::ATTRIBUTE_ANONYMOUS_CLASS)) {
if (!$node->isAnonymous()) {
return [];
}

Assert::assertTrue($node->getAttribute('anonymousClass'));

$classReflection = $this->reflectionProvider->getAnonymousClassReflection($node, $scope);

return [
Expand Down

0 comments on commit 03626d9

Please sign in to comment.