From 8e337a7729e9e0b07f0c726ebc0b7e3b14250197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Hansl=C3=ADk?= Date: Mon, 4 Aug 2025 21:41:34 +0200 Subject: [PATCH] Run tests and PHPStan on PHP 8.5 --- .github/workflows/continuous-integration.yml | 4 ++ composer.json | 2 +- composer.lock | 4 +- src/Reflection/Adapter/ReflectionProperty.php | 6 ++ .../Fixture/PHP85ClassForSourceStubber.php | 14 +++++ .../PHP85ClassForSourceStubberExpected.php | 10 +++ .../PhpStormStubsSourceStubberTest.php | 63 ++++++++++++++++++- .../ReflectionSourceStubberTest.php | 13 ++++ 8 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 test/unit/Fixture/PHP85ClassForSourceStubber.php create mode 100644 test/unit/Fixture/PHP85ClassForSourceStubberExpected.php diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 98cca5f4e..fb89409ea 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -25,6 +25,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" operating-system: - "ubuntu-latest" - "windows-latest" @@ -69,6 +70,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" operating-system: - "ubuntu-latest" @@ -110,6 +112,8 @@ jobs: - "locked" php-version: - "8.4" + # Psalm currently fails + # - "8.5" operating-system: - "ubuntu-latest" diff --git a/composer.json b/composer.json index e1db2ffca..88052b5a2 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Better Reflection - an improved code reflection API", "license": "MIT", "require": { - "php": "~8.2.0 || ~8.3.2 || ~8.4.1", + "php": "~8.2.0 || ~8.3.2 || ~8.4.1 || ~8.5.0", "ext-json": "*", "jetbrains/phpstorm-stubs": "2024.3", "nikic/php-parser": "^5.6.0" diff --git a/composer.lock b/composer.lock index 5f5265c63..8e4af160c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "947ac0c9f48456d26053c80e4e2c9236", + "content-hash": "a064783b40a4e049fa670d3ceafccf9c", "packages": [ { "name": "jetbrains/phpstorm-stubs", @@ -3277,7 +3277,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "~8.2.0 || ~8.3.2 || ~8.4.1", + "php": "~8.2.0 || ~8.3.2 || ~8.4.1 || ~8.5.0", "ext-json": "*" }, "platform-dev": {}, diff --git a/src/Reflection/Adapter/ReflectionProperty.php b/src/Reflection/Adapter/ReflectionProperty.php index 911a3e9b4..9645161ca 100644 --- a/src/Reflection/Adapter/ReflectionProperty.php +++ b/src/Reflection/Adapter/ReflectionProperty.php @@ -10,6 +10,7 @@ use ReflectionException as CoreReflectionException; use ReflectionMethod as CoreReflectionMethod; use ReflectionProperty as CoreReflectionProperty; +use Roave\BetterReflection\Reflection\Adapter\Exception\NotImplemented; use Roave\BetterReflection\Reflection\Exception\NoObjectProvided; use Roave\BetterReflection\Reflection\Exception\NotAnObject; use Roave\BetterReflection\Reflection\ReflectionAttribute as BetterReflectionAttribute; @@ -355,4 +356,9 @@ public function __get(string $name): mixed throw new OutOfBoundsException(sprintf('Property %s::$%s does not exist.', self::class, $name)); } + + public function getMangledName(): string + { + throw new NotImplemented('Not implemented'); + } } diff --git a/test/unit/Fixture/PHP85ClassForSourceStubber.php b/test/unit/Fixture/PHP85ClassForSourceStubber.php new file mode 100644 index 000000000..bf59f7aab --- /dev/null +++ b/test/unit/Fixture/PHP85ClassForSourceStubber.php @@ -0,0 +1,14 @@ + $missingClasses */ + $missingClasses = [ + 'NoDiscard', + 'DelayedTargetValidation', + ]; + if ( + PHP_VERSION_ID >= 80500 + && in_array($className, $missingClasses, true) + ) { + return false; + } + // Check only always enabled extensions return in_array($reflection->getExtensionName(), self::EXTENSIONS, true); }, @@ -188,8 +201,17 @@ private function assertSameClassAttributes(CoreReflectionClass $original, Reflec $this->assertSameInterfaces($original, $stubbed); foreach ($original->getMethods() as $method) { + $methodName = $original->getName() . '#' . $method->getName(); + + // https://github.com/JetBrains/phpstorm-stubs/pull/1781 + if ( + in_array($methodName, ['Closure#getCurrent'], true) + ) { + continue; + } + $stubbedMethod = $stubbed->getMethod($method->getName()); - self::assertNotNull($stubbedMethod); + self::assertNotNull($stubbedMethod, $methodName); $this->assertSameMethodAttributes($method, $stubbedMethod); } @@ -204,10 +226,19 @@ private function assertSameClassAttributes(CoreReflectionClass $original, Reflec $originalConstantName = $originalConstant->getName(); assert($originalConstantName !== ''); + $constantName = $original->getName() . '::' . $originalConstant->getName(); + + // https://github.com/JetBrains/phpstorm-stubs/pull/1781 + if ( + in_array($constantName, ['Attribute::TARGET_CONSTANT'], true) + ) { + continue; + } + $stubbedConstant = $stubbed->getConstant($originalConstantName); - self::assertNotNull($stubbedConstant); - self::assertSame($originalConstant->getValue(), $stubbedConstant->getValue()); + self::assertNotNull($stubbedConstant, $constantName); + self::assertSame($originalConstant->getValue(), $stubbedConstant->getValue(), $constantName); } } @@ -301,6 +332,20 @@ public static function internalFunctionsProvider(): array static function (string $functionName): bool { $reflection = new CoreReflectionFunction($functionName); + // https://github.com/JetBrains/phpstorm-stubs/pull/1781 + if ( + PHP_VERSION_ID >= 80500 + && in_array($functionName, [ + 'array_first', + 'array_last', + 'clone', + 'get_error_handler', + 'get_exception_handler', + ], true) + ) { + return false; + } + // Check only always enabled extensions return in_array($reflection->getExtensionName(), self::EXTENSIONS, true); }, @@ -361,6 +406,18 @@ public static function internalConstantsProvider(): array } foreach ($extensionConstants as $constantName => $constantValue) { + // https://github.com/JetBrains/phpstorm-stubs/pull/1781 + if ( + PHP_VERSION_ID >= 80500 + && in_array($constantName, [ + 'IMAGETYPE_SVG', + 'IMAGETYPE_HEIF', + 'PHP_BUILD_DATE', + ], true) + ) { + continue; + } + $provider[] = [$constantName, $constantValue, $extensionName]; } } diff --git a/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php b/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php index 06e39f188..747c802f4 100644 --- a/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php +++ b/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php @@ -35,6 +35,7 @@ use Roave\BetterReflectionTest\Fixture\InterfaceForSourceStubber; use Roave\BetterReflectionTest\Fixture\PHP81ClassForSourceStubber; use Roave\BetterReflectionTest\Fixture\PHP83ClassForSourceStubber; +use Roave\BetterReflectionTest\Fixture\PHP85ClassForSourceStubber; use Roave\BetterReflectionTest\Fixture\PHP8ClassForSourceStubber; use Roave\BetterReflectionTest\Fixture\TraitForSourceStubber; use stdClass; @@ -116,6 +117,7 @@ public function testCanStubTraits(): void self::assertNull($stubData->getExtensionName()); } + #[RequiresPhp('< 8.5')] public function testClassStub(): void { require_once __DIR__ . '/../../Fixture/ClassForSourceStubber.php'; @@ -189,6 +191,17 @@ public function testClassStubWithTypedConstants(): void self::assertStringEqualsFile(__DIR__ . '/../../Fixture/PHP83ClassForSourceStubberExpected.php', $stubData->getStub()); } + #[RequiresPhp('8.5')] + public function testClassStubWithPHP85Changes(): void + { + require_once __DIR__ . '/../../Fixture/PHP85ClassForSourceStubber.php'; + + $stubData = $this->stubber->generateClassStub(PHP85ClassForSourceStubber::class); + + self::assertNotNull($stubData); + self::assertStringEqualsFile(__DIR__ . '/../../Fixture/PHP85ClassForSourceStubberExpected.php', $stubData->getStub()); + } + public function testClassWithoutNamespaceStub(): void { require_once __DIR__ . '/../../Fixture/ClassWithoutNamespaceForSourceStubber.php';