Skip to content

Commit

Permalink
Fix infinite recursion with self-referencing class constant
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Nov 19, 2023
1 parent 2ec416e commit 93af41b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/Reflection/InitializerExprTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
use PHPStan\Type\TypeUtils;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function assert;
Expand All @@ -79,6 +80,7 @@
use function is_int;
use function max;
use function min;
use function sprintf;
use function strtolower;
use const INF;

Expand All @@ -87,6 +89,9 @@ class InitializerExprTypeResolver

public const CALCULATE_SCALARS_LIMIT = 128;

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

public function __construct(
private ConstantResolver $constantResolver,
private ReflectionProviderProvider $reflectionProviderProvider,
Expand Down Expand Up @@ -1876,9 +1881,18 @@ function (Type $type, callable $traverse): Type {
continue;
}

$resolvingName = sprintf('%s::%s', $constantClassReflection->getName(), $constantName);
if (array_key_exists($resolvingName, $this->currentlyResolvingClassConstant)) {
$types[] = new MixedType();
continue;
}

$this->currentlyResolvingClassConstant[$resolvingName] = true;

if (!$isObject) {
$reflectionConstant = $constantClassReflection->getNativeReflection()->getReflectionConstant($constantName);
if ($reflectionConstant === false) {
unset($this->currentlyResolvingClassConstant[$resolvingName]);
continue;
}
$reflectionConstantDeclaringClass = $reflectionConstant->getDeclaringClass();
Expand All @@ -1893,6 +1907,7 @@ function (Type $type, callable $traverse): Type {
$constantType,
$nativeType,
);
unset($this->currentlyResolvingClassConstant[$resolvingName]);
continue;
}

Expand All @@ -1903,6 +1918,7 @@ function (Type $type, callable $traverse): Type {
&& !$constantReflection->hasPhpDocType()
&& !$constantReflection->hasNativeType()
) {
unset($this->currentlyResolvingClassConstant[$resolvingName]);
return new MixedType();
}

Expand All @@ -1925,6 +1941,7 @@ function (Type $type, callable $traverse): Type {
$constantType,
$nativeType,
);
unset($this->currentlyResolvingClassConstant[$resolvingName]);
$types[] = $constantType;
}

Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/AnalyserIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,12 @@ public function testBug10086(): void
$this->assertNoErrors($errors);
}

public function testBug10147(): void
{
$errors = $this->runAnalyse(__DIR__ . '/data/bug-10147.php');
$this->assertNoErrors($errors);
}

/**
* @param string[]|null $allAnalysedFiles
* @return Error[]
Expand Down
13 changes: 13 additions & 0 deletions tests/PHPStan/Analyser/data/bug-10147.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Bug10147;

abstract class AbstractClass
{
const BASE_URL = self::BASE_URL;
}

final class TestClass extends AbstractClass
{
const BASE_URL = 'http://example.com';
}

0 comments on commit 93af41b

Please sign in to comment.