From 50ecd3449fe6e7342b38beb4a042580a825c24b4 Mon Sep 17 00:00:00 2001 From: Sebastian Schreiber Date: Tue, 17 Nov 2020 23:41:31 +0100 Subject: [PATCH] [TASK] Add extension.neon automatically (#1611) Resolves: #1608 --- build/box.json | 2 + config/services.php | 19 +- .../PHPStanServicesFactory.php | 170 ++++++++++++++++++ utils/phpstan/config/extension.neon | 13 ++ utils/phpstan/config/rules.neon | 10 ++ utils/phpstan/config/typo3-rector.neon | 27 +-- 6 files changed, 216 insertions(+), 25 deletions(-) create mode 100644 src/DependencyInjection/PHPStanServicesFactory.php create mode 100644 utils/phpstan/config/extension.neon create mode 100644 utils/phpstan/config/rules.neon diff --git a/build/box.json b/build/box.json index 244088d6e..243c1e89f 100644 --- a/build/box.json +++ b/build/box.json @@ -10,6 +10,8 @@ "vendor/rector/rector/packages", "config", "src", + "utils/phpstan/config", + "utils/phpstan/src", "Migrations" ], "exclude-composer-files": false, diff --git a/config/services.php b/config/services.php index e7325ebae..8aed83b8d 100644 --- a/config/services.php +++ b/config/services.php @@ -2,10 +2,16 @@ declare(strict_types=1); +use PHPStan\Analyser\NodeScopeResolver; +use PHPStan\Analyser\ScopeFactory; +use PHPStan\PhpDoc\TypeNodeResolver; +use PHPStan\Reflection\ReflectionProvider; use Ssch\TYPO3Rector\Console\Application; +use Ssch\TYPO3Rector\DependencyInjection\PHPStanServicesFactory; use Ssch\TYPO3Rector\Helper\Database\Refactorings\DatabaseConnectionToDbalRefactoring; use Symfony\Component\Console\Application as SymfonyApplication; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use function Symfony\Component\DependencyInjection\Loader\Configurator\service; return static function (ContainerConfigurator $containerConfigurator): void { $services = $containerConfigurator->services(); @@ -20,13 +26,24 @@ $services->alias(SymfonyApplication::class, Application::class); + $services->set(ReflectionProvider::class) + ->factory([service(PHPStanServicesFactory::class), 'createReflectionProvider']); + + $services->set(NodeScopeResolver::class) + ->factory([service(PHPStanServicesFactory::class), 'createNodeScopeResolver']); + + $services->set(ScopeFactory::class) + ->factory([service(PHPStanServicesFactory::class), 'createScopeFactory']); + + $services->set(TypeNodeResolver::class) + ->factory([service(PHPStanServicesFactory::class), 'createTypeNodeResolver']); + $services->load('Ssch\\TYPO3Rector\\', __DIR__ . '/../src') ->exclude( [ __DIR__ . '/../src/Rector', __DIR__ . '/../src/Set', __DIR__ . '/../src/Bootstrap', - __DIR__ . '/../src/DependencyInjection', __DIR__ . '/../src/HttpKernel', __DIR__ . '/../src/Compiler', ] diff --git a/src/DependencyInjection/PHPStanServicesFactory.php b/src/DependencyInjection/PHPStanServicesFactory.php new file mode 100644 index 000000000..f2ea5a250 --- /dev/null +++ b/src/DependencyInjection/PHPStanServicesFactory.php @@ -0,0 +1,170 @@ +appendPhpstanPHPUnitExtensionIfExists( + $currentWorkingDirectory, + $additionalConfigFiles + ); + + $temporaryPHPStanNeon = null; + + $currentProjectConfigFile = $currentWorkingDirectory . '/phpstan.neon'; + + if (file_exists($currentProjectConfigFile)) { + $phpstanNeonContent = $smartFileSystem->readFile($currentProjectConfigFile); + + // bleeding edge clean out, see https://github.com/rectorphp/rector/issues/2431 + if (Strings::match($phpstanNeonContent, self::BLEEDING_EDGE_REGEX)) { + // Note: We need a unique file per process if rector runs in parallel + $pid = getmypid(); + $temporaryPHPStanNeon = $currentWorkingDirectory . '/rector-temp-phpstan' . $pid . '.neon'; + $clearedPhpstanNeonContent = Strings::replace($phpstanNeonContent, self::BLEEDING_EDGE_REGEX); + $smartFileSystem->dumpFile($temporaryPHPStanNeon, $clearedPhpstanNeonContent); + + $additionalConfigFiles[] = $temporaryPHPStanNeon; + } else { + $additionalConfigFiles[] = $currentProjectConfigFile; + } + } + + $additionalConfigFiles[] = __DIR__ . '/../../vendor/rector/rector/packages/node-type-resolver/config/phpstan/type-extensions.neon'; + $additionalConfigFiles[] = __DIR__ . '/../../utils/phpstan/config/extension.neon'; + + // enable type inferring from constructor + $additionalConfigFiles[] = __DIR__ . '/../../vendor/rector/rector/packages/node-type-resolver/config/phpstan/better-infer.neon'; + + $this->container = $containerFactory->create(sys_get_temp_dir(), $additionalConfigFiles, []); + + // clear bleeding edge fallback + if (null !== $temporaryPHPStanNeon) { + $smartFileSystem->remove($temporaryPHPStanNeon); + } + } + + /** + * @api + */ + public function createReflectionProvider(): ReflectionProvider + { + return $this->container->getByType(ReflectionProvider::class); + } + + /** + * @api + */ + public function createNodeScopeResolver(): NodeScopeResolver + { + return $this->container->getByType(NodeScopeResolver::class); + } + + /** + * @api + */ + public function createTypeSpecifier(): TypeSpecifier + { + return $this->container->getByType(TypeSpecifier::class); + } + + /** + * @api + */ + public function createScopeFactory(): ScopeFactory + { + return $this->container->getByType(ScopeFactory::class); + } + + /** + * @api + */ + public function createDynamicReturnTypeExtensionRegistryProvider(): DynamicReturnTypeExtensionRegistryProvider + { + return $this->container->getByType(DynamicReturnTypeExtensionRegistryProvider::class); + } + + /** + * @api + */ + public function createDependencyResolver(): DependencyResolver + { + return $this->container->getByType(DependencyResolver::class); + } + + /** + * @api + */ + public function createFileHelper(): FileHelper + { + return $this->container->getByType(FileHelper::class); + } + + /** + * @api + */ + public function createOperatorTypeSpecifyingExtensionRegistryProvider(): OperatorTypeSpecifyingExtensionRegistryProvider + { + return $this->container->getByType(OperatorTypeSpecifyingExtensionRegistryProvider::class); + } + + /** + * @api + */ + public function createTypeNodeResolver(): TypeNodeResolver + { + return $this->container->getByType(TypeNodeResolver::class); + } + + private function appendPhpstanPHPUnitExtensionIfExists( + string $currentWorkingDirectory, + array $additionalConfigFiles + ): array { + $phpstanPhpunitExtensionConfig = $currentWorkingDirectory . '/vendor/phpstan/phpstan-phpunit/extension.neon'; + if (file_exists($phpstanPhpunitExtensionConfig) && class_exists(TestCase::class)) { + $additionalConfigFiles[] = $phpstanPhpunitExtensionConfig; + } + return $additionalConfigFiles; + } +} diff --git a/utils/phpstan/config/extension.neon b/utils/phpstan/config/extension.neon new file mode 100644 index 000000000..ddea1c47c --- /dev/null +++ b/utils/phpstan/config/extension.neon @@ -0,0 +1,13 @@ +services: + - + class: Ssch\TYPO3Rector\PHPStan\Type\GeneralUtilityDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicStaticMethodReturnTypeExtension + - + class: Ssch\TYPO3Rector\PHPStan\Type\ObjectManagerDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: Ssch\TYPO3Rector\PHPStan\Type\ContextGetAspectDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension diff --git a/utils/phpstan/config/rules.neon b/utils/phpstan/config/rules.neon new file mode 100644 index 000000000..b0777975d --- /dev/null +++ b/utils/phpstan/config/rules.neon @@ -0,0 +1,10 @@ +services: + - + class: Ssch\TYPO3Rector\PHPStan\Rules\AddSeeDocBlockForRectorClass + tags: + - phpstan.rules.rule + + - + class: Ssch\TYPO3Rector\PHPStan\Rules\AddCodeCoverageIgnoreForRectorDefinition + tags: + - phpstan.rules.rule diff --git a/utils/phpstan/config/typo3-rector.neon b/utils/phpstan/config/typo3-rector.neon index ac42b639b..7c704b5bc 100644 --- a/utils/phpstan/config/typo3-rector.neon +++ b/utils/phpstan/config/typo3-rector.neon @@ -1,24 +1,3 @@ -services: - - - class: Ssch\TYPO3Rector\PHPStan\Rules\AddSeeDocBlockForRectorClass - tags: - - phpstan.rules.rule - - - - class: Ssch\TYPO3Rector\PHPStan\Rules\AddCodeCoverageIgnoreForRectorDefinition - tags: - - phpstan.rules.rule - - - - class: Ssch\TYPO3Rector\PHPStan\Type\GeneralUtilityDynamicReturnTypeExtension - tags: - - phpstan.broker.dynamicStaticMethodReturnTypeExtension - - - - class: Ssch\TYPO3Rector\PHPStan\Type\ObjectManagerDynamicReturnTypeExtension - tags: - - phpstan.broker.dynamicMethodReturnTypeExtension - - - class: Ssch\TYPO3Rector\PHPStan\Type\ContextGetAspectDynamicReturnTypeExtension - tags: - - phpstan.broker.dynamicMethodReturnTypeExtension +includes: + - rules.neon + - extension.neon