From 9289b655173e6a53d86df1b857a9f5f1caa0debb Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Mar 2026 05:10:45 +0000 Subject: [PATCH 01/30] Add issue category comments to AnalyserIntegrationTest bug methods Each testBug method now has a comment on its first line describing the nature of the original issue: crash, performance, infinite run, false positive, or false negative. https://claude.ai/code/session_017EKgzxmzYFa1qUT8bcuohj --- .../Analyser/AnalyserIntegrationTest.php | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 820338325d9..5fe2f04b3fb 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -157,6 +157,7 @@ public function testExtendsPdoStatementCrash(): void public function testBug12803(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12803.php'); $this->assertNoErrors($errors); } @@ -199,12 +200,14 @@ public function testPropertyAssignIntersectionStaticTypeBug(): void public function testBug2823(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-2823.php'); $this->assertNoErrors($errors); } public function testBug13424(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-13424.php'); $this->assertCount(1, $errors); $this->assertSame('Instantiated class Bug13424\Hello not found.', $errors[0]->getMessage()); @@ -239,12 +242,14 @@ public function testTwoSameClassesInSingleFile(): void public function testBug6936(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-6936.php'); $this->assertNoErrors($errors); } public function testBug3405(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-3405.php'); $this->assertCount(1, $errors); $this->assertSame('Magic constant __TRAIT__ is always empty outside a trait.', $errors[0]->getMessage()); @@ -253,24 +258,28 @@ public function testBug3405(): void public function testBug3415(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/../Rules/Methods/data/bug-3415.php'); $this->assertNoErrors($errors); } public function testBug3415Two(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/../Rules/Methods/data/bug-3415-2.php'); $this->assertNoErrors($errors); } public function testBug3468(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-3468.php'); $this->assertNoErrors($errors); } public function testBug3686(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-3686.php'); $this->assertNoErrors($errors); } @@ -278,12 +287,14 @@ public function testBug3686(): void #[RequiresPhp('>= 8.0')] public function testBug13352(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-13352.php'); $this->assertNoErrors($errors); } public function testBug3379(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/nsrt/bug-3379.php'); $this->assertCount(1, $errors); $this->assertSame('Constant SOME_UNKNOWN_CONST not found.', $errors[0]->getMessage()); @@ -291,30 +302,35 @@ public function testBug3379(): void public function testBug13685(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-13685.php'); $this->assertNoErrors($errors); } public function testBug3798(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-3798.php'); $this->assertNoErrors($errors); } public function testBug3909(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-3909.php'); $this->assertNoErrors($errors); } public function testBug4097(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-4097.php'); $this->assertNoErrors($errors); } public function testBug4300(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-4300.php'); $this->assertCount(1, $errors); $this->assertSame('Comparison operation ">" between 0 and 0 is always false.', $errors[0]->getMessage()); @@ -323,24 +339,28 @@ public function testBug4300(): void public function testBug4513(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-4513.php'); $this->assertNoErrors($errors); } public function testBug1871(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-1871.php'); $this->assertNoErrors($errors); } public function testBug3309(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-3309.php'); $this->assertNoErrors($errors); } public function testBug11649(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-11649.php'); $this->assertNoErrors($errors); } @@ -348,12 +368,14 @@ public function testBug11649(): void #[RequiresPhp('>= 8.0')] public function testBug6872(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6872.php'); $this->assertNoErrors($errors); } public function testBug3769(): void { + // false positive require_once __DIR__ . '/../Rules/Generics/data/bug-3769.php'; $errors = $this->runAnalyse(__DIR__ . '/../Rules/Generics/data/bug-3769.php'); $this->assertNoErrors($errors); @@ -361,6 +383,7 @@ public function testBug3769(): void public function testBug6301(): void { + // false positive require_once __DIR__ . '/../Rules/Generics/data/bug-6301.php'; $errors = $this->runAnalyse(__DIR__ . '/../Rules/Generics/data/bug-6301.php'); $this->assertNoErrors($errors); @@ -368,18 +391,21 @@ public function testBug6301(): void public function testBug3922(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-3922-integration.php'); $this->assertNoErrors($errors); } public function testBug1843(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-1843.php'); $this->assertNoErrors($errors); } public function testBug9711(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-9711.php'); $this->assertCount(1, $errors); $this->assertSame('Function in_array invoked with 1 parameter, 2-3 required.', $errors[0]->getMessage()); @@ -387,6 +413,7 @@ public function testBug9711(): void public function testBug4713(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-4713.php'); $this->assertCount(1, $errors); $this->assertSame('Method Bug4713\Service::createInstance() should return Bug4713\Service but returns object.', $errors[0]->getMessage()); @@ -401,6 +428,7 @@ public function testBug4713(): void public function testBug4288(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-4288.php'); $this->assertNoErrors($errors); @@ -423,6 +451,7 @@ public function testBug4288(): void public function testBug4702(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-4702.php'); $this->assertNoErrors($errors); } @@ -430,6 +459,7 @@ public function testBug4702(): void #[RequiresPhp('>= 8.1')] public function testBug14100(): void { + // false negative $errors = $this->runAnalyse(__DIR__ . '/data/bug-14100.php'); $this->assertNoErrors($errors); } @@ -448,6 +478,7 @@ public function testFunctionThatExistsOn72AndLater(): void public function testBug4715(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-4715.php'); $this->assertNoErrors($errors); } @@ -455,6 +486,7 @@ public function testBug4715(): void #[RequiresPhp('>= 8.2')] public function testBug4734(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-4734.php'); $this->assertCount(5, $errors); // could be 3 @@ -467,12 +499,14 @@ public function testBug4734(): void public function testBug5231(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-5231.php'); $this->assertNotEmpty($errors); } public function testBug5231Two(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-5231_2.php'); $this->assertNotEmpty($errors); } @@ -480,6 +514,7 @@ public function testBug5231Two(): void #[RequiresPhp('>= 8.1')] public function testBug12512(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12512.php'); $this->assertNoErrors($errors); } @@ -487,30 +522,35 @@ public function testBug12512(): void #[RequiresPhp('>= 8.0')] public function testBug13218(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-13218.php'); $this->assertNoErrors($errors); } public function testBug5529(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/nsrt/bug-5529.php'); $this->assertNoErrors($errors); } public function testBug5527(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-5527.php'); $this->assertNoErrors($errors); } public function testBug5639(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-5639.php'); $this->assertNoErrors($errors); } public function testBug5657(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-5657.php'); $this->assertNoErrors($errors); } @@ -518,6 +558,7 @@ public function testBug5657(): void #[RequiresPhp('>= 8.0')] public function testBug5951(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-5951.php'); $this->assertNoErrors($errors); } @@ -537,12 +578,14 @@ public function testEnums(): void public function testBug6255(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-6255.php'); $this->assertNoErrors($errors); } public function testBug6300(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6300.php'); $this->assertCount(1, $errors); $this->assertSame('Call to an undefined method Bug6300\Bar::get().', $errors[0]->getMessage()); @@ -551,6 +594,7 @@ public function testBug6300(): void public function testBug6466(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6466.php'); $this->assertNoErrors($errors); } @@ -558,12 +602,14 @@ public function testBug6466(): void #[RequiresPhp('>= 8.1')] public function testBug6494(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-6494.php'); $this->assertNoErrors($errors); } public function testBug6253(): void { + // false positive $errors = $this->runAnalyse( __DIR__ . '/data/bug-6253.php', [ @@ -577,6 +623,7 @@ public function testBug6253(): void public function testBug6442(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-6442.php'); $this->assertCount(2, $errors); $this->assertSame('Dumped type: \'Bug6442\\\B\'', $errors[0]->getMessage()); @@ -587,18 +634,21 @@ public function testBug6442(): void public function testBug13057(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-13057.php'); $this->assertNoErrors($errors); } public function testBug6375(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6375.php'); $this->assertNoErrors($errors); } public function testBug6501(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6501.php'); $this->assertCount(1, $errors); $this->assertSame('PHPDoc tag @var with type R of Exception|stdClass is not subtype of native type stdClass.', $errors[0]->getMessage()); @@ -608,48 +658,56 @@ public function testBug6501(): void #[RequiresPhp('>= 8.0')] public function testBug6114(): void { + // false negative $errors = $this->runAnalyse(__DIR__ . '/data/bug-6114.php'); $this->assertNoErrors($errors); } public function testBug6681(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6681.php'); $this->assertNoErrors($errors); } public function testBug6212(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6212.php'); $this->assertNoErrors($errors); } public function testBug6740(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6740-b.php'); $this->assertNoErrors($errors); } public function testBug6866(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6866.php'); $this->assertNoErrors($errors); } public function testBug6649(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-6649.php'); $this->assertNoErrors($errors); } public function testBug12778(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12778.php'); $this->assertNoErrors($errors); } public function testBug6842(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6842.php'); $this->assertCount(2, $errors); $this->assertSame('Generator expects value type T of DateTimeInterface, DateTime|DateTimeImmutable|T of DateTimeInterface given.', $errors[0]->getMessage()); @@ -662,6 +720,7 @@ public function testBug6842(): void #[RequiresPhp('>= 8.0')] public function testBug6896(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6896.php'); $this->assertCount(4, $errors); $this->assertSame('Generic type IteratorIterator<(int|string), mixed> in PHPDoc tag @return does not specify all template types of class IteratorIterator: TKey, TValue, TIterator', $errors[0]->getMessage()); @@ -676,6 +735,7 @@ public function testBug6896(): void public function testBug6940(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6940.php'); $this->assertCount(1, $errors); $this->assertSame('Loose comparison using == between array{} and array{} will always evaluate to true.', $errors[0]->getMessage()); @@ -684,18 +744,21 @@ public function testBug6940(): void public function testBug1447(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-1447.php'); $this->assertNoErrors($errors); } public function testBug5081(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-5081.php'); $this->assertNoErrors($errors); } public function testBug1388(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-1388.php'); $this->assertNoErrors($errors); } @@ -703,18 +766,21 @@ public function testBug1388(): void #[RequiresPhp('>= 8.0')] public function testBug4308(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-4308.php'); $this->assertNoErrors($errors); } public function testBug4732(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-4732.php'); $this->assertNoErrors($errors); } public function testBug6160(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-6160.php'); $this->assertCount(2, $errors); $this->assertSame('Parameter #1 $flags of static method Bug6160\HelloWorld::split() expects 0|1|2, 94561 given.', $errors[0]->getMessage()); @@ -725,12 +791,14 @@ public function testBug6160(): void public function testBug6979(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-6979.php'); $this->assertNoErrors($errors); } public function testBug7030(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7030.php'); $this->assertCount(1, $errors); $this->assertSame('PHPDoc tag @method has invalid value (array getItemsForID($id, $quantity, $shippingPostCode = null, $wholesalerList = null, $shippingLatitude = @@ -740,6 +808,7 @@ public function testBug7030(): void #[RequiresPhp('>= 8.1')] public function testBug7012(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7012.php'); $this->assertNoErrors($errors); } @@ -747,12 +816,14 @@ public function testBug7012(): void #[RequiresPhp('>= 8.1')] public function testBug6192(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-6192.php'); $this->assertNoErrors($errors); } public function testBug7068(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/nsrt/bug-7068.php'); $this->assertNoErrors($errors); } @@ -767,6 +838,7 @@ public function testDiscussion6993(): void public function testBug7077(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7077.php'); $this->assertNoErrors($errors); } @@ -774,6 +846,7 @@ public function testBug7077(): void #[RequiresPhp('>= 8.0')] public function testBug7078(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/nsrt/bug-7078.php'); $this->assertNoErrors($errors); } @@ -781,12 +854,14 @@ public function testBug7078(): void #[RequiresPhp('>= 8.0')] public function testBug7116(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7116.php'); $this->assertNoErrors($errors); } public function testBug3853(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/nsrt/bug-3853.php'); $this->assertNoErrors($errors); } @@ -794,6 +869,7 @@ public function testBug3853(): void #[RequiresPhp('>= 8.1')] public function testBug7135(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7135.php'); $this->assertCount(1, $errors); $this->assertSame('Cannot create callable from the new operator.', $errors[0]->getMessage()); @@ -816,6 +892,7 @@ public function testDiscussion7124(): void public function testBug7214(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-7214.php'); $this->assertCount(1, $errors); $this->assertSame('Method Bug7214\HelloWorld::getFoo() has no return type specified.', $errors[0]->getMessage()); @@ -824,6 +901,7 @@ public function testBug7214(): void public function testBug12327(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12327.php'); $this->assertCount(1, $errors); @@ -833,12 +911,14 @@ public function testBug12327(): void public function testBug7215(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7215.php'); $this->assertNoErrors($errors); } public function testBug7094(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7094.php'); $this->assertCount(6, $errors); @@ -880,42 +960,49 @@ public function testUnresolvableParameter(): void public function testBug7248(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7248.php'); $this->assertNoErrors($errors); } public function testBug7351(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7351.php'); $this->assertNoErrors($errors); } public function testBug7381(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7381.php'); $this->assertNoErrors($errors); } public function testBug7153(): void { + // false negative $errors = $this->runAnalyse(__DIR__ . '/nsrt/bug-7153.php'); $this->assertNoErrors($errors); } public function testBug7275(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7275.php'); $this->assertNoErrors($errors); } public function testBug7500(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7500.php'); $this->assertNoErrors($errors); } public function testBug12767(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12767.php'); $this->assertCount(3, $errors); @@ -926,6 +1013,7 @@ public function testBug12767(): void public function testBug7554(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7554.php'); $this->assertCount(2, $errors); @@ -938,6 +1026,7 @@ public function testBug7554(): void public function testBug7637(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-7637.php'); $this->assertCount(3, $errors); @@ -953,18 +1042,21 @@ public function testBug7637(): void public function testBug12671(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-12671.php'); $this->assertNoErrors($errors); } public function testBug7737(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7737.php'); $this->assertNoErrors($errors); } public function testBug7762(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7762.php'); $this->assertCount(2, $errors); $this->assertSame('Function json_decode invoked with 0 parameters, 1-4 required.', $errors[0]->getMessage()); @@ -983,6 +1075,7 @@ public function testPrestashopInfiniteRunXmlLoaderBug(): void public function testBug7320(): void { + // false negative $errors = $this->runAnalyse(__DIR__ . '/data/bug-7320.php'); $this->assertCount(1, $errors); $this->assertSame('Parameter #1 $c of function Bug7320\foo expects callable(int=): void, Closure(int): void given.', $errors[0]->getMessage()); @@ -991,30 +1084,35 @@ public function testBug7320(): void public function testBug7581(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-7581.php'); $this->assertNoErrors($errors); } public function testBug7903(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-7903.php'); $this->assertCount(39, $errors); } public function testBug7901(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-7901.php'); $this->assertNoErrors($errors); } public function testBug7918(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7918.php'); $this->assertNoErrors($errors); } public function testBug7140(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-7140.php'); $this->assertNoErrors($errors); } @@ -1027,18 +1125,21 @@ public function testArrayUnion(): void public function testBug6948(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-6948.php'); $this->assertNoErrors($errors); } public function testBug7963(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7963.php'); $this->assertNoErrors($errors); } public function testBug7963Two(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7963-two.php'); $this->assertNoErrors($errors); } @@ -1046,6 +1147,7 @@ public function testBug7963Two(): void #[RequiresPhp('>= 8.1')] public function testBug8078(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-8078.php'); $this->assertNoErrors($errors); } @@ -1053,12 +1155,14 @@ public function testBug8078(): void #[RequiresPhp('>= 8.1')] public function testBug8072(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-8072.php'); $this->assertNoErrors($errors); } public function testBug7787(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7787.php'); $this->assertCount(1, $errors); $this->assertSame('Reflection error: Circular reference to class "Bug7787\TestClass"', $errors[0]->getMessage()); @@ -1066,6 +1170,7 @@ public function testBug7787(): void public function testBug3865(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-3865.php'); $this->assertCount(1, $errors); $this->assertSame('The @extends tag of class Bug3865\RecursiveClass describes Bug3865\RecursiveClass but the class extends Bug3865\EntityRepository.', $errors[0]->getMessage()); @@ -1074,6 +1179,7 @@ public function testBug3865(): void public function testBug5312(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-5312.php'); $this->assertCount(5, $errors); $this->assertSame('PHPDoc tag @template T for interface Bug5312\Updatable has invalid bound type Bug5312\T.', $errors[0]->getMessage()); @@ -1090,6 +1196,7 @@ public function testBug5312(): void public function testBug5390(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-5390.php'); $this->assertCount(3, $errors); $this->assertSame('Property Bug5390\A::$b is never written, only read.', $errors[0]->getMessage()); @@ -1102,6 +1209,7 @@ public function testBug5390(): void public function testBug7110(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-7110.php'); $this->assertCount(1, $errors); $this->assertSame('Parameter #1 $s of function Bug7110\takesInt expects int, string given.', $errors[0]->getMessage()); @@ -1110,6 +1218,7 @@ public function testBug7110(): void public function testBug8376(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-8376.php'); $this->assertNoErrors($errors); } @@ -1132,6 +1241,7 @@ public function testAssertDocblock(): void #[RequiresPhp('>= 8.0')] public function testBug8147(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-8147.php'); $this->assertNoErrors($errors); } @@ -1139,6 +1249,7 @@ public function testBug8147(): void #[RequiresPhp('>= 8.0')] public function testBug12934(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12934.php'); $this->assertNoErrors($errors); } @@ -1157,12 +1268,14 @@ public function testPr2030(): void public function testBug6265(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-6265.php'); $this->assertNotEmpty($errors); } public function testBug8503(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-8503.php'); $this->assertNoErrors($errors); } @@ -1170,6 +1283,7 @@ public function testBug8503(): void #[RequiresPhp('>= 8.0')] public function testBug8537(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-8537.php'); $this->assertNoErrors($errors); } @@ -1177,6 +1291,7 @@ public function testBug8537(): void #[RequiresPhp('>= 8.1')] public function testBug7927(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-7927.php'); $this->assertCount(2, $errors); $this->assertSame('Enum case Bug7927\Test::One does not have a value but the enum is backed with the "int" type.', $errors[0]->getMessage()); @@ -1185,18 +1300,21 @@ public function testBug7927(): void public function testBug8146(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-8146b.php'); $this->assertNoErrors($errors); } public function testBug8215(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-8215.php'); $this->assertNoErrors($errors); } public function testBug8146a(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-8146a.php'); $this->assertNoErrors($errors); } @@ -1210,6 +1328,7 @@ public static function getAdditionalConfigFiles(): array public function testBug8004(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-8004.php'); $this->assertCount(2, $errors); $this->assertSame('Strict comparison using !== between null and DateTimeInterface|string will always evaluate to true.', $errors[0]->getMessage()); @@ -1229,30 +1348,35 @@ public function testSkipCheckNoGenericClasses(): void #[RequiresPhp('>= 8.1')] public function testBug8983(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-8983.php'); $this->assertNoErrors($errors); } public function testBug9008(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-9008.php'); $this->assertNoErrors($errors); } public function testBug5091(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-5091.php'); $this->assertNoErrors($errors); } public function testBug13507(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-13507.php'); $this->assertNoErrors($errors); } public function testBug9459(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-9459.php'); $this->assertCount(1, $errors); $this->assertSame('PHPDoc tag @var with type callable(): array is not subtype of native type Closure(): array{}.', $errors[0]->getMessage()); @@ -1260,12 +1384,14 @@ public function testBug9459(): void public function testBug9573(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-9573.php'); $this->assertNoErrors($errors); } public function testBug13978(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-13978.php'); $this->assertNoErrors($errors); } @@ -1278,6 +1404,7 @@ public function testDiscussion13979(): void public function testBug9039(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-9039.php'); $this->assertCount(1, $errors); $this->assertSame('Constant Bug9039\Test::RULES is unused.', $errors[0]->getMessage()); @@ -1292,6 +1419,7 @@ public function testDiscussion9053(): void public function testBug13492(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-13492.php'); $this->assertNoErrors($errors); } @@ -1305,12 +1433,14 @@ public function testProcessCalledMethodInfiniteLoop(): void #[RequiresPhp('>= 8.0')] public function testBug9428(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-9428.php'); $this->assertNoErrors($errors); } public function testBug9690(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-9690.php'); $this->assertNoErrors($errors); } @@ -1339,6 +1469,7 @@ public function testIgnoreIdentifiers(): void #[RequiresPhp('>= 8.1')] public function testBug9994(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-9994.php'); $this->assertCount(2, $errors); $this->assertSame('Negated boolean expression is always false.', $errors[0]->getMessage()); @@ -1348,12 +1479,14 @@ public function testBug9994(): void #[RequiresPhp('>= 8.1')] public function testBug13987(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-13987.php'); $this->assertNoErrors($errors); } public function testBug13982(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-13982.php'); $this->assertNoErrors($errors); } @@ -1361,6 +1494,7 @@ public function testBug13982(): void #[RequiresPhp('>= 8.1')] public function testBug10049(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-10049-recursive.php'); $this->assertCount(4, $errors); $this->assertSame('PHPDoc tag @template for class Bug10049Recursive\SimpleEntity cannot have existing class Bug10049Recursive\SimpleEntity as its name.', $errors[0]->getMessage()); @@ -1376,12 +1510,14 @@ public function testBug10049(): void #[RequiresPhp('>= 8.0')] public function testBug10086(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-10086.php'); $this->assertNoErrors($errors); } public function testBug10147(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-10147.php'); $this->assertNoErrors($errors); } @@ -1389,12 +1525,14 @@ public function testBug10147(): void #[RequiresPhp('>= 8.2')] public function testBug10302(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-10302.php'); $this->assertNoErrors($errors); } public function testBug10358(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-10358.php'); $this->assertCount(1, $errors); $this->assertSame('Cannot use Ns\Foo2 as Foo because the name is already in use', $errors[0]->getMessage()); @@ -1403,6 +1541,7 @@ public function testBug10358(): void public function testBug10509(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-10509.php'); $this->assertCount(2, $errors); $this->assertSame('Method Bug10509\Foo::doFoo() has no return type specified.', $errors[0]->getMessage()); @@ -1411,6 +1550,7 @@ public function testBug10509(): void public function testBug10538(): void { + // infinite run $errors = $this->runAnalyse(__DIR__ . '/data/bug-10538.php'); $this->assertNoErrors($errors); } @@ -1418,6 +1558,7 @@ public function testBug10538(): void #[RequiresPhp('>= 8.1')] public function testBug10847(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-10847.php'); $this->assertNoErrors($errors); } @@ -1425,6 +1566,7 @@ public function testBug10847(): void #[RequiresPhp('>= 8.1')] public function testBug10772(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-10772.php'); $this->assertNoErrors($errors); } @@ -1432,6 +1574,7 @@ public function testBug10772(): void #[RequiresPhp('>= 8.1')] public function testBug10985(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-10985.php'); $this->assertNoErrors($errors); } @@ -1439,18 +1582,21 @@ public function testBug10985(): void #[RequiresPhp('>= 8.1')] public function testBug10979(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-10979.php'); $this->assertNoErrors($errors); } public function testBug11026(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-11026.php'); $this->assertNoErrors($errors); } public function testBug10867(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-10867.php'); $this->assertNoErrors($errors); } @@ -1458,6 +1604,7 @@ public function testBug10867(): void #[RequiresPhp('>= 8.1')] public function testBug11263(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-11263.php'); $this->assertNoErrors($errors); } @@ -1465,6 +1612,7 @@ public function testBug11263(): void #[RequiresPhp('>= 8.0')] public function testBug11147(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-11147.php'); $this->assertCount(1, $errors); $this->assertSame('Method Bug11147\RedisAdapter::createConnection() has invalid return type Bug11147\NonExistentClass.', $errors[0]->getMessage()); @@ -1473,12 +1621,14 @@ public function testBug11147(): void #[RequiresPhp('>= 8.0')] public function testBug11283(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-11283.php'); $this->assertNoErrors($errors); } public function testBug11292(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-11292.php'); $this->assertNoErrors($errors); } @@ -1486,6 +1636,7 @@ public function testBug11292(): void #[RequiresPhp('>= 8.1')] public function testBug11297(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-11297.php'); $this->assertNoErrors($errors); } @@ -1493,6 +1644,7 @@ public function testBug11297(): void #[RequiresPhp('>= 8.0')] public function testBug5597(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-5597.php'); $this->assertNoErrors($errors); } @@ -1500,6 +1652,7 @@ public function testBug5597(): void #[RequiresPhp('>= 8.0')] public function testBug11511(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-11511.php'); $this->assertCount(1, $errors); $this->assertSame('Access to an undefined property object::$bar.', $errors[0]->getMessage()); @@ -1507,18 +1660,21 @@ public function testBug11511(): void public function testBug12214(): void { + // false negative $errors = $this->runAnalyse(__DIR__ . '/data/bug-12214.php'); $this->assertNoErrors($errors); } public function testBug11598(): void { + // false negative $errors = $this->runAnalyse(__DIR__ . '/data/bug-11598.php'); $this->assertNoErrors($errors); } public function testBug11640(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-11640.php'); $this->assertNoErrors($errors); } @@ -1526,12 +1682,14 @@ public function testBug11640(): void #[RequiresPhp('>= 8.0')] public function testBug11709(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-11709.php'); $this->assertNoErrors($errors); } public function testBug11913(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-11913.php'); $this->assertNoErrors($errors); } @@ -1539,12 +1697,14 @@ public function testBug11913(): void #[RequiresPhp('>= 8.3')] public function testBug12549(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12549.php'); $this->assertNoErrors($errors); } public function testBug12627(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12627.php'); $this->assertNoErrors($errors); } @@ -1552,18 +1712,21 @@ public function testBug12627(): void #[RequiresPhp('>= 8.3')] public function testBug12159(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-12159.php'); $this->assertNoErrors($errors); } public function testBug12787(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-12787.php'); $this->assertNoErrors($errors); } public function testBug12800(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-12800.php'); $this->assertNoErrors($errors); } @@ -1571,6 +1734,7 @@ public function testBug12800(): void #[RequiresPhp('>= 8.3')] public function testBug12949(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12949.php'); $this->assertCount(3, $errors); $this->assertSame('Call to an undefined method object::0().', $errors[0]->getMessage()); @@ -1580,18 +1744,21 @@ public function testBug12949(): void public function testBug12979(): void { + // false negative $errors = $this->runAnalyse(__DIR__ . '/data/bug-12979.php'); $this->assertNoErrors($errors); } public function testBug12095(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-12095.php'); $this->assertNoErrors($errors); } public function testBug13279(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-13279.php'); $this->assertCount(1, $errors); $this->assertSame('Parameter #2 $offset of function array_splice expects int, string given.', $errors[0]->getMessage()); @@ -1599,6 +1766,7 @@ public function testBug13279(): void public function testBug13310(): void { + // performance // require file to make sure the defined function is known require_once __DIR__ . '/data/bug-13310.php'; @@ -1608,6 +1776,7 @@ public function testBug13310(): void public function testBug13714(): void { + // crash $errors = $this->runAnalyse(__DIR__ . '/data/bug-13714.php'); $this->assertCount(7, $errors); $this->assertSame('Function Bug13714\curl_setopt invoked with 3 parameters, 0 required.', $errors[0]->getMessage()); @@ -1621,6 +1790,7 @@ public function testBug13714(): void public function testBug13933(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-13933.php'); $this->assertNoErrors($errors); } @@ -1628,30 +1798,35 @@ public function testBug13933(): void #[RequiresPhp('>= 8.4')] public function testBug13980(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-13980.php'); $this->assertNoErrors($errors); } public function testBug14207(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-14207.php'); $this->assertNoErrors($errors); } public function testBug14207And(): void { + // performance $errors = $this->runAnalyse(__DIR__ . '/data/bug-14207-and.php'); $this->assertNoErrors($errors); } public function testBug13945(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-13945.php'); $this->assertNoErrors($errors); } public function testBug13945Two(): void { + // false positive $errors = $this->runAnalyse(__DIR__ . '/data/bug-13945-2.php'); $this->assertNoErrors($errors); } From fa1afb3a50ce17990d5ef46c388298f7a2ac6ce7 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Mar 2026 05:21:25 +0000 Subject: [PATCH 02/30] Extract PHPStanTestCaseTrait and add AbstractBenchCase for phpbench Extract shared container/config infrastructure from PHPStanTestCase into PHPStanTestCaseTrait so it can be reused by both PHPUnit tests and phpbench benchmarks without duplication. Add AbstractBenchCase with runAnalyse method for writing performance benchmarks. https://claude.ai/code/session_017EKgzxmzYFa1qUT8bcuohj --- phpstan-baseline.neon | 6 +- src/Testing/PHPStanTestCase.php | 71 +--------------- src/Testing/PHPStanTestCaseTrait.php | 81 +++++++++++++++++++ tests/PHPStan/Benchmark/AbstractBenchCase.php | 34 ++++++++ 4 files changed, 119 insertions(+), 73 deletions(-) create mode 100644 src/Testing/PHPStanTestCaseTrait.php create mode 100644 tests/PHPStan/Benchmark/AbstractBenchCase.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6c3ff7e1536..59357043ffe 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -754,10 +754,10 @@ parameters: path: src/Testing/LevelsTestCase.php - - rawMessage: Anonymous function has an unused use $container. - identifier: closure.unusedUse + rawMessage: Unused PHPStan\Benchmark\AbstractBenchCase::runAnalyse + identifier: shipmonk.deadMethod count: 1 - path: src/Testing/PHPStanTestCase.php + path: tests/PHPStan/Benchmark/AbstractBenchCase.php - rawMessage: 'Doing instanceof PHPStan\Type\ConstantScalarType is error-prone and deprecated. Use Type::isConstantScalarValue() or Type::getConstantScalarTypes() or Type::getConstantScalarValues() instead.' diff --git a/src/Testing/PHPStanTestCase.php b/src/Testing/PHPStanTestCase.php index 2532c300758..d85c4f3a5fa 100644 --- a/src/Testing/PHPStanTestCase.php +++ b/src/Testing/PHPStanTestCase.php @@ -8,14 +8,9 @@ use PHPStan\Analyser\ScopeFactory; use PHPStan\Analyser\TypeSpecifier; use PHPStan\BetterReflection\Reflector\Reflector; -use PHPStan\DependencyInjection\Container; -use PHPStan\DependencyInjection\ContainerFactory; use PHPStan\DependencyInjection\Reflection\ClassReflectionExtensionRegistryProvider; use PHPStan\DependencyInjection\Type\ExpressionTypeResolverExtensionRegistryProvider; use PHPStan\DependencyInjection\Type\OperatorTypeSpecifyingExtensionRegistryProvider; -use PHPStan\File\FileHelper; -use PHPStan\Internal\DirectoryCreator; -use PHPStan\Internal\DirectoryCreatorException; use PHPStan\Node\Printer\ExprPrinter; use PHPStan\Parser\Parser; use PHPStan\Php\ComposerPhpVersionFactory; @@ -32,76 +27,17 @@ use PHPStan\Type\UsefulTypeAliasResolver; use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\TestCase; -use function array_merge; use function count; -use function hash; use function implode; use function rtrim; use function sprintf; -use function sys_get_temp_dir; use const DIRECTORY_SEPARATOR; -use const PHP_VERSION_ID; /** @api */ abstract class PHPStanTestCase extends TestCase { - /** @var array */ - private static array $containers = []; - - /** @api */ - public static function getContainer(): Container - { - $additionalConfigFiles = [__DIR__ . '/TestCase.neon']; - foreach (static::getAdditionalConfigFiles() as $configFile) { - $additionalConfigFiles[] = $configFile; - } - $cacheKey = hash('sha256', implode("\n", $additionalConfigFiles)); - - if (!isset(self::$containers[$cacheKey])) { - $tmpDir = sys_get_temp_dir() . '/phpstan-tests'; - try { - DirectoryCreator::ensureDirectoryExists($tmpDir, 0777); - } catch (DirectoryCreatorException $e) { - self::fail($e->getMessage()); - } - - $rootDir = __DIR__ . '/../..'; - $fileHelper = new FileHelper($rootDir); - $rootDir = $fileHelper->normalizePath($rootDir, '/'); - $containerFactory = new ContainerFactory($rootDir); - $container = $containerFactory->create($tmpDir, array_merge([ - $containerFactory->getConfigDirectory() . '/config.level8.neon', - ], $additionalConfigFiles), []); - self::$containers[$cacheKey] = $container; - - foreach ($container->getParameter('bootstrapFiles') as $bootstrapFile) { - (static function (string $file) use ($container): void { - require_once $file; - })($bootstrapFile); - } - - if (PHP_VERSION_ID >= 80000) { - require_once __DIR__ . '/../../stubs/runtime/Enum/UnitEnum.php'; - require_once __DIR__ . '/../../stubs/runtime/Enum/BackedEnum.php'; - require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnum.php'; - require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumUnitCase.php'; - require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumBackedCase.php'; - } - } else { - ContainerFactory::postInitializeContainer(self::$containers[$cacheKey]); - } - - return self::$containers[$cacheKey]; - } - - /** - * @return string[] - */ - public static function getAdditionalConfigFiles(): array - { - return []; - } + use PHPStanTestCaseTrait; public static function getParser(): Parser { @@ -188,11 +124,6 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool return true; } - public static function getFileHelper(): FileHelper - { - return self::getContainer()->getByType(FileHelper::class); - } - /** * Provides a DIRECTORY_SEPARATOR agnostic assertion helper, to compare file paths. * diff --git a/src/Testing/PHPStanTestCaseTrait.php b/src/Testing/PHPStanTestCaseTrait.php new file mode 100644 index 00000000000..c4fc4b2e9bf --- /dev/null +++ b/src/Testing/PHPStanTestCaseTrait.php @@ -0,0 +1,81 @@ + */ + private static array $containers = []; + + public static function getContainer(): Container + { + $additionalConfigFiles = [__DIR__ . '/TestCase.neon']; + foreach (static::getAdditionalConfigFiles() as $configFile) { + $additionalConfigFiles[] = $configFile; + } + $cacheKey = hash('sha256', implode("\n", $additionalConfigFiles)); + + if (!isset(self::$containers[$cacheKey])) { + $tmpDir = sys_get_temp_dir() . '/phpstan-tests'; + try { + DirectoryCreator::ensureDirectoryExists($tmpDir, 0777); + } catch (DirectoryCreatorException $e) { + throw new RuntimeException($e->getMessage(), previous: $e); + } + + $rootDir = __DIR__ . '/../..'; + $fileHelper = new FileHelper($rootDir); + $rootDir = $fileHelper->normalizePath($rootDir, '/'); + $containerFactory = new ContainerFactory($rootDir); + $container = $containerFactory->create($tmpDir, array_merge([ + $containerFactory->getConfigDirectory() . '/config.level8.neon', + ], $additionalConfigFiles), []); + self::$containers[$cacheKey] = $container; + + foreach ($container->getParameter('bootstrapFiles') as $bootstrapFile) { + (static function (string $file): void { + require_once $file; + })($bootstrapFile); + } + + if (PHP_VERSION_ID >= 80000) { + require_once __DIR__ . '/../../stubs/runtime/Enum/UnitEnum.php'; + require_once __DIR__ . '/../../stubs/runtime/Enum/BackedEnum.php'; + require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnum.php'; + require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumUnitCase.php'; + require_once __DIR__ . '/../../stubs/runtime/Enum/ReflectionEnumBackedCase.php'; + } + } else { + ContainerFactory::postInitializeContainer(self::$containers[$cacheKey]); + } + + return self::$containers[$cacheKey]; + } + + /** + * @return string[] + */ + public static function getAdditionalConfigFiles(): array + { + return []; + } + + public static function getFileHelper(): FileHelper + { + return self::getContainer()->getByType(FileHelper::class); + } + +} diff --git a/tests/PHPStan/Benchmark/AbstractBenchCase.php b/tests/PHPStan/Benchmark/AbstractBenchCase.php new file mode 100644 index 00000000000..f6ce5467a74 --- /dev/null +++ b/tests/PHPStan/Benchmark/AbstractBenchCase.php @@ -0,0 +1,34 @@ + + */ + protected function runAnalyse(string $file, ?array $allAnalysedFiles = null): array + { + $file = self::getFileHelper()->normalizePath($file); + + $analyser = self::getContainer()->getByType(Analyser::class); + $finalizer = self::getContainer()->getByType(AnalyserResultFinalizer::class); + $errors = $finalizer->finalize( + $analyser->analyse([$file], null, null, true, $allAnalysedFiles), + false, + true, + )->getErrors(); + + return $errors; + } + +} From 2902fcfb781428190c6a1e689c6fd5086ae6fdd1 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Mar 2026 05:30:15 +0000 Subject: [PATCH 03/30] Restore $container in bootstrap closure, move AbstractBenchCase to tests/bench/ The $container variable in the bootstrap closure is used by bootstrap files at runtime. Moved AbstractBenchCase from tests/PHPStan/Benchmark/ to tests/bench/ and updated composer.json classmap accordingly. https://claude.ai/code/session_017EKgzxmzYFa1qUT8bcuohj --- composer.json | 3 ++- phpstan-baseline.neon | 18 +++++++++++++++--- src/Testing/PHPStanTestCaseTrait.php | 2 +- .../Benchmark => bench}/AbstractBenchCase.php | 0 4 files changed, 18 insertions(+), 5 deletions(-) rename tests/{PHPStan/Benchmark => bench}/AbstractBenchCase.php (100%) diff --git a/composer.json b/composer.json index 7e853c5406e..f9e58c76daa 100644 --- a/composer.json +++ b/composer.json @@ -153,7 +153,8 @@ }, "classmap": [ "tests/e2e", - "tests/PHPStan" + "tests/PHPStan", + "tests/bench" ] }, "repositories": [ diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 59357043ffe..dd5cf2ccca6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -754,10 +754,10 @@ parameters: path: src/Testing/LevelsTestCase.php - - rawMessage: Unused PHPStan\Benchmark\AbstractBenchCase::runAnalyse - identifier: shipmonk.deadMethod + rawMessage: Anonymous function has an unused use $container. + identifier: closure.unusedUse count: 1 - path: tests/PHPStan/Benchmark/AbstractBenchCase.php + path: src/Testing/PHPStanTestCase.php - rawMessage: 'Doing instanceof PHPStan\Type\ConstantScalarType is error-prone and deprecated. Use Type::isConstantScalarValue() or Type::getConstantScalarTypes() or Type::getConstantScalarValues() instead.' @@ -1863,6 +1863,18 @@ parameters: count: 1 path: tests/PHPStan/Analyser/EvaluationOrderTest.php + - + rawMessage: Anonymous function has an unused use $container. + identifier: closure.unusedUse + count: 1 + path: tests/bench/AbstractBenchCase.php + + - + rawMessage: Unused PHPStan\Benchmark\AbstractBenchCase::runAnalyse + identifier: shipmonk.deadMethod + count: 1 + path: tests/bench/AbstractBenchCase.php + - rawMessage: Constant SOME_CONSTANT_IN_AUTOLOAD_FILE not found. identifier: constant.notFound diff --git a/src/Testing/PHPStanTestCaseTrait.php b/src/Testing/PHPStanTestCaseTrait.php index c4fc4b2e9bf..49e4c6aef1c 100644 --- a/src/Testing/PHPStanTestCaseTrait.php +++ b/src/Testing/PHPStanTestCaseTrait.php @@ -46,7 +46,7 @@ public static function getContainer(): Container self::$containers[$cacheKey] = $container; foreach ($container->getParameter('bootstrapFiles') as $bootstrapFile) { - (static function (string $file): void { + (static function (string $file) use ($container): void { require_once $file; })($bootstrapFile); } diff --git a/tests/PHPStan/Benchmark/AbstractBenchCase.php b/tests/bench/AbstractBenchCase.php similarity index 100% rename from tests/PHPStan/Benchmark/AbstractBenchCase.php rename to tests/bench/AbstractBenchCase.php From ca8dd2a472d808a84d828d87e98052780706cc53 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Mar 2026 05:38:05 +0000 Subject: [PATCH 04/30] Move performance tests to phpbench RegressionBench Move 32 performance regression tests from AnalyserIntegrationTest to a new RegressionBench class using phpbench. Test data files moved to tests/bench/data/. This separates performance benchmarks from functional integration tests. https://claude.ai/code/session_017EKgzxmzYFa1qUT8bcuohj --- composer.json | 1 + composer.lock | 662 +++++++++++++++++- phpbench.json | 4 + phpstan-baseline.neon | 5 - .../Analyser/AnalyserIntegrationTest.php | 213 ------ tests/bench/RegressionBench.php | 201 ++++++ .../Analyser => bench}/data/bug-10772.php | 0 .../Analyser => bench}/data/bug-10979.php | 0 .../Analyser => bench}/data/bug-11263.php | 0 .../Analyser => bench}/data/bug-11283.php | 0 .../Analyser => bench}/data/bug-11297.php | 0 .../Analyser => bench}/data/bug-11913.php | 0 .../Analyser => bench}/data/bug-12159.php | 0 .../Analyser => bench}/data/bug-12787.php | 0 .../Analyser => bench}/data/bug-12800.php | 0 .../Analyser => bench}/data/bug-13310.php | 0 .../Analyser => bench}/data/bug-13352.php | 0 .../Analyser => bench}/data/bug-13685.php | 0 .../Analyser => bench}/data/bug-1388.php | 0 .../Analyser => bench}/data/bug-13933.php | 0 .../Analyser => bench}/data/bug-14207-and.php | 0 .../Analyser => bench}/data/bug-14207.php | 0 .../Analyser => bench}/data/bug-1447.php | 0 .../Analyser => bench}/data/bug-4308.php | 0 .../Analyser => bench}/data/bug-5081.php | 0 .../Analyser => bench}/data/bug-6265.php | 0 .../Analyser => bench}/data/bug-6936.php | 0 .../Analyser => bench}/data/bug-6948.php | 0 .../Analyser => bench}/data/bug-7581.php | 0 .../Analyser => bench}/data/bug-7637.php | 0 .../Analyser => bench}/data/bug-7901.php | 0 .../Analyser => bench}/data/bug-7903.php | 0 .../Analyser => bench}/data/bug-8146a.php | 0 .../Analyser => bench}/data/bug-8146b.php | 0 .../Analyser => bench}/data/bug-8147.php | 0 .../Analyser => bench}/data/bug-8215.php | 0 .../Analyser => bench}/data/bug-8503.php | 0 .../Analyser => bench}/data/bug-9690.php | 0 38 files changed, 866 insertions(+), 220 deletions(-) create mode 100644 phpbench.json create mode 100644 tests/bench/RegressionBench.php rename tests/{PHPStan/Analyser => bench}/data/bug-10772.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-10979.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-11263.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-11283.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-11297.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-11913.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-12159.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-12787.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-12800.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-13310.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-13352.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-13685.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-1388.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-13933.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-14207-and.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-14207.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-1447.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-4308.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-5081.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-6265.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-6936.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-6948.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-7581.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-7637.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-7901.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-7903.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-8146a.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-8146b.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-8147.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-8215.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-8503.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-9690.php (100%) diff --git a/composer.json b/composer.json index f9e58c76daa..0b5c09cab80 100644 --- a/composer.json +++ b/composer.json @@ -60,6 +60,7 @@ "require-dev": { "cweagans/composer-patches": "^1.7.3", "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpbench/phpbench": "^1.2", "phpstan/phpstan-deprecation-rules": "^2.0.2", "phpstan/phpstan-nette": "^2.0", "phpstan/phpstan-phpunit": "^2.0.8", diff --git a/composer.lock b/composer.lock index 8bbcf4ef465..385a9163aa1 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": "cbd96eba477c2f5a8a05a575aea7522d", + "content-hash": "4563800d2571a09790e7d441c9472235", "packages": [ { "name": "clue/ndjson-react", @@ -4614,6 +4614,160 @@ }, "time": "2022-12-20T22:53:13+00:00" }, + { + "name": "doctrine/annotations", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2 || ^3", + "ext-tokenizer": "*", + "php": "^7.2 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^2.0", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.10.28", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^5.4 || ^6.4 || ^7", + "vimeo/psalm": "^4.30 || ^5.14" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/2.0.2" + }, + "abandoned": true, + "time": "2024-09-05T10:17:24+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.13.4", @@ -4853,6 +5007,207 @@ }, "time": "2024-03-27T12:14:49+00:00" }, + { + "name": "phpbench/container", + "version": "2.2.3", + "source": { + "type": "git", + "url": "https://github.com/phpbench/container.git", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", + "shasum": "" + }, + "require": { + "psr/container": "^1.0|^2.0", + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" + }, + "require-dev": { + "php-cs-fixer/shim": "^3.89", + "phpstan/phpstan": "^0.12.52", + "phpunit/phpunit": "^8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpBench\\DependencyInjection\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Leech", + "email": "daniel@dantleech.com" + } + ], + "description": "Simple, configurable, service container.", + "support": { + "issues": "https://github.com/phpbench/container/issues", + "source": "https://github.com/phpbench/container/tree/2.2.3" + }, + "time": "2025-11-06T09:05:13+00:00" + }, + { + "name": "phpbench/dom", + "version": "0.3.3", + "source": { + "type": "git", + "url": "https://github.com/phpbench/dom.git", + "reference": "786a96db538d0def931f5b19225233ec42ec7a72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpbench/dom/zipball/786a96db538d0def931f5b19225233ec42ec7a72", + "reference": "786a96db538d0def931f5b19225233ec42ec7a72", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": "^7.3||^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.14", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.0||^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpBench\\Dom\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Leech", + "email": "daniel@dantleech.com" + } + ], + "description": "DOM wrapper to simplify working with the PHP DOM implementation", + "support": { + "issues": "https://github.com/phpbench/dom/issues", + "source": "https://github.com/phpbench/dom/tree/0.3.3" + }, + "abandoned": true, + "time": "2023-03-06T23:46:57+00:00" + }, + { + "name": "phpbench/phpbench", + "version": "1.2.15", + "source": { + "type": "git", + "url": "https://github.com/phpbench/phpbench.git", + "reference": "f7000319695cfad04a57fc64bf7ef7abdf4c437c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/f7000319695cfad04a57fc64bf7ef7abdf4c437c", + "reference": "f7000319695cfad04a57fc64bf7ef7abdf4c437c", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^2.0", + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "ext-tokenizer": "*", + "php": "^8.1", + "phpbench/container": "^2.1", + "phpbench/dom": "~0.3.3", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "seld/jsonlint": "^1.1", + "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0", + "symfony/filesystem": "^4.2 || ^5.0 || ^6.0 || ^7.0", + "symfony/finder": "^4.2 || ^5.0 || ^6.0 || ^7.0", + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0", + "symfony/process": "^4.2 || ^5.0 || ^6.0 || ^7.0", + "webmozart/glob": "^4.6" + }, + "require-dev": { + "dantleech/invoke": "^2.0", + "friendsofphp/php-cs-fixer": "^3.0", + "jangregor/phpstan-prophecy": "^1.0", + "phpspec/prophecy": "dev-master", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^10.0", + "rector/rector": "^0.18.10", + "symfony/error-handler": "^5.2 || ^6.0 || ^7.0", + "symfony/var-dumper": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "suggest": { + "ext-xdebug": "For Xdebug profiling extension." + }, + "bin": [ + "bin/phpbench" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "files": [ + "lib/Report/Func/functions.php" + ], + "psr-4": { + "PhpBench\\": "lib/", + "PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Leech", + "email": "daniel@dantleech.com" + } + ], + "description": "PHP Benchmarking Framework", + "keywords": [ + "benchmarking", + "optimization", + "performance", + "profiling", + "testing" + ], + "support": { + "issues": "https://github.com/phpbench/phpbench/issues", + "source": "https://github.com/phpbench/phpbench/tree/1.2.15" + }, + "funding": [ + { + "url": "https://github.com/dantleech", + "type": "github" + } + ], + "time": "2023-11-29T12:21:11+00:00" + }, { "name": "phpstan/phpstan-deprecation-rules", "version": "2.0.4", @@ -5529,6 +5884,55 @@ ], "time": "2026-02-08T07:05:14+00:00" }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, { "name": "sebastian/cli-parser", "version": "3.0.2", @@ -6448,6 +6852,70 @@ ], "time": "2024-10-09T05:16:32+00:00" }, + { + "name": "seld/jsonlint", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2024-07-11T14:55:45+00:00" + }, { "name": "shipmonk/composer-dependency-analyser", "version": "1.7.0", @@ -6703,6 +7171,147 @@ ], "time": "2024-10-20T05:08:20+00:00" }, + { + "name": "symfony/filesystem", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T16:50:00+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "b38026df55197f9e39a44f3215788edf83187b80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", + "reference": "b38026df55197f9e39a44f3215788edf83187b80", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-11-12T15:39:26+00:00" + }, { "name": "theseer/tokenizer", "version": "1.3.1", @@ -6752,6 +7361,55 @@ } ], "time": "2025-11-17T20:03:58+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.7.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/glob.git", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "symfony/filesystem": "^5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "support": { + "issues": "https://github.com/webmozarts/glob/issues", + "source": "https://github.com/webmozarts/glob/tree/4.7.0" + }, + "time": "2024-03-07T20:33:40+00:00" } ], "aliases": [], @@ -6769,5 +7427,5 @@ "platform-overrides": { "php": "8.2.99" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/phpbench.json b/phpbench.json new file mode 100644 index 00000000000..c1e48b1d74c --- /dev/null +++ b/phpbench.json @@ -0,0 +1,4 @@ +{ + "runner.bootstrap": "vendor/autoload.php", + "runner.path": "tests/bench" +} diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index dd5cf2ccca6..b75b62a8b80 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1869,11 +1869,6 @@ parameters: count: 1 path: tests/bench/AbstractBenchCase.php - - - rawMessage: Unused PHPStan\Benchmark\AbstractBenchCase::runAnalyse - identifier: shipmonk.deadMethod - count: 1 - path: tests/bench/AbstractBenchCase.php - rawMessage: Constant SOME_CONSTANT_IN_AUTOLOAD_FILE not found. diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 5fe2f04b3fb..98e4d00e8dc 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -240,12 +240,6 @@ public function testTwoSameClassesInSingleFile(): void $this->assertSame(36, $error->getLine()); } - public function testBug6936(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-6936.php'); - $this->assertNoErrors($errors); - } public function testBug3405(): void { @@ -284,13 +278,6 @@ public function testBug3686(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.0')] - public function testBug13352(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-13352.php'); - $this->assertNoErrors($errors); - } public function testBug3379(): void { @@ -300,12 +287,6 @@ public function testBug3379(): void $this->assertSame('Constant SOME_UNKNOWN_CONST not found.', $errors[0]->getMessage()); } - public function testBug13685(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-13685.php'); - $this->assertNoErrors($errors); - } public function testBug3798(): void { @@ -742,34 +723,9 @@ public function testBug6940(): void $this->assertSame(12, $errors[0]->getLine()); } - public function testBug1447(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-1447.php'); - $this->assertNoErrors($errors); - } - public function testBug5081(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-5081.php'); - $this->assertNoErrors($errors); - } - public function testBug1388(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-1388.php'); - $this->assertNoErrors($errors); - } - #[RequiresPhp('>= 8.0')] - public function testBug4308(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-4308.php'); - $this->assertNoErrors($errors); - } public function testBug4732(): void { @@ -1024,21 +980,6 @@ public function testBug7554(): void $this->assertSame(27, $errors[1]->getLine()); } - public function testBug7637(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-7637.php'); - $this->assertCount(3, $errors); - - $this->assertSame('Method Bug7637\HelloWorld::getProperty() has invalid return type Bug7637\rex_backend_login.', $errors[0]->getMessage()); - $this->assertSame(54, $errors[0]->getLine()); - - $this->assertSame('Method Bug7637\HelloWorld::getProperty() has invalid return type Bug7637\rex_timer.', $errors[1]->getMessage()); - $this->assertSame(54, $errors[1]->getLine()); - - $this->assertSame('Call to function is_string() with string will always evaluate to true.', $errors[2]->getMessage()); - $this->assertSame(57, $errors[2]->getLine()); - } public function testBug12671(): void { @@ -1082,26 +1023,8 @@ public function testBug7320(): void $this->assertSame(13, $errors[0]->getLine()); } - public function testBug7581(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-7581.php'); - $this->assertNoErrors($errors); - } - public function testBug7903(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-7903.php'); - $this->assertCount(39, $errors); - } - public function testBug7901(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-7901.php'); - $this->assertNoErrors($errors); - } public function testBug7918(): void { @@ -1123,12 +1046,6 @@ public function testArrayUnion(): void $this->assertNoErrors($errors); } - public function testBug6948(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-6948.php'); - $this->assertNoErrors($errors); - } public function testBug7963(): void { @@ -1238,13 +1155,6 @@ public function testAssertDocblock(): void $this->assertSame(238, $errors[3]->getLine()); } - #[RequiresPhp('>= 8.0')] - public function testBug8147(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-8147.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.0')] public function testBug12934(): void @@ -1266,19 +1176,7 @@ public function testPr2030(): void $this->assertNoErrors($errors); } - public function testBug6265(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-6265.php'); - $this->assertNotEmpty($errors); - } - public function testBug8503(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-8503.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.0')] public function testBug8537(): void @@ -1298,26 +1196,8 @@ public function testBug7927(): void $this->assertSame('Enum case Bug7927\Test::Two does not have a value but the enum is backed with the "int" type.', $errors[1]->getMessage()); } - public function testBug8146(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-8146b.php'); - $this->assertNoErrors($errors); - } - public function testBug8215(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-8215.php'); - $this->assertNoErrors($errors); - } - public function testBug8146a(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-8146a.php'); - $this->assertNoErrors($errors); - } public static function getAdditionalConfigFiles(): array { @@ -1438,12 +1318,6 @@ public function testBug9428(): void $this->assertNoErrors($errors); } - public function testBug9690(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-9690.php'); - $this->assertNoErrors($errors); - } public function testIgnoreIdentifiers(): void { @@ -1563,13 +1437,6 @@ public function testBug10847(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.1')] - public function testBug10772(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-10772.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.1')] public function testBug10985(): void @@ -1579,13 +1446,6 @@ public function testBug10985(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.1')] - public function testBug10979(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-10979.php'); - $this->assertNoErrors($errors); - } public function testBug11026(): void { @@ -1601,13 +1461,6 @@ public function testBug10867(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.1')] - public function testBug11263(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-11263.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.0')] public function testBug11147(): void @@ -1618,13 +1471,6 @@ public function testBug11147(): void $this->assertSame('Method Bug11147\RedisAdapter::createConnection() has invalid return type Bug11147\NonExistentClass.', $errors[0]->getMessage()); } - #[RequiresPhp('>= 8.0')] - public function testBug11283(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-11283.php'); - $this->assertNoErrors($errors); - } public function testBug11292(): void { @@ -1633,13 +1479,6 @@ public function testBug11292(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.1')] - public function testBug11297(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-11297.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.0')] public function testBug5597(): void @@ -1687,12 +1526,6 @@ public function testBug11709(): void $this->assertNoErrors($errors); } - public function testBug11913(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-11913.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.3')] public function testBug12549(): void @@ -1709,27 +1542,8 @@ public function testBug12627(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.3')] - public function testBug12159(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-12159.php'); - $this->assertNoErrors($errors); - } - public function testBug12787(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-12787.php'); - $this->assertNoErrors($errors); - } - public function testBug12800(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-12800.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.3')] public function testBug12949(): void @@ -1764,15 +1578,6 @@ public function testBug13279(): void $this->assertSame('Parameter #2 $offset of function array_splice expects int, string given.', $errors[0]->getMessage()); } - public function testBug13310(): void - { - // performance - // require file to make sure the defined function is known - require_once __DIR__ . '/data/bug-13310.php'; - - $errors = $this->runAnalyse(__DIR__ . '/data/bug-13310.php'); - $this->assertNoErrors($errors); - } public function testBug13714(): void { @@ -1788,12 +1593,6 @@ public function testBug13714(): void $this->assertSame('Function Bug13714\array_find invoked with 2 parameters, 0 required.', $errors[6]->getMessage()); } - public function testBug13933(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-13933.php'); - $this->assertNoErrors($errors); - } #[RequiresPhp('>= 8.4')] public function testBug13980(): void @@ -1803,19 +1602,7 @@ public function testBug13980(): void $this->assertNoErrors($errors); } - public function testBug14207(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-14207.php'); - $this->assertNoErrors($errors); - } - public function testBug14207And(): void - { - // performance - $errors = $this->runAnalyse(__DIR__ . '/data/bug-14207-and.php'); - $this->assertNoErrors($errors); - } public function testBug13945(): void { diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php new file mode 100644 index 00000000000..af5bd2a1d0f --- /dev/null +++ b/tests/bench/RegressionBench.php @@ -0,0 +1,201 @@ +runAnalyse(__DIR__ . '/data/bug-1388.php'); + } + + public function benchBug1447(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-1447.php'); + } + + public function benchBug4308(): void + { + if (PHP_VERSION_ID < 80000) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-4308.php'); + } + + public function benchBug5081(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-5081.php'); + } + + public function benchBug6265(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-6265.php'); + } + + public function benchBug6936(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-6936.php'); + } + + public function benchBug6948(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-6948.php'); + } + + public function benchBug7581(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-7581.php'); + } + + public function benchBug7637(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-7637.php'); + } + + public function benchBug7901(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-7901.php'); + } + + public function benchBug7903(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-7903.php'); + } + + public function benchBug8146(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-8146b.php'); + } + + public function benchBug8146a(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-8146a.php'); + } + + public function benchBug8147(): void + { + if (PHP_VERSION_ID < 80000) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-8147.php'); + } + + public function benchBug8215(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-8215.php'); + } + + public function benchBug8503(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-8503.php'); + } + + public function benchBug9690(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-9690.php'); + } + + public function benchBug10772(): void + { + if (PHP_VERSION_ID < 80100) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-10772.php'); + } + + public function benchBug10979(): void + { + if (PHP_VERSION_ID < 80100) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-10979.php'); + } + + public function benchBug11263(): void + { + if (PHP_VERSION_ID < 80100) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-11263.php'); + } + + public function benchBug11283(): void + { + if (PHP_VERSION_ID < 80000) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-11283.php'); + } + + public function benchBug11297(): void + { + if (PHP_VERSION_ID < 80100) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-11297.php'); + } + + public function benchBug11913(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-11913.php'); + } + + public function benchBug12159(): void + { + if (PHP_VERSION_ID < 80300) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-12159.php'); + } + + public function benchBug12787(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-12787.php'); + } + + public function benchBug12800(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-12800.php'); + } + + public function benchBug13310(): void + { + require_once __DIR__ . '/data/bug-13310.php'; + $this->runAnalyse(__DIR__ . '/data/bug-13310.php'); + } + + public function benchBug13352(): void + { + if (PHP_VERSION_ID < 80000) { + return; + } + $this->runAnalyse(__DIR__ . '/data/bug-13352.php'); + } + + public function benchBug13685(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-13685.php'); + } + + public function benchBug13933(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-13933.php'); + } + + public function benchBug14207(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-14207.php'); + } + + public function benchBug14207And(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-14207-and.php'); + } + +} diff --git a/tests/PHPStan/Analyser/data/bug-10772.php b/tests/bench/data/bug-10772.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-10772.php rename to tests/bench/data/bug-10772.php diff --git a/tests/PHPStan/Analyser/data/bug-10979.php b/tests/bench/data/bug-10979.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-10979.php rename to tests/bench/data/bug-10979.php diff --git a/tests/PHPStan/Analyser/data/bug-11263.php b/tests/bench/data/bug-11263.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-11263.php rename to tests/bench/data/bug-11263.php diff --git a/tests/PHPStan/Analyser/data/bug-11283.php b/tests/bench/data/bug-11283.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-11283.php rename to tests/bench/data/bug-11283.php diff --git a/tests/PHPStan/Analyser/data/bug-11297.php b/tests/bench/data/bug-11297.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-11297.php rename to tests/bench/data/bug-11297.php diff --git a/tests/PHPStan/Analyser/data/bug-11913.php b/tests/bench/data/bug-11913.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-11913.php rename to tests/bench/data/bug-11913.php diff --git a/tests/PHPStan/Analyser/data/bug-12159.php b/tests/bench/data/bug-12159.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-12159.php rename to tests/bench/data/bug-12159.php diff --git a/tests/PHPStan/Analyser/data/bug-12787.php b/tests/bench/data/bug-12787.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-12787.php rename to tests/bench/data/bug-12787.php diff --git a/tests/PHPStan/Analyser/data/bug-12800.php b/tests/bench/data/bug-12800.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-12800.php rename to tests/bench/data/bug-12800.php diff --git a/tests/PHPStan/Analyser/data/bug-13310.php b/tests/bench/data/bug-13310.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-13310.php rename to tests/bench/data/bug-13310.php diff --git a/tests/PHPStan/Analyser/data/bug-13352.php b/tests/bench/data/bug-13352.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-13352.php rename to tests/bench/data/bug-13352.php diff --git a/tests/PHPStan/Analyser/data/bug-13685.php b/tests/bench/data/bug-13685.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-13685.php rename to tests/bench/data/bug-13685.php diff --git a/tests/PHPStan/Analyser/data/bug-1388.php b/tests/bench/data/bug-1388.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-1388.php rename to tests/bench/data/bug-1388.php diff --git a/tests/PHPStan/Analyser/data/bug-13933.php b/tests/bench/data/bug-13933.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-13933.php rename to tests/bench/data/bug-13933.php diff --git a/tests/PHPStan/Analyser/data/bug-14207-and.php b/tests/bench/data/bug-14207-and.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-14207-and.php rename to tests/bench/data/bug-14207-and.php diff --git a/tests/PHPStan/Analyser/data/bug-14207.php b/tests/bench/data/bug-14207.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-14207.php rename to tests/bench/data/bug-14207.php diff --git a/tests/PHPStan/Analyser/data/bug-1447.php b/tests/bench/data/bug-1447.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-1447.php rename to tests/bench/data/bug-1447.php diff --git a/tests/PHPStan/Analyser/data/bug-4308.php b/tests/bench/data/bug-4308.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-4308.php rename to tests/bench/data/bug-4308.php diff --git a/tests/PHPStan/Analyser/data/bug-5081.php b/tests/bench/data/bug-5081.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-5081.php rename to tests/bench/data/bug-5081.php diff --git a/tests/PHPStan/Analyser/data/bug-6265.php b/tests/bench/data/bug-6265.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-6265.php rename to tests/bench/data/bug-6265.php diff --git a/tests/PHPStan/Analyser/data/bug-6936.php b/tests/bench/data/bug-6936.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-6936.php rename to tests/bench/data/bug-6936.php diff --git a/tests/PHPStan/Analyser/data/bug-6948.php b/tests/bench/data/bug-6948.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-6948.php rename to tests/bench/data/bug-6948.php diff --git a/tests/PHPStan/Analyser/data/bug-7581.php b/tests/bench/data/bug-7581.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-7581.php rename to tests/bench/data/bug-7581.php diff --git a/tests/PHPStan/Analyser/data/bug-7637.php b/tests/bench/data/bug-7637.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-7637.php rename to tests/bench/data/bug-7637.php diff --git a/tests/PHPStan/Analyser/data/bug-7901.php b/tests/bench/data/bug-7901.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-7901.php rename to tests/bench/data/bug-7901.php diff --git a/tests/PHPStan/Analyser/data/bug-7903.php b/tests/bench/data/bug-7903.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-7903.php rename to tests/bench/data/bug-7903.php diff --git a/tests/PHPStan/Analyser/data/bug-8146a.php b/tests/bench/data/bug-8146a.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-8146a.php rename to tests/bench/data/bug-8146a.php diff --git a/tests/PHPStan/Analyser/data/bug-8146b.php b/tests/bench/data/bug-8146b.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-8146b.php rename to tests/bench/data/bug-8146b.php diff --git a/tests/PHPStan/Analyser/data/bug-8147.php b/tests/bench/data/bug-8147.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-8147.php rename to tests/bench/data/bug-8147.php diff --git a/tests/PHPStan/Analyser/data/bug-8215.php b/tests/bench/data/bug-8215.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-8215.php rename to tests/bench/data/bug-8215.php diff --git a/tests/PHPStan/Analyser/data/bug-8503.php b/tests/bench/data/bug-8503.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-8503.php rename to tests/bench/data/bug-8503.php diff --git a/tests/PHPStan/Analyser/data/bug-9690.php b/tests/bench/data/bug-9690.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-9690.php rename to tests/bench/data/bug-9690.php From 3024c44a34f1dd6773ee62d6791fcd91dfc152f1 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Mar 2026 05:57:11 +0000 Subject: [PATCH 05/30] Add .phpbench to .gitignore phpbench stores local benchmark results in .phpbench/ which are machine-specific and should not be committed. https://claude.ai/code/session_017EKgzxmzYFa1qUT8bcuohj --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a1528dc2767..bb7d569b8d6 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ /tests/PHPStan/Reflection/data/golden/ tmp/.memory_limit e2e/bashunit +/.phpbench From 1859b17c62d26c7e3437ea6cc639166c72883e24 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 07:09:39 +0100 Subject: [PATCH 06/30] Exclude tests/bench/data from linting --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 97eb28b4673..f9022a401dc 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ tests-golden-reflection: lint: XDEBUG_MODE=off php vendor/bin/parallel-lint --colors \ --exclude tests/PHPStan/Analyser/data \ + --exclude tests/bench/data \ --exclude tests/PHPStan/Analyser/nsrt \ --exclude tests/PHPStan/Rules/Methods/data \ --exclude tests/PHPStan/Rules/Functions/data \ From 0c94d2839d6a611d1247eeb4e41dd642086615c6 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 07:10:43 +0100 Subject: [PATCH 07/30] No need to exclude old PHP versions, it will always run on PHP 8.5 --- tests/bench/RegressionBench.php | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index af5bd2a1d0f..4b2ee7f8554 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -22,9 +22,6 @@ public function benchBug1447(): void public function benchBug4308(): void { - if (PHP_VERSION_ID < 80000) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-4308.php'); } @@ -80,9 +77,6 @@ public function benchBug8146a(): void public function benchBug8147(): void { - if (PHP_VERSION_ID < 80000) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-8147.php'); } @@ -103,41 +97,26 @@ public function benchBug9690(): void public function benchBug10772(): void { - if (PHP_VERSION_ID < 80100) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-10772.php'); } public function benchBug10979(): void { - if (PHP_VERSION_ID < 80100) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-10979.php'); } public function benchBug11263(): void { - if (PHP_VERSION_ID < 80100) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-11263.php'); } public function benchBug11283(): void { - if (PHP_VERSION_ID < 80000) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-11283.php'); } public function benchBug11297(): void { - if (PHP_VERSION_ID < 80100) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-11297.php'); } @@ -148,9 +127,6 @@ public function benchBug11913(): void public function benchBug12159(): void { - if (PHP_VERSION_ID < 80300) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-12159.php'); } @@ -172,9 +148,6 @@ public function benchBug13310(): void public function benchBug13352(): void { - if (PHP_VERSION_ID < 80000) { - return; - } $this->runAnalyse(__DIR__ . '/data/bug-13352.php'); } From 1710adb003302a0cda71b2ebb311a9f7a86304e4 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 07:17:42 +0100 Subject: [PATCH 08/30] Improve phpbench config --- phpbench.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phpbench.json b/phpbench.json index c1e48b1d74c..5cc579357b9 100644 --- a/phpbench.json +++ b/phpbench.json @@ -1,4 +1,6 @@ { + "$schema":"./vendor/phpbench/phpbench/phpbench.schema.json", "runner.bootstrap": "vendor/autoload.php", - "runner.path": "tests/bench" + "runner.path": "tests/bench", + "runner.file_pattern": "*Bench.php" } From 7e6e94dafb60649965b0391693e2b3379e1f2ceb Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 07:18:41 +0100 Subject: [PATCH 09/30] phpbench storage --- phpbench.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpbench.json b/phpbench.json index 5cc579357b9..c7dcc77dfcd 100644 --- a/phpbench.json +++ b/phpbench.json @@ -2,5 +2,6 @@ "$schema":"./vendor/phpbench/phpbench/phpbench.schema.json", "runner.bootstrap": "vendor/autoload.php", "runner.path": "tests/bench", - "runner.file_pattern": "*Bench.php" + "runner.file_pattern": "*Bench.php", + "storage.xml_storage_path": "tests/bench/storage" } From 0f1f4803e0248eb8aa5092db65ec2f488fabcc79 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 07:37:43 +0100 Subject: [PATCH 10/30] Moved "infinite run" tests --- .../Analyser/AnalyserIntegrationTest.php | 92 ------------------- tests/bench/RegressionBench.php | 58 +++++++++++- .../Analyser => bench}/data/bug-10147.php | 0 .../Analyser => bench}/data/bug-10538.php | 0 .../Analyser => bench}/data/bug-12671.php | 0 .../Analyser => bench}/data/bug-13218.php | 0 .../Analyser => bench}/data/bug-3686.php | 0 .../Analyser => bench}/data/bug-4300.php | 0 .../Analyser => bench}/data/bug-5231.php | 0 .../Analyser => bench}/data/bug-5231_2.php | 0 .../Analyser => bench}/data/bug-6442.php | 0 .../Analyser => bench}/data/bug-7140.php | 0 .../Analyser => bench}/data/bug-7214.php | 0 13 files changed, 57 insertions(+), 93 deletions(-) rename tests/{PHPStan/Analyser => bench}/data/bug-10147.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-10538.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-12671.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-13218.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-3686.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-4300.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-5231.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-5231_2.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-6442.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-7140.php (100%) rename tests/{PHPStan/Analyser => bench}/data/bug-7214.php (100%) diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 98e4d00e8dc..36d7ca6e58c 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -271,14 +271,6 @@ public function testBug3468(): void $this->assertNoErrors($errors); } - public function testBug3686(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-3686.php'); - $this->assertNoErrors($errors); - } - - public function testBug3379(): void { // crash @@ -309,15 +301,6 @@ public function testBug4097(): void $this->assertNoErrors($errors); } - public function testBug4300(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-4300.php'); - $this->assertCount(1, $errors); - $this->assertSame('Comparison operation ">" between 0 and 0 is always false.', $errors[0]->getMessage()); - $this->assertSame(13, $errors[0]->getLine()); - } - public function testBug4513(): void { // false positive @@ -478,20 +461,6 @@ public function testBug4734(): void $this->assertSame('Access to an undefined property Bug4734\Foo::$httpMethodParameterOverride4.', $errors[4]->getMessage()); } - public function testBug5231(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-5231.php'); - $this->assertNotEmpty($errors); - } - - public function testBug5231Two(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-5231_2.php'); - $this->assertNotEmpty($errors); - } - #[RequiresPhp('>= 8.1')] public function testBug12512(): void { @@ -500,14 +469,6 @@ public function testBug12512(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.0')] - public function testBug13218(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-13218.php'); - $this->assertNoErrors($errors); - } - public function testBug5529(): void { // crash @@ -602,16 +563,6 @@ public function testBug6253(): void $this->assertNoErrors($errors); } - public function testBug6442(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-6442.php'); - $this->assertCount(2, $errors); - $this->assertSame('Dumped type: \'Bug6442\\\B\'', $errors[0]->getMessage()); - $this->assertSame(9, $errors[0]->getLine()); - $this->assertSame('Dumped type: \'Bug6442\\\A\'', $errors[1]->getMessage()); - $this->assertSame(9, $errors[1]->getLine()); - } public function testBug13057(): void { @@ -723,10 +674,6 @@ public function testBug6940(): void $this->assertSame(12, $errors[0]->getLine()); } - - - - public function testBug4732(): void { // false positive @@ -846,14 +793,6 @@ public function testDiscussion7124(): void $this->assertSame(59, $errors[3]->getLine()); } - public function testBug7214(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-7214.php'); - $this->assertCount(1, $errors); - $this->assertSame('Method Bug7214\HelloWorld::getFoo() has no return type specified.', $errors[0]->getMessage()); - $this->assertSame(6, $errors[0]->getLine()); - } public function testBug12327(): void { @@ -981,13 +920,6 @@ public function testBug7554(): void } - public function testBug12671(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-12671.php'); - $this->assertNoErrors($errors); - } - public function testBug7737(): void { // false positive @@ -1023,9 +955,6 @@ public function testBug7320(): void $this->assertSame(13, $errors[0]->getLine()); } - - - public function testBug7918(): void { // crash @@ -1033,13 +962,6 @@ public function testBug7918(): void $this->assertNoErrors($errors); } - public function testBug7140(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-7140.php'); - $this->assertNoErrors($errors); - } - public function testArrayUnion(): void { $errors = $this->runAnalyse(__DIR__ . '/data/array-union.php'); @@ -1389,13 +1311,6 @@ public function testBug10086(): void $this->assertNoErrors($errors); } - public function testBug10147(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-10147.php'); - $this->assertNoErrors($errors); - } - #[RequiresPhp('>= 8.2')] public function testBug10302(): void { @@ -1422,13 +1337,6 @@ public function testBug10509(): void $this->assertSame('PHPDoc tag @return contains unresolvable type.', $errors[1]->getMessage()); } - public function testBug10538(): void - { - // infinite run - $errors = $this->runAnalyse(__DIR__ . '/data/bug-10538.php'); - $this->assertNoErrors($errors); - } - #[RequiresPhp('>= 8.1')] public function testBug10847(): void { diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index 4b2ee7f8554..704d950545c 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -5,8 +5,9 @@ use PhpBench\Attributes as Bench; #[Bench\Revs(revs: 1)] -#[Bench\Iterations(iterations: 3)] +#[Bench\Iterations(iterations: 5)] #[Bench\Warmup(revs: 1)] +#[Bench\RetryThreshold(retryThreshold: 5)] class RegressionBench extends AbstractBenchCase { @@ -171,4 +172,59 @@ public function benchBug14207And(): void $this->runAnalyse(__DIR__ . '/data/bug-14207-and.php'); } + public function benchBug3686(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-3686.php'); + } + + public function benchBug4300(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-4300.php'); + } + + public function benchBug5231(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-5231.php'); + } + + public function benchBug5231Two(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-5231_2.php'); + } + + public function benchBug6442(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-6442.php'); + } + + public function benchBug7140(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-7140.php'); + } + + public function benchBug7214(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-7214.php'); + } + + public function benchBug10147(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-10147.php'); + } + + public function benchBug10538(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-10538.php'); + } + + public function benchBug12671(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-12671.php'); + } + + public function benchBug13218(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-13218.php'); + } + } diff --git a/tests/PHPStan/Analyser/data/bug-10147.php b/tests/bench/data/bug-10147.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-10147.php rename to tests/bench/data/bug-10147.php diff --git a/tests/PHPStan/Analyser/data/bug-10538.php b/tests/bench/data/bug-10538.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-10538.php rename to tests/bench/data/bug-10538.php diff --git a/tests/PHPStan/Analyser/data/bug-12671.php b/tests/bench/data/bug-12671.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-12671.php rename to tests/bench/data/bug-12671.php diff --git a/tests/PHPStan/Analyser/data/bug-13218.php b/tests/bench/data/bug-13218.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-13218.php rename to tests/bench/data/bug-13218.php diff --git a/tests/PHPStan/Analyser/data/bug-3686.php b/tests/bench/data/bug-3686.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-3686.php rename to tests/bench/data/bug-3686.php diff --git a/tests/PHPStan/Analyser/data/bug-4300.php b/tests/bench/data/bug-4300.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-4300.php rename to tests/bench/data/bug-4300.php diff --git a/tests/PHPStan/Analyser/data/bug-5231.php b/tests/bench/data/bug-5231.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-5231.php rename to tests/bench/data/bug-5231.php diff --git a/tests/PHPStan/Analyser/data/bug-5231_2.php b/tests/bench/data/bug-5231_2.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-5231_2.php rename to tests/bench/data/bug-5231_2.php diff --git a/tests/PHPStan/Analyser/data/bug-6442.php b/tests/bench/data/bug-6442.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-6442.php rename to tests/bench/data/bug-6442.php diff --git a/tests/PHPStan/Analyser/data/bug-7140.php b/tests/bench/data/bug-7140.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-7140.php rename to tests/bench/data/bug-7140.php diff --git a/tests/PHPStan/Analyser/data/bug-7214.php b/tests/bench/data/bug-7214.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-7214.php rename to tests/bench/data/bug-7214.php From d92d73be0dc4b9fd37ffc9896a45eeb7f48b7114 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 07:38:22 +0100 Subject: [PATCH 11/30] Fix CS --- phpcs.xml | 3 ++- .../Analyser/AnalyserIntegrationTest.php | 26 ------------------- .../{AbstractBenchCase.php => BenchCase.php} | 6 ++--- tests/bench/RegressionBench.php | 2 +- 4 files changed, 5 insertions(+), 32 deletions(-) rename tests/bench/{AbstractBenchCase.php => BenchCase.php} (89%) diff --git a/phpcs.xml b/phpcs.xml index 3a6696fa3db..4d57743f555 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -53,7 +53,7 @@ src/Command/CommandHelper.php - src/Testing/PHPStanTestCase.php + src/Testing/PHPStanTestCaseTrait.php tests @@ -65,6 +65,7 @@ + diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 36d7ca6e58c..0635f12716e 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -240,7 +240,6 @@ public function testTwoSameClassesInSingleFile(): void $this->assertSame(36, $error->getLine()); } - public function testBug3405(): void { // crash @@ -279,7 +278,6 @@ public function testBug3379(): void $this->assertSame('Constant SOME_UNKNOWN_CONST not found.', $errors[0]->getMessage()); } - public function testBug3798(): void { // false positive @@ -563,7 +561,6 @@ public function testBug6253(): void $this->assertNoErrors($errors); } - public function testBug13057(): void { // crash @@ -793,7 +790,6 @@ public function testDiscussion7124(): void $this->assertSame(59, $errors[3]->getLine()); } - public function testBug12327(): void { // crash @@ -919,7 +915,6 @@ public function testBug7554(): void $this->assertSame(27, $errors[1]->getLine()); } - public function testBug7737(): void { // false positive @@ -968,7 +963,6 @@ public function testArrayUnion(): void $this->assertNoErrors($errors); } - public function testBug7963(): void { // false positive @@ -1077,7 +1071,6 @@ public function testAssertDocblock(): void $this->assertSame(238, $errors[3]->getLine()); } - #[RequiresPhp('>= 8.0')] public function testBug12934(): void { @@ -1098,8 +1091,6 @@ public function testPr2030(): void $this->assertNoErrors($errors); } - - #[RequiresPhp('>= 8.0')] public function testBug8537(): void { @@ -1118,9 +1109,6 @@ public function testBug7927(): void $this->assertSame('Enum case Bug7927\Test::Two does not have a value but the enum is backed with the "int" type.', $errors[1]->getMessage()); } - - - public static function getAdditionalConfigFiles(): array { return [ @@ -1240,7 +1228,6 @@ public function testBug9428(): void $this->assertNoErrors($errors); } - public function testIgnoreIdentifiers(): void { $errors = $this->runAnalyse(__DIR__ . '/data/ignore-identifiers.php'); @@ -1345,7 +1332,6 @@ public function testBug10847(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.1')] public function testBug10985(): void { @@ -1354,7 +1340,6 @@ public function testBug10985(): void $this->assertNoErrors($errors); } - public function testBug11026(): void { // crash @@ -1369,7 +1354,6 @@ public function testBug10867(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.0')] public function testBug11147(): void { @@ -1379,7 +1363,6 @@ public function testBug11147(): void $this->assertSame('Method Bug11147\RedisAdapter::createConnection() has invalid return type Bug11147\NonExistentClass.', $errors[0]->getMessage()); } - public function testBug11292(): void { // crash @@ -1387,7 +1370,6 @@ public function testBug11292(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.0')] public function testBug5597(): void { @@ -1434,7 +1416,6 @@ public function testBug11709(): void $this->assertNoErrors($errors); } - #[RequiresPhp('>= 8.3')] public function testBug12549(): void { @@ -1450,9 +1431,6 @@ public function testBug12627(): void $this->assertNoErrors($errors); } - - - #[RequiresPhp('>= 8.3')] public function testBug12949(): void { @@ -1486,7 +1464,6 @@ public function testBug13279(): void $this->assertSame('Parameter #2 $offset of function array_splice expects int, string given.', $errors[0]->getMessage()); } - public function testBug13714(): void { // crash @@ -1501,7 +1478,6 @@ public function testBug13714(): void $this->assertSame('Function Bug13714\array_find invoked with 2 parameters, 0 required.', $errors[6]->getMessage()); } - #[RequiresPhp('>= 8.4')] public function testBug13980(): void { @@ -1510,8 +1486,6 @@ public function testBug13980(): void $this->assertNoErrors($errors); } - - public function testBug13945(): void { // false positive diff --git a/tests/bench/AbstractBenchCase.php b/tests/bench/BenchCase.php similarity index 89% rename from tests/bench/AbstractBenchCase.php rename to tests/bench/BenchCase.php index f6ce5467a74..8f94d3bb89a 100644 --- a/tests/bench/AbstractBenchCase.php +++ b/tests/bench/BenchCase.php @@ -7,7 +7,7 @@ use PHPStan\Analyser\Error; use PHPStan\Testing\PHPStanTestCaseTrait; -abstract class AbstractBenchCase +abstract class BenchCase { use PHPStanTestCaseTrait; @@ -22,13 +22,11 @@ protected function runAnalyse(string $file, ?array $allAnalysedFiles = null): ar $analyser = self::getContainer()->getByType(Analyser::class); $finalizer = self::getContainer()->getByType(AnalyserResultFinalizer::class); - $errors = $finalizer->finalize( + return $finalizer->finalize( $analyser->analyse([$file], null, null, true, $allAnalysedFiles), false, true, )->getErrors(); - - return $errors; } } diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index 704d950545c..12f3c9b5ec0 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -8,7 +8,7 @@ #[Bench\Iterations(iterations: 5)] #[Bench\Warmup(revs: 1)] #[Bench\RetryThreshold(retryThreshold: 5)] -class RegressionBench extends AbstractBenchCase +class RegressionBench extends BenchCase { public function benchBug1388(): void From bc282bcd0afa474e76af0d4dbb0868f3d3eac71c Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 07:44:43 +0100 Subject: [PATCH 12/30] Move more tests --- .../Analyser/AnalyserIntegrationTest.php | 25 ------------------- tests/bench/RegressionBench.php | 15 +++++++++++ .../Analyser => bench}/data/bug-5390.php | 0 .../conditional-expression-infinite-loop.php | 0 .../process-called-method-infinite-loop.php | 0 5 files changed, 15 insertions(+), 25 deletions(-) rename tests/{PHPStan/Analyser => bench}/data/bug-5390.php (100%) rename tests/{PHPStan/Analyser => bench}/data/conditional-expression-infinite-loop.php (100%) rename tests/{PHPStan/Analyser => bench}/data/process-called-method-infinite-loop.php (100%) diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 0635f12716e..c74a1c3ff59 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1027,19 +1027,6 @@ public function testBug5312(): void $this->assertSame(13, $errors[4]->getLine()); } - public function testBug5390(): void - { - // crash - $errors = $this->runAnalyse(__DIR__ . '/data/bug-5390.php'); - $this->assertCount(3, $errors); - $this->assertSame('Property Bug5390\A::$b is never written, only read.', $errors[0]->getMessage()); - $this->assertSame(9, $errors[0]->getLine()); - $this->assertSame('Method Bug5390\A::infiniteRecursion() has no return type specified.', $errors[1]->getMessage()); - $this->assertSame(11, $errors[1]->getLine()); - $this->assertSame('Call to an undefined method Bug5390\B::someMethod().', $errors[2]->getMessage()); - $this->assertSame(12, $errors[2]->getLine()); - } - public function testBug7110(): void { // false positive @@ -1079,12 +1066,6 @@ public function testBug12934(): void $this->assertNoErrors($errors); } - public function testConditionalExpressionInfiniteLoop(): void - { - $errors = $this->runAnalyse(__DIR__ . '/data/conditional-expression-infinite-loop.php'); - $this->assertNoErrors($errors); - } - public function testPr2030(): void { $errors = $this->runAnalyse(__DIR__ . '/data/pr-2030.php'); @@ -1214,12 +1195,6 @@ public function testBug13492(): void $this->assertNoErrors($errors); } - public function testProcessCalledMethodInfiniteLoop(): void - { - $errors = $this->runAnalyse(__DIR__ . '/data/process-called-method-infinite-loop.php'); - $this->assertNoErrors($errors); - } - #[RequiresPhp('>= 8.0')] public function testBug9428(): void { diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index 12f3c9b5ec0..53a2149f7a0 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -227,4 +227,19 @@ public function benchBug13218(): void $this->runAnalyse(__DIR__ . '/data/bug-13218.php'); } + public function benchConditionalExpressionInfiniteLoop(): void + { + $this->runAnalyse(__DIR__ . '/data/conditional-expression-infinite-loop.php'); + } + + public function benchProcessCalledMethodInfiniteLoop(): void + { + $this->runAnalyse(__DIR__ . '/data/process-called-method-infinite-loop.php'); + } + + public function benchBug5390(): void + { + $this->runAnalyse(__DIR__ . '/data/bug-5390.php'); + } + } diff --git a/tests/PHPStan/Analyser/data/bug-5390.php b/tests/bench/data/bug-5390.php similarity index 100% rename from tests/PHPStan/Analyser/data/bug-5390.php rename to tests/bench/data/bug-5390.php diff --git a/tests/PHPStan/Analyser/data/conditional-expression-infinite-loop.php b/tests/bench/data/conditional-expression-infinite-loop.php similarity index 100% rename from tests/PHPStan/Analyser/data/conditional-expression-infinite-loop.php rename to tests/bench/data/conditional-expression-infinite-loop.php diff --git a/tests/PHPStan/Analyser/data/process-called-method-infinite-loop.php b/tests/bench/data/process-called-method-infinite-loop.php similarity index 100% rename from tests/PHPStan/Analyser/data/process-called-method-infinite-loop.php rename to tests/bench/data/process-called-method-infinite-loop.php From e4155d5efebc6c375a0cad1d4f231d32ab9df54a Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:03:52 +0100 Subject: [PATCH 13/30] Higher RetryThreshold because of CI --- tests/bench/RegressionBench.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index 53a2149f7a0..c6ea11e50c1 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -7,7 +7,7 @@ #[Bench\Revs(revs: 1)] #[Bench\Iterations(iterations: 5)] #[Bench\Warmup(revs: 1)] -#[Bench\RetryThreshold(retryThreshold: 5)] +#[Bench\RetryThreshold(retryThreshold: 10.0)] class RegressionBench extends BenchCase { From 77838bfd8cad6f0c884a7a46cec442521ea9b676 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:18:03 +0100 Subject: [PATCH 14/30] Bench CI workflow --- .github/workflows/bench.yml | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .github/workflows/bench.yml diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml new file mode 100644 index 00000000000..6afc8c85b29 --- /dev/null +++ b/.github/workflows/bench.yml @@ -0,0 +1,86 @@ +name: "Benchmark" + +on: + pull_request: + paths-ignore: + - 'compiler/**' + - 'apigen/**' + - 'changelog-generator/**' + - 'issue-bot/**' + push: + branches: + - "2.1.x" + paths-ignore: + - 'compiler/**' + - 'apigen/**' + - 'changelog-generator/**' + - 'issue-bot/**' + +concurrency: + group: bench-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + baseline: + name: "Baseline" + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 + with: + egress-policy: audit + + - name: "Checkout base branch" + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + + - name: "Install PHP" + uses: "shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1" # v2 + with: + coverage: "none" + php-version: "8.5" + tools: pecl + extensions: ds,mbstring + ini-file: development + ini-values: memory_limit=-1 + + - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 + + - name: "Run phpbench baseline" + run: "vendor/bin/phpbench run --dump-file=tests/bench/storage/baseline.xml --tag=baseline" + + - name: "Upload baseline artifact" + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: phpbench-baseline + path: tests/bench/storage/baseline.xml + + test: + name: "Test" + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 + with: + egress-policy: audit + + - name: "Checkout" + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + + - name: "Install PHP" + uses: "shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1" # v2 + with: + coverage: "none" + php-version: "8.5" + tools: pecl + extensions: ds,mbstring + ini-file: development + ini-values: memory_limit=-1 + + - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 + + - name: "Run phpbench test" + run: "vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --ref=baseline --report=aggregate --assert=\"variant.mode <= baseline.mode +/- 5%\"" From 02f1a86314d14ce3f08e1f406bab4511c57f455a Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:27:17 +0100 Subject: [PATCH 15/30] Fix PHPStan --- phpstan-baseline.neon | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index b75b62a8b80..479566a2892 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1867,8 +1867,7 @@ parameters: rawMessage: Anonymous function has an unused use $container. identifier: closure.unusedUse count: 1 - path: tests/bench/AbstractBenchCase.php - + path: tests/bench/BenchCase.php - rawMessage: Constant SOME_CONSTANT_IN_AUTOLOAD_FILE not found. From 70788c82b07bed3bd7c7b482bb6047e7ef6fe732 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:34:33 +0100 Subject: [PATCH 16/30] Fix workflow --- .github/workflows/bench.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 6afc8c85b29..54986152995 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -83,4 +83,4 @@ jobs: - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 - name: "Run phpbench test" - run: "vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --ref=baseline --report=aggregate --assert=\"variant.mode <= baseline.mode +/- 5%\"" + run: "vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --ref=baseline --report=aggregate --assert=\"mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%\"" From 5fb14ada34b4d3c048e3834b551d23efe2f73df8 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:36:26 +0100 Subject: [PATCH 17/30] Upload my baseline temporarily --- tests/bench/storage/baseline.xml | 776 +++++++++++++++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 tests/bench/storage/baseline.xml diff --git a/tests/bench/storage/baseline.xml b/tests/bench/storage/baseline.xml new file mode 100644 index 00000000000..dadca2f51fb --- /dev/null +++ b/tests/bench/storage/baseline.xml @@ -0,0 +1,776 @@ + + + + + + Darwin + Ondrejs-MacBook-Pro.local + 25.3.0 + Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:15 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T6000 + arm64 + + + + 8.5.3 + /opt/homebrew/etc/php/8.5/php.ini + Core, date, lexbor, openssl, pcre, sqlite3, zlib, bcmath, bz2, calendar, ctype, curl, dba, uri, json, mbstring, SPL, FFI, fileinfo, filter, ftp, gd, gettext, gmp, hash, iconv, intl, session, ldap, standard, libxml, mysqlnd, mysqli, odbc, Zend OPcache, pcntl, PDO, pdo_dblib, pdo_mysql, PDO_ODBC, pdo_pgsql, pdo_sqlite, pgsql, Phar, posix, random, readline, Reflection, exif, shmop, SimpleXML, snmp, soap, sockets, sodium, sysvmsg, sysvsem, sysvshm, tidy, tokenizer, dom, xml, xmlreader, xmlwriter, xsl, zip + + + 1 + 1 + + + git + claude/add-test-comments-1vopL + 0b0fdda05ce4304e30ab799bbba5a680d971f78b + + + 0.072956085205078 + 0.23818016052246 + 3.4120082855225 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From cd74f0dc939850f797c0097f2e5bafa9dc59c2f1 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:41:15 +0100 Subject: [PATCH 18/30] Move phpbench --- .github/workflows/bench.yml | 10 +- composer.json | 1 - composer.lock | 662 +------------------------------- tests/composer.json | 3 +- tests/composer.lock | 727 +++++++++++++++++++++++++++++++++++- 5 files changed, 738 insertions(+), 665 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 54986152995..ad7670cf4b7 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -46,9 +46,12 @@ jobs: ini-values: memory_limit=-1 - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 + - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 + with: + working-directory: "tests/" - name: "Run phpbench baseline" - run: "vendor/bin/phpbench run --dump-file=tests/bench/storage/baseline.xml --tag=baseline" + run: "tests/vendor/bin/phpbench run --dump-file=tests/bench/storage/baseline.xml --tag=baseline" - name: "Upload baseline artifact" uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 @@ -81,6 +84,9 @@ jobs: ini-values: memory_limit=-1 - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 + - uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # v3 + with: + working-directory: "tests/" - name: "Run phpbench test" - run: "vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --ref=baseline --report=aggregate --assert=\"mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%\"" + run: "tests/vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --ref=baseline --report=aggregate --assert=\"mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%\"" diff --git a/composer.json b/composer.json index 0b5c09cab80..f9e58c76daa 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,6 @@ "require-dev": { "cweagans/composer-patches": "^1.7.3", "php-parallel-lint/php-parallel-lint": "^1.2.0", - "phpbench/phpbench": "^1.2", "phpstan/phpstan-deprecation-rules": "^2.0.2", "phpstan/phpstan-nette": "^2.0", "phpstan/phpstan-phpunit": "^2.0.8", diff --git a/composer.lock b/composer.lock index 385a9163aa1..8bbcf4ef465 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": "4563800d2571a09790e7d441c9472235", + "content-hash": "cbd96eba477c2f5a8a05a575aea7522d", "packages": [ { "name": "clue/ndjson-react", @@ -4614,160 +4614,6 @@ }, "time": "2022-12-20T22:53:13+00:00" }, - { - "name": "doctrine/annotations", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", - "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^2 || ^3", - "ext-tokenizer": "*", - "php": "^7.2 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^2.0", - "doctrine/coding-standard": "^10", - "phpstan/phpstan": "^1.10.28", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^5.4 || ^6.4 || ^7", - "vimeo/psalm": "^4.30 || ^5.14" - }, - "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/2.0.2" - }, - "abandoned": true, - "time": "2024-09-05T10:17:24+00:00" - }, - { - "name": "doctrine/lexer", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10.5", - "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^5.21" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/3.0.1" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], - "time": "2024-02-05T11:56:58+00:00" - }, { "name": "myclabs/deep-copy", "version": "1.13.4", @@ -5007,207 +4853,6 @@ }, "time": "2024-03-27T12:14:49+00:00" }, - { - "name": "phpbench/container", - "version": "2.2.3", - "source": { - "type": "git", - "url": "https://github.com/phpbench/container.git", - "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", - "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", - "shasum": "" - }, - "require": { - "psr/container": "^1.0|^2.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" - }, - "require-dev": { - "php-cs-fixer/shim": "^3.89", - "phpstan/phpstan": "^0.12.52", - "phpunit/phpunit": "^8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "PhpBench\\DependencyInjection\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Leech", - "email": "daniel@dantleech.com" - } - ], - "description": "Simple, configurable, service container.", - "support": { - "issues": "https://github.com/phpbench/container/issues", - "source": "https://github.com/phpbench/container/tree/2.2.3" - }, - "time": "2025-11-06T09:05:13+00:00" - }, - { - "name": "phpbench/dom", - "version": "0.3.3", - "source": { - "type": "git", - "url": "https://github.com/phpbench/dom.git", - "reference": "786a96db538d0def931f5b19225233ec42ec7a72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbench/dom/zipball/786a96db538d0def931f5b19225233ec42ec7a72", - "reference": "786a96db538d0def931f5b19225233ec42ec7a72", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": "^7.3||^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.14", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.0||^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpBench\\Dom\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Leech", - "email": "daniel@dantleech.com" - } - ], - "description": "DOM wrapper to simplify working with the PHP DOM implementation", - "support": { - "issues": "https://github.com/phpbench/dom/issues", - "source": "https://github.com/phpbench/dom/tree/0.3.3" - }, - "abandoned": true, - "time": "2023-03-06T23:46:57+00:00" - }, - { - "name": "phpbench/phpbench", - "version": "1.2.15", - "source": { - "type": "git", - "url": "https://github.com/phpbench/phpbench.git", - "reference": "f7000319695cfad04a57fc64bf7ef7abdf4c437c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/f7000319695cfad04a57fc64bf7ef7abdf4c437c", - "reference": "f7000319695cfad04a57fc64bf7ef7abdf4c437c", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^2.0", - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "ext-tokenizer": "*", - "php": "^8.1", - "phpbench/container": "^2.1", - "phpbench/dom": "~0.3.3", - "psr/log": "^1.1 || ^2.0 || ^3.0", - "seld/jsonlint": "^1.1", - "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/filesystem": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/finder": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/process": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "webmozart/glob": "^4.6" - }, - "require-dev": { - "dantleech/invoke": "^2.0", - "friendsofphp/php-cs-fixer": "^3.0", - "jangregor/phpstan-prophecy": "^1.0", - "phpspec/prophecy": "dev-master", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^10.0", - "rector/rector": "^0.18.10", - "symfony/error-handler": "^5.2 || ^6.0 || ^7.0", - "symfony/var-dumper": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "ext-xdebug": "For Xdebug profiling extension." - }, - "bin": [ - "bin/phpbench" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "files": [ - "lib/Report/Func/functions.php" - ], - "psr-4": { - "PhpBench\\": "lib/", - "PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Leech", - "email": "daniel@dantleech.com" - } - ], - "description": "PHP Benchmarking Framework", - "keywords": [ - "benchmarking", - "optimization", - "performance", - "profiling", - "testing" - ], - "support": { - "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.2.15" - }, - "funding": [ - { - "url": "https://github.com/dantleech", - "type": "github" - } - ], - "time": "2023-11-29T12:21:11+00:00" - }, { "name": "phpstan/phpstan-deprecation-rules", "version": "2.0.4", @@ -5884,55 +5529,6 @@ ], "time": "2026-02-08T07:05:14+00:00" }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, { "name": "sebastian/cli-parser", "version": "3.0.2", @@ -6852,70 +6448,6 @@ ], "time": "2024-10-09T05:16:32+00:00" }, - { - "name": "seld/jsonlint", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", - "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", - "shasum": "" - }, - "require": { - "php": "^5.3 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" - }, - "bin": [ - "bin/jsonlint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Seld\\JsonLint\\": "src/Seld/JsonLint/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "https://seld.be" - } - ], - "description": "JSON Linter", - "keywords": [ - "json", - "linter", - "parser", - "validator" - ], - "support": { - "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" - }, - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", - "type": "tidelift" - } - ], - "time": "2024-07-11T14:55:45+00:00" - }, { "name": "shipmonk/composer-dependency-analyser", "version": "1.7.0", @@ -7171,147 +6703,6 @@ ], "time": "2024-10-20T05:08:20+00:00" }, - { - "name": "symfony/filesystem", - "version": "v7.4.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", - "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" - }, - "require-dev": { - "symfony/process": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.6" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-02-25T16:50:00+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v7.4.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "b38026df55197f9e39a44f3215788edf83187b80" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", - "reference": "b38026df55197f9e39a44f3215788edf83187b80", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-11-12T15:39:26+00:00" - }, { "name": "theseer/tokenizer", "version": "1.3.1", @@ -7361,55 +6752,6 @@ } ], "time": "2025-11-17T20:03:58+00:00" - }, - { - "name": "webmozart/glob", - "version": "4.7.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/glob.git", - "reference": "8a2842112d6916e61e0e15e316465b611f3abc17" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17", - "reference": "8a2842112d6916e61e0e15e316465b611f3abc17", - "shasum": "" - }, - "require": { - "php": "^7.3 || ^8.0.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.5", - "symfony/filesystem": "^5.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.1-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Glob\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "A PHP implementation of Ant's glob.", - "support": { - "issues": "https://github.com/webmozarts/glob/issues", - "source": "https://github.com/webmozarts/glob/tree/4.7.0" - }, - "time": "2024-03-07T20:33:40+00:00" } ], "aliases": [], @@ -7427,5 +6769,5 @@ "platform-overrides": { "php": "8.2.99" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/tests/composer.json b/tests/composer.json index aaad8c1afd1..46b7fefdb4e 100644 --- a/tests/composer.json +++ b/tests/composer.json @@ -2,7 +2,8 @@ "name": "phpstan/phpstan-src-tests", "require-dev": { "phpunit/phpunit": "^11.5.23", - "brianium/paratest": "^7.8.3" + "brianium/paratest": "^7.8.3", + "phpbench/phpbench": "^1.5" }, "config": { "platform": { diff --git a/tests/composer.lock b/tests/composer.lock index d372ba0a81f..11535d0d88b 100644 --- a/tests/composer.lock +++ b/tests/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": "868be8e811ed8ef2531495ab93a0d835", + "content-hash": "806842328c3aeb6bc6f75007f410ebe6", "packages": [], "packages-dev": [ { @@ -100,6 +100,160 @@ ], "time": "2026-01-08T08:02:38+00:00" }, + { + "name": "doctrine/annotations", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2 || ^3", + "ext-tokenizer": "*", + "php": "^7.2 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^2.0", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.10.28", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^5.4 || ^6.4 || ^7", + "vimeo/psalm": "^4.30 || ^5.14" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/2.0.2" + }, + "abandoned": true, + "time": "2024-09-05T10:17:24+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, { "name": "fidry/cpu-core-counter", "version": "1.3.0", @@ -457,6 +611,156 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpbench/container", + "version": "2.2.3", + "source": { + "type": "git", + "url": "https://github.com/phpbench/container.git", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", + "shasum": "" + }, + "require": { + "psr/container": "^1.0|^2.0", + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" + }, + "require-dev": { + "php-cs-fixer/shim": "^3.89", + "phpstan/phpstan": "^0.12.52", + "phpunit/phpunit": "^8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpBench\\DependencyInjection\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Leech", + "email": "daniel@dantleech.com" + } + ], + "description": "Simple, configurable, service container.", + "support": { + "issues": "https://github.com/phpbench/container/issues", + "source": "https://github.com/phpbench/container/tree/2.2.3" + }, + "time": "2025-11-06T09:05:13+00:00" + }, + { + "name": "phpbench/phpbench", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/phpbench/phpbench.git", + "reference": "9a28fd0833f11171b949843c6fd663eb69b6d14c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/9a28fd0833f11171b949843c6fd663eb69b6d14c", + "reference": "9a28fd0833f11171b949843c6fd663eb69b6d14c", + "shasum": "" + }, + "require": { + "doctrine/annotations": "^2.0", + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "ext-tokenizer": "*", + "php": "^8.2", + "phpbench/container": "^2.2", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "seld/jsonlint": "^1.1", + "symfony/console": "^6.1 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.1 || ^7.0 || ^8.0", + "symfony/finder": "^6.1 || ^7.0 || ^8.0", + "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0", + "symfony/process": "^6.1 || ^7.0 || ^8.0", + "webmozart/glob": "^4.6" + }, + "require-dev": { + "dantleech/invoke": "^2.0", + "ergebnis/composer-normalize": "^2.39", + "jangregor/phpstan-prophecy": "^1.0", + "php-cs-fixer/shim": "^3.9", + "phpspec/prophecy": "^1.22", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^11.5", + "rector/rector": "^1.2", + "sebastian/exporter": "^6.3.2", + "symfony/error-handler": "^6.1 || ^7.0 || ^8.0", + "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0" + }, + "suggest": { + "ext-xdebug": "For Xdebug profiling extension." + }, + "bin": [ + "bin/phpbench" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "files": [ + "lib/Report/Func/functions.php" + ], + "psr-4": { + "PhpBench\\": "lib/", + "PhpBench\\Extensions\\XDebug\\": "extensions/xdebug/lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Leech", + "email": "daniel@dantleech.com" + } + ], + "description": "PHP Benchmarking Framework", + "keywords": [ + "benchmarking", + "optimization", + "performance", + "profiling", + "testing" + ], + "support": { + "issues": "https://github.com/phpbench/phpbench/issues", + "source": "https://github.com/phpbench/phpbench/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/dantleech", + "type": "github" + } + ], + "time": "2026-03-05T08:18:58+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "11.0.12", @@ -914,6 +1218,55 @@ ], "time": "2026-02-08T07:05:14+00:00" }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, { "name": "psr/container", "version": "2.0.2", @@ -967,6 +1320,56 @@ }, "time": "2021-11-05T16:47:00+00:00" }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, { "name": "sebastian/cli-parser", "version": "3.0.2", @@ -1953,6 +2356,70 @@ ], "time": "2024-10-09T05:16:32+00:00" }, + { + "name": "seld/jsonlint", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2024-07-11T14:55:45+00:00" + }, { "name": "staabm/side-effects-detector", "version": "1.0.5", @@ -2170,6 +2637,215 @@ ], "time": "2024-09-25T14:21:43+00:00" }, + { + "name": "symfony/filesystem", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T16:50:00+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-29T09:40:50+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "b38026df55197f9e39a44f3215788edf83187b80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", + "reference": "b38026df55197f9e39a44f3215788edf83187b80", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-11-12T15:39:26+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.33.0", @@ -2797,6 +3473,55 @@ } ], "time": "2025-11-17T20:03:58+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.7.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/glob.git", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "symfony/filesystem": "^5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "support": { + "issues": "https://github.com/webmozarts/glob/issues", + "source": "https://github.com/webmozarts/glob/tree/4.7.0" + }, + "time": "2024-03-07T20:33:40+00:00" } ], "aliases": [], From 50b0f2f0a0acbde5da2ee4ae399d8e3783f567fa Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:46:29 +0100 Subject: [PATCH 19/30] baseline.xml from GitHub Actions --- tests/bench/storage/baseline.xml | 586 ++++++++++++++++--------------- 1 file changed, 295 insertions(+), 291 deletions(-) diff --git a/tests/bench/storage/baseline.xml b/tests/bench/storage/baseline.xml index dadca2f51fb..80a4bef5875 100644 --- a/tests/bench/storage/baseline.xml +++ b/tests/bench/storage/baseline.xml @@ -1,33 +1,38 @@ - + - Darwin - Ondrejs-MacBook-Pro.local - 25.3.0 - Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:15 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T6000 - arm64 + Linux + runnervm0kj6c + 6.14.0-1017-azure + #17~24.04.1-Ubuntu SMP Mon Dec 1 20:10:50 UTC 2025 + x86_64 8.5.3 - /opt/homebrew/etc/php/8.5/php.ini - Core, date, lexbor, openssl, pcre, sqlite3, zlib, bcmath, bz2, calendar, ctype, curl, dba, uri, json, mbstring, SPL, FFI, fileinfo, filter, ftp, gd, gettext, gmp, hash, iconv, intl, session, ldap, standard, libxml, mysqlnd, mysqli, odbc, Zend OPcache, pcntl, PDO, pdo_dblib, pdo_mysql, PDO_ODBC, pdo_pgsql, pdo_sqlite, pgsql, Phar, posix, random, readline, Reflection, exif, shmop, SimpleXML, snmp, soap, sockets, sodium, sysvmsg, sysvsem, sysvshm, tidy, tokenizer, dom, xml, xmlreader, xmlwriter, xsl, zip + /etc/php/8.5/cli/php.ini + Core, date, lexbor, openssl, pcre, zlib, filter, hash, json, uri, Zend OPcache, pcntl, random, Reflection, SPL, session, standard, sodium, libxml, mysqlnd, PDO, xml, apcu, ast, bcmath, bz2, calendar, ctype, curl, dba, dom, enchant, mbstring, FFI, fileinfo, ftp, gd, gettext, gmp, iconv, igbinary, imagick, imap, intl, ldap, exif, memcache, mongodb, msgpack, mysqli, odbc, pdo_dblib, PDO_Firebird, pdo_mysql, PDO_ODBC, pdo_pgsql, pdo_sqlite, pdo_sqlsrv, pgsql, Phar, posix, readline, shmop, SimpleXML, snmp, soap, sockets, sqlite3, sqlsrv, sysvmsg, sysvsem, sysvshm, tidy, tokenizer, xmlreader, xmlwriter, xsl, yaml, zip, zmq, memcached, redis, ds 1 - 1 + + + 0.6982421875 + 0.21142578125 + 0.07373046875 + git - claude/add-test-comments-1vopL - 0b0fdda05ce4304e30ab799bbba5a680d971f78b + (unnamed branch) + - 0.072956085205078 - 0.23818016052246 - 3.4120082855225 + 0.0059604644775391 + 0.14901161193848 + 1.6880035400391 @@ -39,12 +44,12 @@ - - - - - - + + + + + + @@ -55,12 +60,12 @@ - - - - - - + + + + + + @@ -71,12 +76,12 @@ - - - - - - + + + + + + @@ -87,12 +92,12 @@ - - - - - - + + + + + + @@ -103,12 +108,12 @@ - - - - - - + + + + + + @@ -119,12 +124,12 @@ - - - - - - + + + + + + @@ -135,12 +140,12 @@ - - - - - - + + + + + + @@ -151,12 +156,12 @@ - - - - - - + + + + + + @@ -167,12 +172,12 @@ - - - - - - + + + + + + @@ -183,12 +188,12 @@ - - - - - - + + + + + + @@ -199,12 +204,12 @@ - - - - - - + + + + + + @@ -215,12 +220,12 @@ - - - - - - + + + + + + @@ -231,12 +236,12 @@ - - - - - - + + + + + + @@ -247,12 +252,12 @@ - - - - - - + + + + + + @@ -263,12 +268,12 @@ - - - - - - + + + + + + @@ -279,12 +284,12 @@ - - - - - - + + + + + + @@ -295,12 +300,12 @@ - - - - - - + + + + + + @@ -311,12 +316,12 @@ - - - - - - + + + + + + @@ -327,12 +332,12 @@ - - - - - - + + + + + + @@ -343,12 +348,12 @@ - - - - - - + + + + + + @@ -359,12 +364,12 @@ - - - - - - + + + + + + @@ -375,12 +380,12 @@ - - - - - - + + + + + + @@ -391,12 +396,12 @@ - - - - - - + + + + + + @@ -407,12 +412,12 @@ - - - - - - + + + + + + @@ -423,12 +428,12 @@ - - - - - - + + + + + + @@ -439,12 +444,12 @@ - - - - - - + + + + + + @@ -455,12 +460,12 @@ - - - - - - + + + + + + @@ -471,12 +476,12 @@ - - - - - - + + + + + + @@ -487,12 +492,12 @@ - - - - - - + + + + + + @@ -503,12 +508,12 @@ - - - - - - + + + + + + @@ -519,12 +524,12 @@ - - - - - - + + + + + + @@ -535,12 +540,12 @@ - - - - - - + + + + + + @@ -551,12 +556,12 @@ - - - - - - + + + + + + @@ -567,12 +572,12 @@ - - - - - - + + + + + + @@ -583,12 +588,12 @@ - - - - - - + + + + + + @@ -599,12 +604,12 @@ - - - - - - + + + + + + @@ -615,12 +620,12 @@ - - - - - - + + + + + + @@ -631,12 +636,12 @@ - - - - - - + + + + + + @@ -647,12 +652,12 @@ - - - - - - + + + + + + @@ -663,12 +668,12 @@ - - - - - - + + + + + + @@ -679,12 +684,12 @@ - - - - - - + + + + + + @@ -695,12 +700,12 @@ - - - - - - + + + + + + @@ -711,12 +716,12 @@ - - - - - - + + + + + + @@ -727,12 +732,12 @@ - - - - - - + + + + + + @@ -743,12 +748,12 @@ - - - - - - + + + + + + @@ -759,18 +764,17 @@ - - - - - - + + + + + + - From 081f445dd7a6681419138c1f7b7e335a3bd3ffec Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 08:57:19 +0100 Subject: [PATCH 20/30] Fix workflow --- .github/workflows/bench.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index ad7670cf4b7..d6b887f2a4e 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -51,7 +51,7 @@ jobs: working-directory: "tests/" - name: "Run phpbench baseline" - run: "tests/vendor/bin/phpbench run --dump-file=tests/bench/storage/baseline.xml --tag=baseline" + run: "tests/vendor/bin/phpbench run --dump-file=tests/bench/storage/baseline.xml" - name: "Upload baseline artifact" uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 @@ -89,4 +89,4 @@ jobs: working-directory: "tests/" - name: "Run phpbench test" - run: "tests/vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --ref=baseline --report=aggregate --assert=\"mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%\"" + run: "tests/vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --report=aggregate --assert=\"mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%\"" From 1be0d93f8e1c600677f04573e4eb32e759c1dc8a Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:12:54 +0100 Subject: [PATCH 21/30] Sophisticated assertion --- .github/workflows/bench.yml | 2 +- tests/bench/RegressionBench.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index d6b887f2a4e..cab8bd89033 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -89,4 +89,4 @@ jobs: working-directory: "tests/" - name: "Run phpbench test" - run: "tests/vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --report=aggregate --assert=\"mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%\"" + run: "tests/vendor/bin/phpbench run --file=tests/bench/storage/baseline.xml --report=aggregate" diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index c6ea11e50c1..8e4273863b7 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -8,6 +8,10 @@ #[Bench\Iterations(iterations: 5)] #[Bench\Warmup(revs: 1)] #[Bench\RetryThreshold(retryThreshold: 10.0)] +#[Bench\Assert(expression: ' + (mode(baseline.time.avg) < 50 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 25%) + or (mode(baseline.time.avg) >= 50 milliseconds and mode(baseline.time.avg) < 500 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%) + or (mode(baseline.time.avg) >= 500 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 5%)')] class RegressionBench extends BenchCase { From 00f0ba7cbc85c58e9d1ff59e7fb1c18e320b0a44 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:14:50 +0100 Subject: [PATCH 22/30] Fix workflow --- .github/workflows/bench.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index cab8bd89033..8f359728b50 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -20,6 +20,9 @@ concurrency: group: bench-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: baseline: name: "Baseline" From e8787d0a94d192e068c6e941f62db2103ef6cd18 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:26:09 +0100 Subject: [PATCH 23/30] Use ParamProviders --- tests/bench/RegressionBench.php | 242 +++----------------------------- 1 file changed, 21 insertions(+), 221 deletions(-) diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index 8e4273863b7..f480c131a98 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -3,6 +3,7 @@ namespace PHPStan\Benchmark; use PhpBench\Attributes as Bench; +use Symfony\Component\Finder\Finder; #[Bench\Revs(revs: 1)] #[Bench\Iterations(iterations: 5)] @@ -15,235 +16,34 @@ class RegressionBench extends BenchCase { - public function benchBug1388(): void + /** + * @param array{string} $params + */ + #[Bench\ParamProviders(['provideFiles'])] + public function benchRunAnalyse(array $params): void { - $this->runAnalyse(__DIR__ . '/data/bug-1388.php'); + $this->runAnalyse($params[0]); } - public function benchBug1447(): void + /** + * @return iterable + */ + public function provideFiles(): iterable { - $this->runAnalyse(__DIR__ . '/data/bug-1447.php'); + yield from self::findTestDataFilesFromDirectory(__DIR__ . '/data'); } - public function benchBug4308(): void + private static function findTestDataFilesFromDirectory(string $directory): array { - $this->runAnalyse(__DIR__ . '/data/bug-4308.php'); - } - - public function benchBug5081(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-5081.php'); - } - - public function benchBug6265(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-6265.php'); - } - - public function benchBug6936(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-6936.php'); - } - - public function benchBug6948(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-6948.php'); - } - - public function benchBug7581(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-7581.php'); - } - - public function benchBug7637(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-7637.php'); - } - - public function benchBug7901(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-7901.php'); - } - - public function benchBug7903(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-7903.php'); - } - - public function benchBug8146(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-8146b.php'); - } - - public function benchBug8146a(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-8146a.php'); - } - - public function benchBug8147(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-8147.php'); - } - - public function benchBug8215(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-8215.php'); - } - - public function benchBug8503(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-8503.php'); - } - - public function benchBug9690(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-9690.php'); - } - - public function benchBug10772(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-10772.php'); - } - - public function benchBug10979(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-10979.php'); - } - - public function benchBug11263(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-11263.php'); - } - - public function benchBug11283(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-11283.php'); - } - - public function benchBug11297(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-11297.php'); - } - - public function benchBug11913(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-11913.php'); - } - - public function benchBug12159(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-12159.php'); - } + $finder = new Finder(); + $finder->followLinks(); + $finder->sortByName(true); + $files = []; + foreach ($finder->files()->name('*.php')->in($directory) as $fileInfo) { + $files[$fileInfo->getBasename()] = [$fileInfo->getPathname()]; + } - public function benchBug12787(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-12787.php'); - } - - public function benchBug12800(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-12800.php'); - } - - public function benchBug13310(): void - { - require_once __DIR__ . '/data/bug-13310.php'; - $this->runAnalyse(__DIR__ . '/data/bug-13310.php'); - } - - public function benchBug13352(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-13352.php'); - } - - public function benchBug13685(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-13685.php'); - } - - public function benchBug13933(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-13933.php'); - } - - public function benchBug14207(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-14207.php'); - } - - public function benchBug14207And(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-14207-and.php'); - } - - public function benchBug3686(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-3686.php'); - } - - public function benchBug4300(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-4300.php'); - } - - public function benchBug5231(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-5231.php'); - } - - public function benchBug5231Two(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-5231_2.php'); - } - - public function benchBug6442(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-6442.php'); - } - - public function benchBug7140(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-7140.php'); - } - - public function benchBug7214(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-7214.php'); - } - - public function benchBug10147(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-10147.php'); - } - - public function benchBug10538(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-10538.php'); - } - - public function benchBug12671(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-12671.php'); - } - - public function benchBug13218(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-13218.php'); - } - - public function benchConditionalExpressionInfiniteLoop(): void - { - $this->runAnalyse(__DIR__ . '/data/conditional-expression-infinite-loop.php'); - } - - public function benchProcessCalledMethodInfiniteLoop(): void - { - $this->runAnalyse(__DIR__ . '/data/process-called-method-infinite-loop.php'); - } - - public function benchBug5390(): void - { - $this->runAnalyse(__DIR__ . '/data/bug-5390.php'); + return $files; } } From 2cb623ac7aa0aaeadcf8cf2e28799020029225d9 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:32:43 +0100 Subject: [PATCH 24/30] Fix tests workflow --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 80474700d47..bdd01803733 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -259,7 +259,7 @@ jobs: - name: "Downgrade PHPUnit with Paratest" shell: bash - run: "composer require --dev phpunit/phpunit:^9.6 brianium/paratest:^6.5 symfony/console:^5.4 symfony/process:^5.4 doctrine/instantiator:^1.0 --update-with-dependencies --ignore-platform-reqs --working-dir=tests" + run: "composer require --dev phpbench/phpbench:^1.2.15 phpunit/phpunit:^9.6 brianium/paratest:^6.5 symfony/console:^5.4 symfony/process:^5.4 doctrine/instantiator:^1.0 --update-with-dependencies --ignore-platform-reqs --working-dir=tests" - uses: ./.github/actions/downgrade-code with: From 2e011a5b4de4eb4ed7e10084fef8bad93aef3740 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:33:54 +0100 Subject: [PATCH 25/30] Do not analyse benches --- build/phpstan.neon | 1 + 1 file changed, 1 insertion(+) diff --git a/build/phpstan.neon b/build/phpstan.neon index 3469b8fca5a..526f68798d2 100644 --- a/build/phpstan.neon +++ b/build/phpstan.neon @@ -31,6 +31,7 @@ parameters: - ../tests/PHPStan/Analyser/nsrt/* - ../tests/PHPStan/Analyser/traits/* - ../tests/notAutoloaded/* + - ../tests/bench/* - ../tests/PHPStan/Reflection/UnionTypesTest.php - ../tests/PHPStan/Reflection/MixedTypeTest.php - ../tests/e2e/magic-setter/* From 1c473c493462aaaf4b32f739656f3c8310d62f57 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:34:36 +0100 Subject: [PATCH 26/30] Fix config file --- phpbench.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpbench.json b/phpbench.json index c7dcc77dfcd..aa0b03f4724 100644 --- a/phpbench.json +++ b/phpbench.json @@ -1,7 +1,7 @@ { - "$schema":"./vendor/phpbench/phpbench/phpbench.schema.json", - "runner.bootstrap": "vendor/autoload.php", - "runner.path": "tests/bench", + "$schema":"./tests/vendor/phpbench/phpbench/phpbench.schema.json", + "runner.bootstrap": "vendor/autoload.php", + "runner.path": "tests/bench", "runner.file_pattern": "*Bench.php", "storage.xml_storage_path": "tests/bench/storage" } From f9e97eb108ba8579af566eff0cb183748f1580bb Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:35:50 +0100 Subject: [PATCH 27/30] Update baseline file --- tests/bench/storage/baseline.xml | 1261 ++++++++++++------------------ 1 file changed, 519 insertions(+), 742 deletions(-) diff --git a/tests/bench/storage/baseline.xml b/tests/bench/storage/baseline.xml index 80a4bef5875..e64638ac8cd 100644 --- a/tests/bench/storage/baseline.xml +++ b/tests/bench/storage/baseline.xml @@ -1,6 +1,6 @@ - - + + Linux @@ -20,9 +20,9 @@ - 0.6982421875 - 0.21142578125 - 0.07373046875 + 0.529296875 + 0.12841796875 + 0.04296875 git @@ -30,746 +30,523 @@ - 0.0059604644775391 - 0.14901161193848 - 1.6880035400391 + 0.0071525573730469 + 0.16689300537109 + 1.9149780273438 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From e852e8f7df3c8fbff7619e4162bc80c558ba16af Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:43:09 +0100 Subject: [PATCH 28/30] Exclude RegressionBench from linting because it has multi-line attribute and PHP 7.4 does not like that --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index f9022a401dc..83fd04c81ab 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ lint: XDEBUG_MODE=off php vendor/bin/parallel-lint --colors \ --exclude tests/PHPStan/Analyser/data \ --exclude tests/bench/data \ + --exclude tests/bench/RegressionBench.php \ --exclude tests/PHPStan/Analyser/nsrt \ --exclude tests/PHPStan/Rules/Methods/data \ --exclude tests/PHPStan/Rules/Functions/data \ From 98b76f027a2fe79f90ffa74e736247d761c88c12 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:47:08 +0100 Subject: [PATCH 29/30] Fix baseline --- phpstan-baseline.neon | 6 ------ 1 file changed, 6 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 479566a2892..6c3ff7e1536 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1863,12 +1863,6 @@ parameters: count: 1 path: tests/PHPStan/Analyser/EvaluationOrderTest.php - - - rawMessage: Anonymous function has an unused use $container. - identifier: closure.unusedUse - count: 1 - path: tests/bench/BenchCase.php - - rawMessage: Constant SOME_CONSTANT_IN_AUTOLOAD_FILE not found. identifier: constant.notFound From 753fecf20f379513f20c19059cb1b45894ea5171 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 11 Mar 2026 09:47:12 +0100 Subject: [PATCH 30/30] More lenient phpbench assertions --- tests/bench/RegressionBench.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bench/RegressionBench.php b/tests/bench/RegressionBench.php index f480c131a98..6998eea56e5 100644 --- a/tests/bench/RegressionBench.php +++ b/tests/bench/RegressionBench.php @@ -10,8 +10,8 @@ #[Bench\Warmup(revs: 1)] #[Bench\RetryThreshold(retryThreshold: 10.0)] #[Bench\Assert(expression: ' - (mode(baseline.time.avg) < 50 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 25%) - or (mode(baseline.time.avg) >= 50 milliseconds and mode(baseline.time.avg) < 500 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 10%) + (mode(baseline.time.avg) < 100 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 50%) + or (mode(baseline.time.avg) >= 100 milliseconds and mode(baseline.time.avg) < 500 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 25%) or (mode(baseline.time.avg) >= 500 milliseconds and mode(variant.time.avg) < mode(baseline.time.avg) +/- 5%)')] class RegressionBench extends BenchCase {