From 4e89e3bfd8ccd8c6568a1670c40210f91cc63ac9 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 7 Oct 2025 14:07:41 +0200 Subject: [PATCH 1/4] [autoload] Add workaround for phpstan + rector tests co-run to avoid duplicated php-parser loading error --- build/build-preload.php | 6 ++++ ...aramArrayDocblockBasedOnArrayMapRector.php | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/build/build-preload.php b/build/build-preload.php index 8129619832f..5264c6e10f0 100755 --- a/build/build-preload.php +++ b/build/build-preload.php @@ -55,6 +55,12 @@ final class PreloadBuilder return; } +// edge case during Rector tests case, happens when +// 1. phpstan autoload test case is triggered first, +// 2. all php-parser classes are loaded, +if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists(\PHPStan\Testing\PHPStanTestCase::class, false) && interface_exists(\PhpParser\Node::class, false)) { + return; +} CODE_SAMPLE; diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php index 9b6cf452a9e..adcc1c877bf 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php @@ -11,6 +11,11 @@ use PhpParser\Node\Stmt\Function_; use PHPStan\Type\ArrayType; use PHPStan\Type\MixedType; +<<<<<<< HEAD +======= +use PHPStan\Type\Type; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; +>>>>>>> a264677ce8 ([autoload] Add workaround for phpstan + rector tests co-run to avoid duplicated php-parser loading error) use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Rector\AbstractRector; use Rector\StaticTypeMapper\StaticTypeMapper; @@ -147,4 +152,31 @@ private function isArrayParam(Param $param): bool return $this->isName($param->type, 'array'); } +<<<<<<< HEAD +======= + + private function isMixedArrayType(Type $type): bool + { + if (! $type instanceof ArrayType) { + return false; + } + + if (! $type->getItemType() instanceof MixedType) { + return false; + } + + return $type->getKeyType() instanceof MixedType; + } + + private function isAlreadyNonMixedParamType(PhpDocInfo $functionPhpDocInfo, string $paramName): bool + { + $currentParamType = $functionPhpDocInfo->getParamType($paramName); + if ($currentParamType instanceof MixedType) { + return false; + } + + // has useful param type already? + return ! $this->isMixedArrayType($currentParamType); + } +>>>>>>> a264677ce8 ([autoload] Add workaround for phpstan + rector tests co-run to avoid duplicated php-parser loading error) } From 653e44866180dfdfb813a97a6067955d361dd9dd Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 7 Oct 2025 14:11:53 +0200 Subject: [PATCH 2/4] rebuild autoload --- preload-split-package.php | 6 ++++++ preload.php | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/preload-split-package.php b/preload-split-package.php index 7da50430478..60693aa58e1 100644 --- a/preload-split-package.php +++ b/preload-split-package.php @@ -6,6 +6,12 @@ return; } +// edge case during Rector tests case, happens when +// 1. phpstan autoload test case is triggered first, +// 2. all php-parser classes are loaded, +if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists(\PHPStan\Testing\PHPStanTestCase::class, false) && interface_exists(\PhpParser\Node::class, false)) { + return; +} require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/Node.php'; require_once __DIR__ . '/src/Contract/PhpParser/Node/StmtsAwareInterface.php'; require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php'; diff --git a/preload.php b/preload.php index ff3df4b2673..bc4c4d219bf 100644 --- a/preload.php +++ b/preload.php @@ -6,6 +6,12 @@ return; } +// edge case during Rector tests case, happens when +// 1. phpstan autoload test case is triggered first, +// 2. all php-parser classes are loaded, +if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists(\PHPStan\Testing\PHPStanTestCase::class, false) && interface_exists(\PhpParser\Node::class, false)) { + return; +} require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node.php'; require_once __DIR__ . '/src/Contract/PhpParser/Node/StmtsAwareInterface.php'; require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php'; From d1f3cf3f73492307f0749844c589645c9a436b4e Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 7 Oct 2025 14:15:51 +0200 Subject: [PATCH 3/4] cs --- preload-split-package.php | 9 +++++- preload.php | 9 +++++- ...aramArrayDocblockBasedOnArrayMapRector.php | 32 ------------------- .../PhpDocManipulator/PhpDocTypeChanger.php | 1 - 4 files changed, 16 insertions(+), 35 deletions(-) diff --git a/preload-split-package.php b/preload-split-package.php index 60693aa58e1..56eac84aba3 100644 --- a/preload-split-package.php +++ b/preload-split-package.php @@ -2,6 +2,9 @@ declare(strict_types=1); +use PhpParser\Node; +use PHPStan\Testing\PHPStanTestCase; + if (defined('__PHPSTAN_RUNNING__')) { return; } @@ -9,9 +12,13 @@ // edge case during Rector tests case, happens when // 1. phpstan autoload test case is triggered first, // 2. all php-parser classes are loaded, -if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists(\PHPStan\Testing\PHPStanTestCase::class, false) && interface_exists(\PhpParser\Node::class, false)) { +if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists( + PHPStanTestCase::class, + false +) && interface_exists(Node::class, false)) { return; } + require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/Node.php'; require_once __DIR__ . '/src/Contract/PhpParser/Node/StmtsAwareInterface.php'; require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php'; diff --git a/preload.php b/preload.php index bc4c4d219bf..5bce92733db 100644 --- a/preload.php +++ b/preload.php @@ -2,6 +2,9 @@ declare(strict_types=1); +use PhpParser\Node; +use PHPStan\Testing\PHPStanTestCase; + if (defined('__PHPSTAN_RUNNING__')) { return; } @@ -9,9 +12,13 @@ // edge case during Rector tests case, happens when // 1. phpstan autoload test case is triggered first, // 2. all php-parser classes are loaded, -if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists(\PHPStan\Testing\PHPStanTestCase::class, false) && interface_exists(\PhpParser\Node::class, false)) { +if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists( + PHPStanTestCase::class, + false +) && interface_exists(Node::class, false)) { return; } + require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node.php'; require_once __DIR__ . '/src/Contract/PhpParser/Node/StmtsAwareInterface.php'; require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php'; diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php index adcc1c877bf..9b6cf452a9e 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php @@ -11,11 +11,6 @@ use PhpParser\Node\Stmt\Function_; use PHPStan\Type\ArrayType; use PHPStan\Type\MixedType; -<<<<<<< HEAD -======= -use PHPStan\Type\Type; -use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; ->>>>>>> a264677ce8 ([autoload] Add workaround for phpstan + rector tests co-run to avoid duplicated php-parser loading error) use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Rector\AbstractRector; use Rector\StaticTypeMapper\StaticTypeMapper; @@ -152,31 +147,4 @@ private function isArrayParam(Param $param): bool return $this->isName($param->type, 'array'); } -<<<<<<< HEAD -======= - - private function isMixedArrayType(Type $type): bool - { - if (! $type instanceof ArrayType) { - return false; - } - - if (! $type->getItemType() instanceof MixedType) { - return false; - } - - return $type->getKeyType() instanceof MixedType; - } - - private function isAlreadyNonMixedParamType(PhpDocInfo $functionPhpDocInfo, string $paramName): bool - { - $currentParamType = $functionPhpDocInfo->getParamType($paramName); - if ($currentParamType instanceof MixedType) { - return false; - } - - // has useful param type already? - return ! $this->isMixedArrayType($currentParamType); - } ->>>>>>> a264677ce8 ([autoload] Add workaround for phpstan + rector tests co-run to avoid duplicated php-parser loading error) } diff --git a/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php b/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php index 8cb0abd62bc..4a4df6812cf 100644 --- a/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php +++ b/src/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php @@ -7,7 +7,6 @@ use PhpParser\Node\FunctionLike; use PhpParser\Node\Param; use PhpParser\Node\Stmt; -use PhpParser\Node\Stmt\ClassMethod; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode; use PHPStan\PhpDocParser\Ast\Node; use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; From e476fb37ad692b1096e00f59a74acdda67e4a0e8 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 7 Oct 2025 14:55:08 +0200 Subject: [PATCH 4/4] remove cs from preload --- build/build-preload.php | 13 ++++++++++++- ecs.php | 3 +++ preload-split-package.php | 14 +++++++++----- preload.php | 14 +++++++++----- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/build/build-preload.php b/build/build-preload.php index 5264c6e10f0..cac10bc1e87 100755 --- a/build/build-preload.php +++ b/build/build-preload.php @@ -51,6 +51,9 @@ final class PreloadBuilder declare(strict_types=1); +use PhpParser\Node; +use PHPStan\Testing\PHPStanTestCase; + if (defined('__PHPSTAN_RUNNING__')) { return; } @@ -58,10 +61,18 @@ final class PreloadBuilder // edge case during Rector tests case, happens when // 1. phpstan autoload test case is triggered first, // 2. all php-parser classes are loaded, -if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists(\PHPStan\Testing\PHPStanTestCase::class, false) && interface_exists(\PhpParser\Node::class, false)) { +if (defined('PHPUNIT_COMPOSER_INSTALL') && isPHPStanTestPreloaded()) { return; } +function isPHPStanTestPreloaded(): bool +{ + if (! class_exists(PHPStanTestCase::class, false)) { + return false; + } + + return interface_exists(Node::class, false); +} CODE_SAMPLE; /** diff --git a/ecs.php b/ecs.php index 0497edc8d5b..1ab742fc29d 100644 --- a/ecs.php +++ b/ecs.php @@ -24,6 +24,9 @@ '*/Fixture/*', '*/Expected/*', + // avoid re-running on build + __DIR__ . '/preload.php', + PhpdocTypesFixer::class => [ // double to Double false positive __DIR__ . '/rules/Php74/Rector/Double/RealToFloatTypeCastRector.php', diff --git a/preload-split-package.php b/preload-split-package.php index 56eac84aba3..b014aa1f698 100644 --- a/preload-split-package.php +++ b/preload-split-package.php @@ -12,14 +12,18 @@ // edge case during Rector tests case, happens when // 1. phpstan autoload test case is triggered first, // 2. all php-parser classes are loaded, -if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists( - PHPStanTestCase::class, - false -) && interface_exists(Node::class, false)) { +if (defined('PHPUNIT_COMPOSER_INSTALL') && isPHPStanTestPreloaded()) { return; } -require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/Node.php'; +function isPHPStanTestPreloaded(): bool +{ + if (! class_exists(PHPStanTestCase::class, false)) { + return false; + } + + return interface_exists(Node::class, false); +}require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/Node.php'; require_once __DIR__ . '/src/Contract/PhpParser/Node/StmtsAwareInterface.php'; require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php'; require_once __DIR__ . '/../../../vendor/nikic/php-parser/lib/PhpParser/Node/Expr.php'; diff --git a/preload.php b/preload.php index 5bce92733db..0e8f2828f72 100644 --- a/preload.php +++ b/preload.php @@ -12,14 +12,18 @@ // edge case during Rector tests case, happens when // 1. phpstan autoload test case is triggered first, // 2. all php-parser classes are loaded, -if (defined('PHPUNIT_COMPOSER_INSTALL') && class_exists( - PHPStanTestCase::class, - false -) && interface_exists(Node::class, false)) { +if (defined('PHPUNIT_COMPOSER_INSTALL') && isPHPStanTestPreloaded()) { return; } -require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node.php'; +function isPHPStanTestPreloaded(): bool +{ + if (! class_exists(PHPStanTestCase::class, false)) { + return false; + } + + return interface_exists(Node::class, false); +}require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node.php'; require_once __DIR__ . '/src/Contract/PhpParser/Node/StmtsAwareInterface.php'; require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php'; require_once __DIR__ . '/vendor/nikic/php-parser/lib/PhpParser/Node/Expr.php';