Skip to content

Commit

Permalink
resolve class constant types when patching return types
Browse files Browse the repository at this point in the history
  • Loading branch information
xabbuh committed Oct 14, 2024
1 parent 82ed889 commit ad57ca0
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 1 deletion.
26 changes: 25 additions & 1 deletion DebugClassLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,30 @@ private function setReturnType(string $types, string $class, string $method, str
$docTypes = [];

foreach ($typesMap as $n => $t) {
if (str_contains($n, '::')) {
[$definingClass, $constantName] = explode('::', $n, 2);
$definingClass = match ($definingClass) {
'self', 'static', 'parent' => $class,
default => $definingClass,
};

if (!\defined($definingClass.'::'.$constantName)) {
return;
}

$constant = new \ReflectionClassConstant($definingClass, $constantName);

if (\PHP_VERSION_ID >= 80300 && $constantType = $constant->getType()) {
if ($constantType instanceof \ReflectionNamedType) {
$n = $constantType->getName();
} else {
return;
}
} else {
$n = \gettype($constant->getValue());
}
}

if ('null' === $n) {
$nullable = true;
continue;
Expand All @@ -872,7 +896,7 @@ private function setReturnType(string $types, string $class, string $method, str
continue;
}

if (!isset($phpTypes[''])) {
if (!isset($phpTypes['']) && !\in_array($n, $phpTypes, true)) {
$phpTypes[] = $n;
}
}
Expand Down
22 changes: 22 additions & 0 deletions Tests/DebugClassLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,26 @@ class_exists('Test\\'.ReturnType::class, true);
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::true()" might add "true" as a native return type declaration in the future. Do the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" now to avoid errors or add an explicit @return annotation to suppress this message.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::never()" might add "never" as a native return type declaration in the future. Do the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" now to avoid errors or add an explicit @return annotation to suppress this message.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::null()" might add "null" as a native return type declaration in the future. Do the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" now to avoid errors or add an explicit @return annotation to suppress this message.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::classConstant()" might add "string" as a native return type declaration in the future. Do the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" now to avoid errors or add an explicit @return annotation to suppress this message.',
], $deprecations);
}

/**
* @requires PHP >= 8.3
*/
public function testReturnTypePhp83()
{
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);

class_exists('Test\\'.ReturnTypePhp83::class, true);

error_reporting($e);
restore_error_handler();

$this->assertSame([
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParentPhp83::classConstantWithType()" might add "string" as a native return type declaration in the future. Do the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnTypePhp83" now to avoid errors or add an explicit @return annotation to suppress this message.',
], $deprecations);
}

Expand Down Expand Up @@ -542,6 +562,8 @@ public function ownAbstractBaseMethod() { }
}');
} elseif ('Test\\'.ReturnType::class === $class) {
return $fixtureDir.\DIRECTORY_SEPARATOR.'ReturnType.php';
} elseif ('Test\\'.ReturnTypePhp83::class === $class) {
return $fixtureDir.\DIRECTORY_SEPARATOR.'ReturnTypePhp83.php';
} elseif ('Test\\'.Fixtures\OutsideInterface::class === $class) {
return $fixtureDir.\DIRECTORY_SEPARATOR.'OutsideInterface.php';
} elseif ('Test\\'.OverrideOutsideFinalProperty::class === $class) {
Expand Down
1 change: 1 addition & 0 deletions Tests/Fixtures/ReturnType.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ public function true() { }
public function never() { }
public function null() { }
public function outsideMethod() { }
public function classConstant() { }
}
9 changes: 9 additions & 0 deletions Tests/Fixtures/ReturnTypeParent.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

abstract class ReturnTypeParent extends ReturnTypeGrandParent implements ReturnTypeParentInterface
{
const FOO = 'foo';

/**
* @return void
*/
Expand Down Expand Up @@ -254,4 +256,11 @@ public function null()
public function notExtended()
{
}

/**
* @return self::FOO
*/
public function classConstant()
{
}
}
23 changes: 23 additions & 0 deletions Tests/Fixtures/ReturnTypeParentPhp83.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Symfony\Component\ErrorHandler\Tests\Fixtures;

abstract class ReturnTypeParentPhp83
{
const string FOO = 'foo';
const string|int BAR = 'bar';

/**
* @return self::FOO
*/
public function classConstantWithType()
{
}

/**
* @return self::BAR
*/
public function classConstantWithUnionType()
{
}
}
11 changes: 11 additions & 0 deletions Tests/Fixtures/ReturnTypePhp83.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Test\Symfony\Component\ErrorHandler\Tests;

use Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParentPhp83;

class ReturnTypePhp83 extends ReturnTypeParentPhp83
{
public function classConstantWithType() { }
public function classConstantWithUnionType() { }
}

0 comments on commit ad57ca0

Please sign in to comment.