From 7ede0d8cc1deeedbf3101e000d352eda7f5a211a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Tue, 29 Jul 2025 07:25:42 +0200 Subject: [PATCH 1/6] Allow PHP 8.5 as max version --- conf/parametersSchema.neon | 6 +++--- e2e/composer-min-open-end-version/test.php | 4 ++-- e2e/composer-min-version/test.php | 4 ++-- e2e/composer-no-versions/test.php | 2 +- src/Php/PhpVersionFactory.php | 2 +- tests/PHPStan/Analyser/ScopePhpVersionTest.php | 4 ++-- tests/PHPStan/Analyser/nsrt/predefined-constants.php | 2 +- tests/PHPStan/Php/PhpVersionFactoryTest.php | 10 ++++++++-- 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon index 3f60d6383d..76d8e86b40 100644 --- a/conf/parametersSchema.neon +++ b/conf/parametersSchema.neon @@ -87,10 +87,10 @@ parametersSchema: buffer: int() ]) phpVersion: schema(anyOf( - schema(int(), min(70100), max(80499)), + schema(int(), min(70100), max(80599)), structure([ - min: schema(int(), min(70100), max(80499)), - max: schema(int(), min(70100), max(80499)) + min: schema(int(), min(70100), max(80599)), + max: schema(int(), min(70100), max(80599)) ]) ), nullable()) polluteScopeWithLoopInitialAssignments: bool() diff --git a/e2e/composer-min-open-end-version/test.php b/e2e/composer-min-open-end-version/test.php index d4d06a34eb..9ed998185b 100644 --- a/e2e/composer-min-open-end-version/test.php +++ b/e2e/composer-min-open-end-version/test.php @@ -1,6 +1,6 @@ ', PHP_VERSION_ID); +\PHPStan\Testing\assertType('int<80100, 80599>', PHP_VERSION_ID); \PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); -\PHPStan\Testing\assertType('int<1, 4>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<1, 5>', PHP_MINOR_VERSION); \PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-min-version/test.php b/e2e/composer-min-version/test.php index d4d06a34eb..9ed998185b 100644 --- a/e2e/composer-min-version/test.php +++ b/e2e/composer-min-version/test.php @@ -1,6 +1,6 @@ ', PHP_VERSION_ID); +\PHPStan\Testing\assertType('int<80100, 80599>', PHP_VERSION_ID); \PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); -\PHPStan\Testing\assertType('int<1, 4>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<1, 5>', PHP_MINOR_VERSION); \PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-no-versions/test.php b/e2e/composer-no-versions/test.php index 28c8a3183b..3cae7a0628 100644 --- a/e2e/composer-no-versions/test.php +++ b/e2e/composer-no-versions/test.php @@ -1,6 +1,6 @@ ', PHP_VERSION_ID); +\PHPStan\Testing\assertType('int<50207, 80599>', PHP_VERSION_ID); \PHPStan\Testing\assertType('int<5, 8>', PHP_MAJOR_VERSION); \PHPStan\Testing\assertType('int<0, max>', PHP_MINOR_VERSION); \PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); diff --git a/src/Php/PhpVersionFactory.php b/src/Php/PhpVersionFactory.php index eb71104673..73f510e0dc 100644 --- a/src/Php/PhpVersionFactory.php +++ b/src/Php/PhpVersionFactory.php @@ -13,7 +13,7 @@ final class PhpVersionFactory { public const MIN_PHP_VERSION = 70100; - public const MAX_PHP_VERSION = 80499; + public const MAX_PHP_VERSION = 80599; public const MAX_PHP5_VERSION = 50699; public const MAX_PHP7_VERSION = 70499; diff --git a/tests/PHPStan/Analyser/ScopePhpVersionTest.php b/tests/PHPStan/Analyser/ScopePhpVersionTest.php index 395cc0891b..193a55c53c 100644 --- a/tests/PHPStan/Analyser/ScopePhpVersionTest.php +++ b/tests/PHPStan/Analyser/ScopePhpVersionTest.php @@ -15,11 +15,11 @@ public static function dataTestPhpVersion(): array { return [ [ - 'int<80000, 80499>', + 'int<80000, 80599>', __DIR__ . '/data/scope-constants-global.php', ], [ - 'int<80000, 80499>', + 'int<80000, 80599>', __DIR__ . '/data/scope-constants-namespace.php', ], ]; diff --git a/tests/PHPStan/Analyser/nsrt/predefined-constants.php b/tests/PHPStan/Analyser/nsrt/predefined-constants.php index 9d9d1b1fc5..7c38d3833b 100644 --- a/tests/PHPStan/Analyser/nsrt/predefined-constants.php +++ b/tests/PHPStan/Analyser/nsrt/predefined-constants.php @@ -7,7 +7,7 @@ assertType('int<5, 8>', PHP_MAJOR_VERSION); assertType('int<0, max>', PHP_MINOR_VERSION); assertType('int<0, max>', PHP_RELEASE_VERSION); -assertType('int<50207, 80499>', PHP_VERSION_ID); +assertType('int<50207, 80599>', PHP_VERSION_ID); assertType('string', PHP_EXTRA_VERSION); assertType('0|1', PHP_ZTS); assertType('0|1', PHP_DEBUG); diff --git a/tests/PHPStan/Php/PhpVersionFactoryTest.php b/tests/PHPStan/Php/PhpVersionFactoryTest.php index adc5564253..3687e60e07 100644 --- a/tests/PHPStan/Php/PhpVersionFactoryTest.php +++ b/tests/PHPStan/Php/PhpVersionFactoryTest.php @@ -81,8 +81,8 @@ public static function dataCreate(): array [ null, '8.5', - 80499, - '8.4.99', + 80500, + '8.5', ], [ null, @@ -90,6 +90,12 @@ public static function dataCreate(): array 80095, '8.0.95', ], + [ + null, + '8.6', + 80599, + '8.5.99', + ], ]; } From b4217edcef3c853c638667320b61bc8857d9dc3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Tue, 29 Jul 2025 07:53:36 +0200 Subject: [PATCH 2/6] Update workflows --- .github/workflows/lint.yml | 1 + .github/workflows/reflection-golden-test.yml | 1 + .github/workflows/static-analysis.yml | 3 ++- .github/workflows/tests.yml | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 16ed00181a..e42c6f23cf 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,6 +28,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" steps: - name: "Checkout" diff --git a/.github/workflows/reflection-golden-test.yml b/.github/workflows/reflection-golden-test.yml index 91b38f9e13..44cceae778 100644 --- a/.github/workflows/reflection-golden-test.yml +++ b/.github/workflows/reflection-golden-test.yml @@ -67,6 +67,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" steps: - uses: Wandalen/wretry.action@v3.8.0 diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index af50f11f51..bebb3f7483 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -34,6 +34,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" operating-system: [ubuntu-latest, windows-latest] steps: @@ -79,7 +80,7 @@ jobs: php-version: - "8.2" - "8.3" - - "8.4" + - "8.5" steps: - name: "Checkout" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 328020a361..c431ecee52 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,6 +35,7 @@ jobs: - "8.2" - "8.3" - "8.4" + - "8.5" operating-system: [ ubuntu-latest, windows-latest ] steps: From 684353a2ce3bf24c450f265bf1929d6ddb9a063b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Tue, 29 Jul 2025 08:11:32 +0200 Subject: [PATCH 3/6] Do not remove 8.4 --- .github/workflows/static-analysis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index bebb3f7483..a49e5e7623 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -80,6 +80,7 @@ jobs: php-version: - "8.2" - "8.3" + - "8.4" - "8.5" steps: From 288fcc2eece9c48b48014ca2f0fa21e1d9a118b0 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Tue, 29 Jul 2025 23:32:42 +0200 Subject: [PATCH 4/6] Use authoritative Attribute stub --- .../BetterReflection/BetterReflectionSourceLocatorFactory.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php index bce28616f4..08f145d7c3 100644 --- a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php @@ -75,7 +75,9 @@ public function __construct( public function create(): SourceLocator { - $locators = []; + $locators = [ + $this->optimizedSingleFileSourceLocatorRepository->getOrCreate(__DIR__ . '/../../../stubs/runtime/Attribute.php'), + ]; if ($this->singleReflectionFile !== null) { $locators[] = $this->optimizedSingleFileSourceLocatorRepository->getOrCreate($this->singleReflectionFile); From 9018681c33f268178afa94305e01cc52b6a1328c Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Tue, 29 Jul 2025 23:42:13 +0200 Subject: [PATCH 5/6] Try different stubs for PHP 8.4 and 8.5+ --- conf/config.neon | 2 +- .../BetterReflectionSourceLocatorFactory.php | 7 +- .../{Attribute.php => Attribute84.php} | 0 stubs/runtime/Attribute85.php | 88 +++++++++++++++++++ tests/PHPStan/Command/CommandHelperTest.php | 2 +- 5 files changed, 96 insertions(+), 3 deletions(-) rename stubs/runtime/{Attribute.php => Attribute84.php} (100%) create mode 100644 stubs/runtime/Attribute85.php diff --git a/conf/config.neon b/conf/config.neon index 65cda918e7..664145f443 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -7,7 +7,7 @@ parameters: bootstrapFiles: - ../stubs/runtime/ReflectionUnionType.php - ../stubs/runtime/ReflectionAttribute.php - - ../stubs/runtime/Attribute.php + - ../stubs/runtime/Attribute85.php - ../stubs/runtime/ReflectionIntersectionType.php excludePaths: [] level: null diff --git a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php index 08f145d7c3..5aade14d0f 100644 --- a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php @@ -31,6 +31,7 @@ use function extension_loaded; use function is_dir; use function is_file; +use const PHP_VERSION_ID; #[AutowiredService] final class BetterReflectionSourceLocatorFactory @@ -76,7 +77,11 @@ public function __construct( public function create(): SourceLocator { $locators = [ - $this->optimizedSingleFileSourceLocatorRepository->getOrCreate(__DIR__ . '/../../../stubs/runtime/Attribute.php'), + $this->optimizedSingleFileSourceLocatorRepository->getOrCreate( + PHP_VERSION_ID < 80500 + ? __DIR__ . '/../../../stubs/runtime/Attribute84.php' + : __DIR__ . '/../../../stubs/runtime/Attribute85.php', + ), ]; if ($this->singleReflectionFile !== null) { diff --git a/stubs/runtime/Attribute.php b/stubs/runtime/Attribute84.php similarity index 100% rename from stubs/runtime/Attribute.php rename to stubs/runtime/Attribute84.php diff --git a/stubs/runtime/Attribute85.php b/stubs/runtime/Attribute85.php new file mode 100644 index 0000000000..37a522ea84 --- /dev/null +++ b/stubs/runtime/Attribute85.php @@ -0,0 +1,88 @@ +flags = $flags; + } + + } +} + +if (\PHP_VERSION_ID < 80100 && !class_exists('ReturnTypeWillChange', false)) { + #[Attribute(Attribute::TARGET_METHOD)] + final class ReturnTypeWillChange + { + } +} + +if (\PHP_VERSION_ID < 80200 && !class_exists('AllowDynamicProperties', false)) { + #[Attribute(Attribute::TARGET_CLASS)] + final class AllowDynamicProperties + { + } +} + +if (\PHP_VERSION_ID < 80200 && !class_exists('SensitiveParameter', false)) { + #[Attribute(Attribute::TARGET_PARAMETER)] + final class SensitiveParameter + { + } +} diff --git a/tests/PHPStan/Command/CommandHelperTest.php b/tests/PHPStan/Command/CommandHelperTest.php index 702b5ac4ae..5ecf380ddb 100644 --- a/tests/PHPStan/Command/CommandHelperTest.php +++ b/tests/PHPStan/Command/CommandHelperTest.php @@ -165,7 +165,7 @@ public static function dataParameters(): array 'bootstrapFiles' => [ realpath(__DIR__ . '/../../../stubs/runtime/ReflectionUnionType.php'), realpath(__DIR__ . '/../../../stubs/runtime/ReflectionAttribute.php'), - realpath(__DIR__ . '/../../../stubs/runtime/Attribute.php'), + realpath(__DIR__ . '/../../../stubs/runtime/Attribute85.php'), realpath(__DIR__ . '/../../../stubs/runtime/ReflectionIntersectionType.php'), __DIR__ . DIRECTORY_SEPARATOR . 'relative-paths' . DIRECTORY_SEPARATOR . 'here.php', ], From 42ebc988caff7ca71b99eb47a3c7bcd99088219d Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Tue, 29 Jul 2025 23:49:09 +0200 Subject: [PATCH 6/6] Fix TestCaseSourceLocatorFactory --- src/Testing/TestCaseSourceLocatorFactory.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Testing/TestCaseSourceLocatorFactory.php b/src/Testing/TestCaseSourceLocatorFactory.php index 724380955e..a87bf4d9df 100644 --- a/src/Testing/TestCaseSourceLocatorFactory.php +++ b/src/Testing/TestCaseSourceLocatorFactory.php @@ -16,12 +16,14 @@ use PHPStan\Reflection\BetterReflection\SourceLocator\AutoloadSourceLocator; use PHPStan\Reflection\BetterReflection\SourceLocator\ComposerJsonAndInstalledJsonSourceLocatorMaker; use PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher; +use PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedSingleFileSourceLocatorRepository; use PHPStan\Reflection\BetterReflection\SourceLocator\PhpVersionBlacklistSourceLocator; use ReflectionClass; use function dirname; use function is_file; use function serialize; use function sha1; +use const PHP_VERSION_ID; final class TestCaseSourceLocatorFactory { @@ -35,6 +37,7 @@ final class TestCaseSourceLocatorFactory */ public function __construct( private ComposerJsonAndInstalledJsonSourceLocatorMaker $composerJsonAndInstalledJsonSourceLocatorMaker, + private OptimizedSingleFileSourceLocatorRepository $optimizedSingleFileSourceLocatorRepository, private Parser $phpParser, private Parser $php8Parser, private FileNodesFetcher $fileNodesFetcher, @@ -57,7 +60,13 @@ public function create(): SourceLocator $this->excludePaths, ])); if ($classLoaderReflection->hasProperty('vendorDir') && ! isset(self::$composerSourceLocatorsCache[$cacheKey])) { - $composerLocators = []; + $composerLocators = [ + $this->optimizedSingleFileSourceLocatorRepository->getOrCreate( + PHP_VERSION_ID < 80500 + ? __DIR__ . '/../../stubs/runtime/Attribute84.php' + : __DIR__ . '/../../stubs/runtime/Attribute85.php', + ), + ]; $vendorDirProperty = $classLoaderReflection->getProperty('vendorDir'); $vendorDirProperty->setAccessible(true); foreach ($classLoaders as $classLoader) {