From 13093231ebdf6d262b53b32b950aba901ed15c58 Mon Sep 17 00:00:00 2001 From: LubuSeb <187313664+LubuSeb@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:38:07 +0200 Subject: [PATCH 1/4] Fix symbol discovery after class name tokens --- .../SourceLocator/PhpFileCleaner.php | 5 +++- .../SourceLocator/SymbolFinderInFilesTest.php | 9 +++++++ .../class-name-before-global-constant.php | 24 +++++++++++++++++++ turbo-ext/src/SymbolScan.h | 8 +++++-- turbo-ext/tests/php-file-cleaner-corpus.php | 1 + turbo-ext/tests/symbol-finder-corpus.php | 1 + 6 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/symbol-finder/class-name-before-global-constant.php diff --git a/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php b/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php index 4233ab2fea4..a51abde5b12 100644 --- a/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php +++ b/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php @@ -146,7 +146,10 @@ public function clean(string $contents, int $maxMatches): string if (isset($this->typeConfig[$char])) { $type = $this->typeConfig[$char]; - if (substr($this->contents, $this->index, $type['length']) === $type['name']) { + if ( + substr($this->contents, $this->index, $type['length']) === $type['name'] + && $this->match('~.\\b(?])' . $type['name'] . '\\b~Ais', offset: $this->index - 1) + ) { if ($maxMatches === 1 && $this->match($type['pattern'], $match, $this->index - 1)) { return $clean . $match[0]; } diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/SymbolFinderInFilesTest.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/SymbolFinderInFilesTest.php index 7667289b78b..df4c83f446b 100644 --- a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/SymbolFinderInFilesTest.php +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/SymbolFinderInFilesTest.php @@ -13,6 +13,15 @@ final class SymbolFinderInFilesTest extends PHPStanTestCase */ public static function dataFindSymbols(): iterable { + yield 'class name expressions do not hide later global constants' => [ + __DIR__ . '/data/symbol-finder/class-name-before-global-constant.php', + [ + [], + ['symbolfinderclassname', 'classname', 'symbolfinderanonymousclass'], + ['AFTER_CLASS_NAME', 'AFTER_CLASS_PREFIX', 'AFTER_ANONYMOUS_CLASS'], + ], + ]; + yield 'namespaced constants do not leak a class entry' => [ __DIR__ . '/data/symbol-finder/namespaced-constants.php', [ diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/symbol-finder/class-name-before-global-constant.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/symbol-finder/class-name-before-global-constant.php new file mode 100644 index 00000000000..fb52529f45a --- /dev/null +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/data/symbol-finder/class-name-before-global-constant.php @@ -0,0 +1,24 @@ + "\n\n " "class;\n", + 'class name before global constant' => " " " "just text, no php at all\n", diff --git a/turbo-ext/tests/symbol-finder-corpus.php b/turbo-ext/tests/symbol-finder-corpus.php index 22a356a3f28..4b2895e6c0f 100644 --- a/turbo-ext/tests/symbol-finder-corpus.php +++ b/turbo-ext/tests/symbol-finder-corpus.php @@ -64,6 +64,7 @@ 'interface const' => " " " " " " " Date: Fri, 16 Oct 2026 15:43:15 +0200 Subject: [PATCH 2/4] Avoid PHP 7.4-incompatible scanner call --- .../BetterReflection/SourceLocator/PhpFileCleaner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php b/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php index a51abde5b12..64a9cf63d1b 100644 --- a/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php +++ b/src/Reflection/BetterReflection/SourceLocator/PhpFileCleaner.php @@ -148,7 +148,7 @@ public function clean(string $contents, int $maxMatches): string if ( substr($this->contents, $this->index, $type['length']) === $type['name'] - && $this->match('~.\\b(?])' . $type['name'] . '\\b~Ais', offset: $this->index - 1) + && $this->match('~.\\b(?])' . $type['name'] . '\\b~Ais', $match, $this->index - 1) ) { if ($maxMatches === 1 && $this->match($type['pattern'], $match, $this->index - 1)) { return $clean . $match[0]; From bba1cf716f4f53bad494832e5b1dc058c0765426 Mon Sep 17 00:00:00 2001 From: LubuSeb <187313664+LubuSeb@users.noreply.github.com> Date: Fri, 16 Oct 2026 15:43:24 +0200 Subject: [PATCH 3/4] Bump expected turbo version --- src/Turbo/TurboExtensionEnabler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Turbo/TurboExtensionEnabler.php b/src/Turbo/TurboExtensionEnabler.php index c2200f4bdd1..84bf915bd2f 100644 --- a/src/Turbo/TurboExtensionEnabler.php +++ b/src/Turbo/TurboExtensionEnabler.php @@ -34,7 +34,7 @@ final class TurboExtensionEnabler { - public const EXPECTED_EXTENSION_VERSION = '1cb5faf'; + public const EXPECTED_EXTENSION_VERSION = 'b0feb1b'; private static bool $active = false; From 50e680eea3c93f39d976a8801ecf47e1c7a7e3d0 Mon Sep 17 00:00:00 2001 From: LubuSeb <187313664+LubuSeb@users.noreply.github.com> Date: Sun, 18 Oct 2026 15:00:01 +0200 Subject: [PATCH 4/4] Update native extension version pin after rebase --- src/Turbo/TurboExtensionEnabler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Turbo/TurboExtensionEnabler.php b/src/Turbo/TurboExtensionEnabler.php index 84bf915bd2f..4f5841b8e6a 100644 --- a/src/Turbo/TurboExtensionEnabler.php +++ b/src/Turbo/TurboExtensionEnabler.php @@ -34,7 +34,7 @@ final class TurboExtensionEnabler { - public const EXPECTED_EXTENSION_VERSION = 'b0feb1b'; + public const EXPECTED_EXTENSION_VERSION = '1309323'; private static bool $active = false;