Skip to content

Commit

Permalink
Fix infinite recursion in mixin extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 4, 2022
1 parent c87284a commit 9ab4e6f
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/Reflection/Mixin/MixinMethodsClassReflectionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Reflection\MethodsClassReflectionExtension;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\VerbosityLevel;
use function array_intersect;
use function count;

Expand All @@ -17,6 +18,9 @@ class MixinMethodsClassReflectionExtension implements MethodsClassReflectionExte
/** @var string[] */
private array $mixinExcludeClasses;

/** @var array<string, array<string, true>> */
private array $inProcess = [];

/**
* @param string[] $mixinExcludeClasses
*/
Expand Down Expand Up @@ -48,11 +52,22 @@ private function findMethod(ClassReflection $classReflection, string $methodName
continue;
}

$typeDescription = $type->describe(VerbosityLevel::typeOnly());
if (isset($this->inProcess[$typeDescription][$methodName])) {
continue;
}

$this->inProcess[$typeDescription][$methodName] = true;

if (!$type->hasMethod($methodName)->yes()) {
unset($this->inProcess[$typeDescription][$methodName]);
continue;
}

$method = $type->getMethod($methodName, new OutOfClassScope());

unset($this->inProcess[$typeDescription][$methodName]);

$static = $method->isStatic();
if (
!$static
Expand Down
17 changes: 16 additions & 1 deletion src/Reflection/Mixin/MixinPropertiesClassReflectionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Reflection\PropertyReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\VerbosityLevel;
use function array_intersect;
use function count;

Expand All @@ -17,6 +18,9 @@ class MixinPropertiesClassReflectionExtension implements PropertiesClassReflecti
/** @var string[] */
private array $mixinExcludeClasses;

/** @var array<string, array<string, true>> */
private array $inProcess = [];

/**
* @param string[] $mixinExcludeClasses
*/
Expand Down Expand Up @@ -48,11 +52,22 @@ private function findProperty(ClassReflection $classReflection, string $property
continue;
}

$typeDescription = $type->describe(VerbosityLevel::typeOnly());
if (isset($this->inProcess[$typeDescription][$propertyName])) {
continue;
}

$this->inProcess[$typeDescription][$propertyName] = true;

if (!$type->hasProperty($propertyName)->yes()) {
unset($this->inProcess[$typeDescription][$propertyName]);
continue;
}

return $type->getProperty($propertyName, new OutOfClassScope());
$property = $type->getProperty($propertyName, new OutOfClassScope());
unset($this->inProcess[$typeDescription][$propertyName]);

return $property;
}

foreach ($classReflection->getParents() as $parentClass) {
Expand Down
11 changes: 11 additions & 0 deletions tests/PHPStan/Analyser/AnalyserIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,17 @@ public function testBug6255(): void
$this->assertNoErrors($errors);
}

public function testBug6300(): void
{
$errors = $this->runAnalyse(__DIR__ . '/data/bug-6300.php');
$this->assertCount(2, $errors);
$this->assertSame('Call to an undefined method Bug6300\Bar::get().', $errors[0]->getMessage());
$this->assertSame(23, $errors[0]->getLine());

$this->assertSame('Access to an undefined property Bug6300\Bar::$fooProp.', $errors[1]->getMessage());
$this->assertSame(24, $errors[1]->getLine());
}

/**
* @return Error[]
*/
Expand Down
26 changes: 26 additions & 0 deletions tests/PHPStan/Analyser/data/bug-6300.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Bug6300;

/**
* @mixin Bar
*/
class Foo
{

}

/**
* @mixin Foo
*/
class Bar
{

}

function (Bar $b): void
{
$b->get();
echo $b->fooProp;
};

0 comments on commit 9ab4e6f

Please sign in to comment.