add PHPStanStaticTypeMapperChecker packages

This commit is contained in:
TomasVotruba 2020-01-16 02:22:46 +01:00
parent e1e45ff02e
commit 1678950146
6 changed files with 193 additions and 1 deletions

View File

@ -100,8 +100,23 @@ jobs:
- run: composer install --no-progress
- run: |
php ci/check_services_in_yaml_configs.php
- run: |
php ci/run_all_sets.php
phpstan_types_checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
-
uses: shivammathur/setup-php@v1
with:
php-version: 7.2
coverage: none # disable xdebug, pcov
- run: composer install --no-progress
- run: |
bin/rector sync-types
- run: |
bin/rector check-static-type-mappers
fatal_scan:
runs-on: ubuntu-latest

View File

@ -173,6 +173,7 @@
"Rector\\Phalcon\\Tests\\": "packages/Phalcon/tests",
"Rector\\DoctrineGedmoToKnplabs\\Tests\\": "packages/DoctrineGedmoToKnplabs/tests",
"Rector\\MinimalScope\\Tests\\": "packages/MinimalScope/tests",
"Rector\\Utils\\PHPStanStaticTypeMapperChecker\\": "utils/PHPStanStaticTypeMapperChecker/src",
"Rector\\Polyfill\\Tests\\": "packages/Polyfill/tests"
},
"classmap": [

View File

@ -2,7 +2,7 @@ imports:
- { resource: '../packages/**/config/config.yaml' }
- { resource: 'services.yaml' }
# only in local repository
- { resource: '../utils/**/config/config.yaml', ignore_errors: true }
- { resource: '../utils/**/config/config.yaml' }
parameters:
# processed paths

View File

@ -0,0 +1,8 @@
services:
_defaults:
public: true
autowire: true
autoconfigure: true
Rector\Utils\PHPStanStaticTypeMapperChecker\:
resource: '../src'

View File

@ -0,0 +1,108 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanStaticTypeMapperChecker\Command;
use PHPStan\Type\NonexistentParentClassType;
use Rector\Console\Command\AbstractCommand;
use Rector\Console\Shell;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
use Rector\Utils\PHPStanStaticTypeMapperChecker\Finder\PHPStanTypeClassFinder;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Console\Command\CommandNaming;
final class CheckStaticTypeMappersCommand extends AbstractCommand
{
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
/**
* @var TypeMapperInterface[]
*/
private $typeMappers = [];
/**
* @var PHPStanTypeClassFinder
*/
private $phpStanTypeClassFinder;
/**
* @param TypeMapperInterface[] $typeMappers
*/
public function __construct(
array $typeMappers,
SymfonyStyle $symfonyStyle,
PHPStanTypeClassFinder $phpStanTypeClassFinder
) {
$this->typeMappers = $typeMappers;
$this->symfonyStyle = $symfonyStyle;
$this->phpStanTypeClassFinder = $phpStanTypeClassFinder;
parent::__construct();
}
protected function configure(): void
{
$this->setName(CommandNaming::classToName(self::class));
$this->setDescription('[Dev] check PHPStan types to TypeMappers');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$missingNodeClasses = $this->getMissingNodeClasses();
if ($missingNodeClasses === []) {
$this->symfonyStyle->success('All PHPStan Types are covered by TypeMapper');
return Shell::CODE_SUCCESS;
}
$this->symfonyStyle->error('Some classes are missing nodes');
$this->symfonyStyle->listing($missingNodeClasses);
die;
return Shell::CODE_ERROR;
}
/**
* @return string[]
*/
private function getMissingNodeClasses(): array
{
$phpStanTypeClasses = $this->phpStanTypeClassFinder->find();
$supportedPHPStanTypeClasses = $this->getSupportedTypeClasses();
$unsupportedTypeClasses = [];
foreach ($phpStanTypeClasses as $phpStanTypeClass) {
foreach ($supportedPHPStanTypeClasses as $supportedPHPStanTypeClass) {
if (is_a($phpStanTypeClass, $supportedPHPStanTypeClass, true)) {
continue 2;
}
}
$unsupportedTypeClasses[] = $phpStanTypeClass;
}
$typesToRemove = [NonexistentParentClassType::class];
return array_diff($unsupportedTypeClasses, $typesToRemove);
}
/**
* @return string[]
*/
private function getSupportedTypeClasses(): array
{
$supportedPHPStanTypeClasses = [];
foreach ($this->typeMappers as $typeMappers) {
$supportedPHPStanTypeClasses[] = $typeMappers->getNodeClass();
}
return $supportedPHPStanTypeClasses;
}
}

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanStaticTypeMapperChecker\Finder;
use Nette\Loaders\RobotLoader;
use Nette\Utils\Strings;
final class PHPStanTypeClassFinder
{
/**
* @return string[]
*/
public function find(): array
{
$robotLoader = new RobotLoader();
$robotLoader->addDirectory($this->getPHPStanPharSrcTypeDirectoryPath());
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_phpstan_types');
$robotLoader->acceptFiles = ['*Type.php'];
$robotLoader->rebuild();
$classLikesToFilePaths = $robotLoader->getIndexedClasses();
$classLikes = array_keys($classLikesToFilePaths);
return $this->filterClassesOnly($classLikes);
}
/**
* @param string[] $classLikes
* @return string[]
*/
private function filterClassesOnly(array $classLikes): array
{
$classes = [];
foreach ($classLikes as $classLike) {
if (! class_exists($classLike)) {
continue;
}
if (Strings::match($classLike, '#\\\\Accessory\\\\#')) {
continue;
}
$classes[] = $classLike;
}
return $classes;
}
/**
* @see https://github.com/dg/nette-robot-loader/blob/593c0e40e511c0b0700610a6a3964a210219139f/tests/Loaders/RobotLoader.phar.phpt#L33
*/
private function getPHPStanPharSrcTypeDirectoryPath(): string
{
$phpstanPharRealpath = realpath(__DIR__ . '/../../../../vendor/phpstan/phpstan/phpstan.phar');
return 'phar://' . $phpstanPharRealpath . '/src/Type';
}
}