Skip to content

Commit

Permalink
IllegalConstructorStaticCallRule - fix for renamed trait constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jul 5, 2023
1 parent eafba2e commit 65330d3
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 5 deletions.
38 changes: 33 additions & 5 deletions src/Rules/Methods/IllegalConstructorStaticCallRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function array_key_exists;
use function array_map;
use function in_array;
use function sprintf;
use function strtolower;

/**
Expand Down Expand Up @@ -37,16 +39,19 @@ public function processNode(Node $node, Scope $scope): array
];
}

private function isCollectCallingConstructor(Node $node, Scope $scope): bool
private function isCollectCallingConstructor(Node\Expr\StaticCall $node, Scope $scope): bool
{
if (!$node instanceof Node\Expr\StaticCall) {
return true;
}
// __construct should be called from inside constructor
if ($scope->getFunction() !== null && $scope->getFunction()->getName() !== '__construct') {
if ($scope->getFunction() === null) {
return false;
}

if ($scope->getFunction()->getName() !== '__construct') {
if (!$this->isInRenamedTraitConstructor($scope)) {
return false;
}
}

if (!$scope->isInClass()) {
return false;
}
Expand All @@ -60,4 +65,27 @@ private function isCollectCallingConstructor(Node $node, Scope $scope): bool
return in_array(strtolower($scope->resolveName($node->class)), $parentClasses, true);
}

private function isInRenamedTraitConstructor(Scope $scope): bool
{
if (!$scope->isInClass()) {
return false;
}

if (!$scope->isInTrait()) {
return false;
}

if ($scope->getFunction() === null) {
return false;
}

$traitAliases = $scope->getClassReflection()->getNativeReflection()->getTraitAliases();
$functionName = $scope->getFunction()->getName();
if (!array_key_exists($functionName, $traitAliases)) {

Check failure on line 84 in src/Rules/Methods/IllegalConstructorStaticCallRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.2, ubuntu-latest)

Call to method getTraitAliases() on an unknown class PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum.

Check failure on line 84 in src/Rules/Methods/IllegalConstructorStaticCallRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.2, windows-latest)

Call to method getTraitAliases() on an unknown class PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum.

Check failure on line 84 in src/Rules/Methods/IllegalConstructorStaticCallRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.3, ubuntu-latest)

Call to method getTraitAliases() on an unknown class PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum.

Check failure on line 84 in src/Rules/Methods/IllegalConstructorStaticCallRule.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.3, windows-latest)

Call to method getTraitAliases() on an unknown class PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum.
return false;
}

return $traitAliases[$functionName] === sprintf('%s::%s', $scope->getTraitReflection()->getName(), '__construct');
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use const PHP_VERSION_ID;

/**
* @extends RuleTestCase<IllegalConstructorStaticCallRule>
Expand Down Expand Up @@ -46,4 +47,13 @@ public function testMethods(): void
]);
}

public function testBug9577(): void
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Test requires PHP 8.1.');
}

$this->analyse([__DIR__ . '/data/bug-9577.php'], []);
}

}
40 changes: 40 additions & 0 deletions tests/PHPStan/Rules/Methods/data/bug-9577.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php // lint >= 8.1

namespace Bug9577IllegalConstructorStaticCall;

trait StringableMessageTrait
{
public function __construct(
private readonly \Stringable $StringableMessage,
int $code = 0,
?\Throwable $previous = null,
) {
parent::__construct((string) $StringableMessage, $code, $previous);
}

public function getStringableMessage(): \Stringable
{
return $this->StringableMessage;
}
}

class SpecializedException extends \RuntimeException
{
use StringableMessageTrait {
StringableMessageTrait::__construct as __traitConstruct;
}

public function __construct(
private readonly object $aService,
\Stringable $StringableMessage,
int $code = 0,
?\Throwable $previous = null,
) {
$this->__traitConstruct($StringableMessage, $code, $previous);
}

public function getService(): object
{
return $this->aService;
}
}

0 comments on commit 65330d3

Please sign in to comment.