drop PHPStanAttributeTypeSyncer, handled by external package (#5131)

This commit is contained in:
Tomas Votruba 2021-01-10 14:51:27 +01:00 committed by GitHub
parent 074298d35c
commit d1df8f76cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1 additions and 705 deletions

View File

@ -43,10 +43,6 @@ jobs:
# this is very slow, so it has to be in own workflow
run: bin/rector validate-sets --ansi
-
name: 'Validate PHPStan Types Compatibility'
run: bin/rector sync-types --ansi
-
name: 'Validate PHPStan Mappers Compatibility'
run: bin/rector check-static-type-mappers --ansi

View File

@ -283,7 +283,6 @@
"Rector\\Utils\\DoctrineAnnotationParserSyncer\\": "utils/doctrine-annotation-parser-syncer/src",
"Rector\\Utils\\NodeDocumentationGenerator\\": "utils/node-documentation-generator/src",
"Rector\\Utils\\NodeDocumentationGenerator\\Tests\\": "utils/node-documentation-generator/tests",
"Rector\\Utils\\PHPStanAttributeTypeSyncer\\": "utils/phpstan-attribute-type-syncer/src",
"Rector\\Utils\\PHPStanTypeMapperChecker\\": "utils/phpstan-type-mapper-checker/src",
"Rector\\Utils\\ProjectValidator\\": "utils/project-validator/src",
"Rector\\Carbon\\Tests\\": "rules/carbon/tests"

View File

@ -6,7 +6,7 @@ sonar.projectKey=rectorphp_rector
# wildcards don't work :(
sonar.sources=src,rules/autodiscovery/src,rules/architecture/src,packages/attribute-aware-php-doc/src,packages/better-php-doc-parser/src,rules/cakephp/src,rules/code-quality/src,rules/coding-style/src,packages/console-differ/src,rules/dead-code/src,rules/doctrine/src,rules/doctrine-code-quality/src,packages/file-system-rector/src,rules/laravel/src,rules/legacy/src,rules/mysql-to-mysqli/src,rules/nette-tester-to-phpunit/src,rules/nette-to-symfony/src,rules/nette/src,packages/node-collector/src,packages/node-type-resolver/src,packages/node-name-resolver/src,packages/phpstan-static-type-mapper/src,rules/phpunit-symfony/src,rules/phpunit/src,rules/psr4/src,rules/php-spec-to-phpunit/src,rules/php52/src,rules/php53/src,rules/php54/src,rules/php55/src,rules/php56/src,rules/php70/src,rules/php71/src,rules/php72/src,rules/php73/src,rules/php74/src,rules/php80/src,rules/removing-static/src,rules/renaming/src,rules/restoration/src,rules/dependency-injection/src,rules/sensio/src,packages/static-type-mapper/src,rules/symfony-code-quality/src,rules/symfony-phpunit/src,rules/symfony/src,rules/twig/src,rules/type-declaration/src,packages/vendor-locker/src,packages/rector-generator/src,rules/code-quality-strict/src,rules/phalcon/src,rules/doctrine-gedmo-to-knplabs/src,rules/polyfill/src,rules/generic/src
sonar.tests=tests,rules/autodiscovery/tests,rules/architecture/tests,packages/better-php-doc-parser/tests,rules/cakephp/tests,rules/code-quality/tests,rules/coding-style/tests,rules/dead-code/tests,rules/doctrine/tests,rules/doctrine-code-quality/tests,rules/laravel/tests,rules/legacy/tests,rules/mysql-to-mysqli/tests,rules/nette-tester-to-phpunit/tests,rules/nette-to-symfony/tests,rules/nette/tests,packages/node-type-resolver/tests,utils/phpstan-extensions/src,rules/phpunit-symfony/tests,rules/phpunit/tests,rules/psr4/tests,rules/php-spec-to-phpunit/tests,rules/php52/tests,rules/php53/tests,rules/php54/tests,rules/php55/tests,rules/php56/tests,rules/php70/tests,rules/php71/tests,rules/php72/tests,rules/php73/tests,rules/php74/tests,rules/php80/tests,rules/removing-static/tests,rules/renaming/tests,rules/restoration/tests,rules/dependency-injection/tests,rules/sensio/tests,rules/symfony-code-quality/tests,rules/symfony-phpunit/tests,rules/symfony/tests,rules/twig/tests,rules/type-declaration/tests,rules/code-quality-strict/tests,rules/phalcon/tests,utils/node-documentation-generator/src,utils/phpstan-attribute-type-syncer/src,utils/phpstan-type-mapper-checker/src,rules/doctrine-gedmo-to-knplabs/tests,rules/polyfill/tests,rules/generic/tests
sonar.tests=tests,rules/autodiscovery/tests,rules/architecture/tests,packages/better-php-doc-parser/tests,rules/cakephp/tests,rules/code-quality/tests,rules/coding-style/tests,rules/dead-code/tests,rules/doctrine/tests,rules/doctrine-code-quality/tests,rules/laravel/tests,rules/legacy/tests,rules/mysql-to-mysqli/tests,rules/nette-tester-to-phpunit/tests,rules/nette-to-symfony/tests,rules/nette/tests,packages/node-type-resolver/tests,utils/phpstan-extensions/src,rules/phpunit-symfony/tests,rules/phpunit/tests,rules/psr4/tests,rules/php-spec-to-phpunit/tests,rules/php52/tests,rules/php53/tests,rules/php54/tests,rules/php55/tests,rules/php56/tests,rules/php70/tests,rules/php71/tests,rules/php72/tests,rules/php73/tests,rules/php74/tests,rules/php80/tests,rules/removing-static/tests,rules/renaming/tests,rules/restoration/tests,rules/dependency-injection/tests,rules/sensio/tests,rules/symfony-code-quality/tests,rules/symfony-phpunit/tests,rules/symfony/tests,rules/twig/tests,rules/type-declaration/tests,rules/code-quality-strict/tests,rules/phalcon/tests,utils/node-documentation-generator/src,utils/phpstan-type-mapper-checker/src,rules/doctrine-gedmo-to-knplabs/tests,rules/polyfill/tests,rules/generic/tests
# possibly manual operation needed :/
# https://docs.sonarqube.org/latest/project-administration/narrowing-the-focus/

View File

@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->defaults()
->public()
->autowire()
->autoconfigure();
$services->load('Rector\Utils\PHPStanAttributeTypeSyncer\\', __DIR__ . '/../src')
->exclude([__DIR__ . '/../src/ValueObject']);
};

View File

@ -1,47 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\ClassNaming;
use Nette\Utils\Strings;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\Utils\PHPStanAttributeTypeSyncer\ValueObject\Paths;
final class AttributeClassNaming
{
/**
* @var ClassNaming
*/
private $classNaming;
public function __construct(ClassNaming $classNaming)
{
$this->classNaming = $classNaming;
}
public function createAttributeAwareShortClassName(string $nodeClass): string
{
$shortMissingNodeClass = $this->classNaming->getShortName($nodeClass);
return 'AttributeAware' . $shortMissingNodeClass;
}
public function createAttributeAwareFactoryShortClassName(string $nodeClass): string
{
$shortMissingNodeClass = $this->classNaming->getShortName($nodeClass);
return 'AttributeAware' . $shortMissingNodeClass . 'Factory';
}
public function createAttributeAwareClassName(string $nodeClass): string
{
if (Strings::contains($nodeClass, '\\Type\\')) {
$namespace = Paths::NAMESPACE_TYPE_NODE;
} else {
$namespace = Paths::NAMESPACE_PHPDOC_NODE;
}
return $namespace . '\\' . $this->createAttributeAwareShortClassName($nodeClass);
}
}

View File

@ -1,99 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\Command;
use Rector\AttributeAwarePhpDoc\AttributeAwareNodeFactoryCollector;
use Rector\Core\Console\Command\AbstractCommand;
use Rector\Utils\PHPStanAttributeTypeSyncer\Finder\NodeClassFinder;
use Rector\Utils\PHPStanAttributeTypeSyncer\Generator\AttributeAwareNodeFactoryGenerator;
use Rector\Utils\PHPStanAttributeTypeSyncer\Generator\AttributeAwareNodeGenerator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Console\ShellCode;
final class SyncTypesCommand extends AbstractCommand
{
/**
* @var AttributeAwareNodeFactoryCollector
*/
private $attributeAwareNodeFactoryCollector;
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
/**
* @var NodeClassFinder
*/
private $nodeClassFinder;
/**
* @var AttributeAwareNodeGenerator
*/
private $attributeAwareNodeGenerator;
/**
* @var AttributeAwareNodeFactoryGenerator
*/
private $attributeAwareNodeFactoryGenerator;
public function __construct(
AttributeAwareNodeFactoryCollector $attributeAwareNodeFactoryCollector,
AttributeAwareNodeFactoryGenerator $attributeAwareNodeFactoryGenerator,
AttributeAwareNodeGenerator $attributeAwareNodeGenerator,
NodeClassFinder $nodeClassFinder,
SymfonyStyle $symfonyStyle
) {
$this->attributeAwareNodeFactoryCollector = $attributeAwareNodeFactoryCollector;
$this->symfonyStyle = $symfonyStyle;
$this->nodeClassFinder = $nodeClassFinder;
$this->attributeAwareNodeGenerator = $attributeAwareNodeGenerator;
$this->attributeAwareNodeFactoryGenerator = $attributeAwareNodeFactoryGenerator;
parent::__construct();
}
protected function configure(): void
{
$this->setDescription('[DEV] Synchronize PHPStan types to attribute aware types in Rectors');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$missingNodeClasses = $this->getMissingNodeClasses();
if ($missingNodeClasses === []) {
$this->symfonyStyle->success(
'All PHPStan Doc Parser nodes are covered with attribute aware mirror in Rector'
);
return ShellCode::SUCCESS;
}
$this->symfonyStyle->error('These classes are missing their attribute aware brother');
foreach ($missingNodeClasses as $missingNodeClass) {
// 1. generate node
$this->attributeAwareNodeGenerator->generateFromPhpDocParserNodeClass($missingNodeClass);
// 2. generate node factory...
$this->attributeAwareNodeFactoryGenerator->generateFromPhpDocParserNodeClass($missingNodeClass);
}
return ShellCode::SUCCESS;
}
/**
* @return string[]
*/
private function getMissingNodeClasses(): array
{
$phpDocParserTagValueNodeClasses = $this->nodeClassFinder->findCurrentPHPDocParserNodeClasses();
$supportedNodeClasses = $this->attributeAwareNodeFactoryCollector->getSupportedNodeClasses();
return array_diff($phpDocParserTagValueNodeClasses, $supportedNodeClasses);
}
}

View File

@ -1,61 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\Finder;
use Nette\Loaders\RobotLoader;
final class NodeClassFinder
{
/**
* @var string[]
*/
private const EXCLUDED_CLASSES = ['PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode'];
/**
* @return class-string[]
*/
public function findCurrentPHPDocParserNodeClasses(): array
{
return $this->findClassesByNamePatternInDirectories(
'*Node.php',
[
__DIR__ . '/../../../../vendor/phpstan/phpdoc-parser/src/Ast/Type',
__DIR__ . '/../../../../vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc',
]
);
}
/**
* @param string[] $directories
* @return class-string[]
*/
private function findClassesByNamePatternInDirectories(string $namePattern, array $directories): array
{
$robotLoader = new RobotLoader();
$robotLoader->addDirectory(...$directories);
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_phpdoc_parser_ast');
$robotLoader->acceptFiles = [$namePattern];
$robotLoader->rebuild();
$indexedClasses = $robotLoader->getIndexedClasses();
$classLikes = array_keys($indexedClasses);
// keep only classes, skip interfaces
$classes = [];
foreach ($classLikes as $classLike) {
if (! class_exists($classLike)) {
continue;
}
$classes[] = $classLike;
}
return array_diff($classes, self::EXCLUDED_CLASSES);
}
}

View File

@ -1,40 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\Generator;
use PhpParser\Node\Stmt\Namespace_;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Symplify\SmartFileSystem\SmartFileSystem;
abstract class AbstractAttributeAwareNodeGenerator
{
/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;
/**
* @var SmartFileSystem
*/
private $smartFileSystem;
/**
* @required
*/
public function autowireAbstractAttributeAwareNodeGenerator(
BetterStandardPrinter $betterStandardPrinter,
SmartFileSystem $smartFileSystem
): void {
$this->betterStandardPrinter = $betterStandardPrinter;
$this->smartFileSystem = $smartFileSystem;
}
protected function printNamespaceToFile(Namespace_ $namespace, string $targetFilePath): void
{
$fileContent = $this->betterStandardPrinter->prettyPrintFile([$namespace]);
$this->smartFileSystem->dumpFile($targetFilePath, $fileContent);
}
}

View File

@ -1,84 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\Generator;
use Nette\Utils\Strings;
use Rector\Utils\PHPStanAttributeTypeSyncer\ClassNaming\AttributeClassNaming;
use Rector\Utils\PHPStanAttributeTypeSyncer\NodeFactory\AttributeAwareClassFactoryFactory;
use Symfony\Component\Console\Style\SymfonyStyle;
final class AttributeAwareNodeFactoryGenerator extends AbstractAttributeAwareNodeGenerator
{
/**
* @var AttributeClassNaming
*/
private $attributeClassNaming;
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
/**
* @var AttributeAwareClassFactoryFactory
*/
private $attributeAwareClassFactoryFactory;
public function __construct(
AttributeAwareClassFactoryFactory $attributeAwareClassFactoryFactory,
AttributeClassNaming $attributeClassNaming,
SymfonyStyle $symfonyStyle
) {
$this->attributeClassNaming = $attributeClassNaming;
$this->symfonyStyle = $symfonyStyle;
$this->attributeAwareClassFactoryFactory = $attributeAwareClassFactoryFactory;
}
public function generateFromPhpDocParserNodeClass(string $phpDocParserNodeClass): void
{
$targetFilePath = $this->resolveTargetFilePath($phpDocParserNodeClass);
// prevent file override
if (file_exists($targetFilePath)) {
$realTargetFilePath = realpath($targetFilePath);
$message = sprintf('File "%s" already exists, skipping', $realTargetFilePath);
$this->symfonyStyle->note($message);
return;
}
$namespace = $this->attributeAwareClassFactoryFactory->createFromPhpDocParserNodeClass($phpDocParserNodeClass);
$this->printNamespaceToFile($namespace, $targetFilePath);
$this->reportGeneratedAttributeAwareNode($phpDocParserNodeClass, $targetFilePath);
}
private function resolveTargetFilePath(string $phpDocParserNodeClass): string
{
$shortClassName = $this->attributeClassNaming->createAttributeAwareFactoryShortClassName(
$phpDocParserNodeClass
);
if (Strings::contains($phpDocParserNodeClass, '\\Type\\')) {
return __DIR__ . '/../../../../packages/attribute-aware-php-doc/src/AttributeAwareNodeFactory/Type/' . $shortClassName . '.php';
}
return __DIR__ . '/../../../../packages/attribute-aware-php-doc/src/AttributeAwareNodeFactory/PhpDoc/' . $shortClassName . '.php';
}
private function reportGeneratedAttributeAwareNode(string $missingNodeClass, string $filePath): void
{
$attributeAwareFullyQualifiedClassName = $this->attributeClassNaming->createAttributeAwareClassName(
$missingNodeClass
);
$message = sprintf(
'Class "%s" now has freshly generated "%s" in "%s"',
$missingNodeClass,
$attributeAwareFullyQualifiedClassName,
$filePath
);
$this->symfonyStyle->note($message);
}
}

View File

@ -1,82 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\Generator;
use Nette\Utils\Strings;
use Rector\Utils\PHPStanAttributeTypeSyncer\ClassNaming\AttributeClassNaming;
use Rector\Utils\PHPStanAttributeTypeSyncer\NodeFactory\AttributeAwareClassFactory;
use Symfony\Component\Console\Style\SymfonyStyle;
final class AttributeAwareNodeGenerator extends AbstractAttributeAwareNodeGenerator
{
/**
* @var AttributeClassNaming
*/
private $attributeClassNaming;
/**
* @var SymfonyStyle
*/
private $symfonyStyle;
/**
* @var AttributeAwareClassFactory
*/
private $attributeAwareClassFactory;
public function __construct(
AttributeAwareClassFactory $attributeAwareClassFactory,
AttributeClassNaming $attributeClassNaming,
SymfonyStyle $symfonyStyle
) {
$this->attributeClassNaming = $attributeClassNaming;
$this->symfonyStyle = $symfonyStyle;
$this->attributeAwareClassFactory = $attributeAwareClassFactory;
}
public function generateFromPhpDocParserNodeClass(string $phpDocParserNodeClass): void
{
$targetFilePath = $this->resolveTargetFilePath($phpDocParserNodeClass);
// prevent file override
if (file_exists($targetFilePath)) {
$realTargetFilePath = realpath($targetFilePath);
$message = sprintf('File "%s" already exists, skipping', $realTargetFilePath);
$this->symfonyStyle->note($message);
return;
}
$namespace = $this->attributeAwareClassFactory->createFromPhpDocParserNodeClass($phpDocParserNodeClass);
$this->printNamespaceToFile($namespace, $targetFilePath);
$this->reportGeneratedAttributeAwareNode($phpDocParserNodeClass);
}
private function resolveTargetFilePath(string $phpDocParserNodeClass): string
{
$shortClassName = $this->attributeClassNaming->createAttributeAwareShortClassName($phpDocParserNodeClass);
if (Strings::contains($phpDocParserNodeClass, '\\Type\\')) {
return __DIR__ . '/../../../../packages/attribute-aware-php-doc/src/Ast/Type/' . $shortClassName . '.php';
}
return __DIR__ . '/../../../../packages/attribute-aware-php-doc/src/Ast/PhpDoc/' . $shortClassName . '.php';
}
private function reportGeneratedAttributeAwareNode(string $missingNodeClass): void
{
$attributeAwareFullyQualifiedClassName = $this->attributeClassNaming->createAttributeAwareClassName(
$missingNodeClass
);
$message = sprintf(
'Class "%s" now has freshly generated "%s"',
$missingNodeClass,
$attributeAwareFullyQualifiedClassName
);
$this->symfonyStyle->note($message);
}
}

View File

@ -1,60 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\NodeFactory;
use Nette\Utils\Strings;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Namespace_;
use Rector\BetterPhpDocParser\Attributes\Attribute\AttributeTrait;
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;
use Rector\Core\PhpParser\Builder\ClassBuilder;
use Rector\Core\PhpParser\Builder\NamespaceBuilder;
use Rector\Core\PhpParser\Builder\TraitUseBuilder;
use Rector\Utils\PHPStanAttributeTypeSyncer\ClassNaming\AttributeClassNaming;
use Rector\Utils\PHPStanAttributeTypeSyncer\ValueObject\Paths;
final class AttributeAwareClassFactory
{
/**
* @var AttributeClassNaming
*/
private $attributeClassNaming;
public function __construct(AttributeClassNaming $attributeClassNaming)
{
$this->attributeClassNaming = $attributeClassNaming;
}
public function createFromPhpDocParserNodeClass(string $nodeClass): Namespace_
{
if (Strings::contains($nodeClass, '\\Type\\')) {
$namespace = Paths::NAMESPACE_TYPE_NODE;
} else {
$namespace = Paths::NAMESPACE_PHPDOC_NODE;
}
$namespaceBuilder = new NamespaceBuilder($namespace);
$shortClassName = $this->attributeClassNaming->createAttributeAwareShortClassName($nodeClass);
$classBuilder = $this->createClassBuilder($nodeClass, $shortClassName);
$traitUseBuilder = new TraitUseBuilder(new FullyQualified(AttributeTrait::class));
$classBuilder->addStmt($traitUseBuilder);
$namespaceBuilder->addStmt($classBuilder->getNode());
return $namespaceBuilder->getNode();
}
private function createClassBuilder(string $nodeClass, string $shortClassName): ClassBuilder
{
$classBuilder = new ClassBuilder($shortClassName);
$classBuilder->makeFinal();
$classBuilder->extend(new FullyQualified($nodeClass));
$classBuilder->implement(new FullyQualified(AttributeAwareNodeInterface::class));
return $classBuilder;
}
}

View File

@ -1,181 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\NodeFactory;
use Nette\Utils\Strings;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Return_;
use PHPStan\PhpDocParser\Ast\Node;
use Rector\AttributeAwarePhpDoc\Contract\AttributeNodeAwareFactory\AttributeNodeAwareFactoryInterface;
use Rector\BetterPhpDocParser\Contract\PhpDocNode\AttributeAwareNodeInterface;
use Rector\Core\PhpParser\Builder\ClassBuilder;
use Rector\Core\PhpParser\Builder\MethodBuilder;
use Rector\Core\PhpParser\Builder\NamespaceBuilder;
use Rector\Core\PhpParser\Builder\ParamBuilder;
use Rector\Utils\PHPStanAttributeTypeSyncer\ClassNaming\AttributeClassNaming;
use Rector\Utils\PHPStanAttributeTypeSyncer\ValueObject\Paths;
use ReflectionClass;
final class AttributeAwareClassFactoryFactory
{
/**
* @var string
*/
private const NODE = 'node';
/**
* @var AttributeClassNaming
*/
private $attributeClassNaming;
public function __construct(AttributeClassNaming $attributeClassNaming)
{
$this->attributeClassNaming = $attributeClassNaming;
}
public function createFromPhpDocParserNodeClass(string $nodeClass): Namespace_
{
if (Strings::contains($nodeClass, '\\Type\\')) {
$namespace = Paths::NAMESPACE_TYPE_NODE_FACTORY;
} else {
$namespace = Paths::NAMESPACE_PHPDOC_NODE_FACTORY;
}
$namespaceBuilder = new NamespaceBuilder($namespace);
$shortClassName = $this->attributeClassNaming->createAttributeAwareFactoryShortClassName($nodeClass);
$classBuilder = new ClassBuilder($shortClassName);
$classBuilder->makeFinal();
$classBuilder->implement(new FullyQualified(AttributeNodeAwareFactoryInterface::class));
$classMethods = $this->createClassMethods($nodeClass);
$classBuilder->addStmts($classMethods);
$namespaceBuilder->addStmt($classBuilder->getNode());
return $namespaceBuilder->getNode();
}
/**
* @return ClassMethod[]
*/
private function createClassMethods(string $nodeClass): array
{
$classMethods = [];
$classMethods[] = $this->createGetOriginalNodeClass($nodeClass);
$paramBuilder = new ParamBuilder(self::NODE);
$paramBuilder->setType(new FullyQualified(Node::class));
$classMethods[] = $this->createIsMatchClassMethod($nodeClass, $paramBuilder);
$classMethods[] = $this->createCreateClassMethod($nodeClass);
return $classMethods;
}
private function createGetOriginalNodeClass(string $nodeClass): ClassMethod
{
$methodBuilder = new MethodBuilder('getOriginalNodeClass');
$methodBuilder->makePublic();
$methodBuilder->setReturnType('string');
$classConstFetch = $this->createClassReference($nodeClass);
$methodBuilder->addStmt(new Return_($classConstFetch));
return $methodBuilder->getNode();
}
private function createIsMatchClassMethod(string $nodeClass, ParamBuilder $paramBuilder): ClassMethod
{
$methodBuilder = new MethodBuilder('isMatch');
$methodBuilder->addParam($paramBuilder);
$methodBuilder->makePublic();
$methodBuilder->setReturnType('bool');
$isAFuncCall = $this->createIsAFuncCall($nodeClass);
$methodBuilder->addStmt(new Return_($isAFuncCall));
return $methodBuilder->getNode();
}
private function createCreateClassMethod(string $nodeClass): ClassMethod
{
$methodBuilder = new MethodBuilder('create');
$paramBuilder = new ParamBuilder('docContent');
$paramBuilder->setType('string');
$docContentParam = $paramBuilder->getNode();
$methodBuilder->addParam($paramBuilder);
$methodBuilder->addParam($docContentParam);
$methodBuilder->makePublic();
$methodBuilder->setReturnType(new FullyQualified(AttributeAwareNodeInterface::class));
// add @paramBuilder doc with more precise type
$paramDocBlock = sprintf('/**%s * @paramBuilder \\%s%s */', PHP_EOL, $nodeClass, PHP_EOL);
$methodBuilder->setDocComment($paramDocBlock);
$attributeAwareClassName = $this->attributeClassNaming->createAttributeAwareClassName($nodeClass);
$new = new New_(new FullyQualified($attributeAwareClassName));
// complete new args
$this->completeNewArgs($new, $nodeClass);
$methodBuilder->addStmt(new Return_($new));
return $methodBuilder->getNode();
}
private function createClassReference(string $nodeClass): ClassConstFetch
{
return new ClassConstFetch(new FullyQualified($nodeClass), 'class');
}
private function createIsAFuncCall(string $nodeClass): FuncCall
{
$variable = new Variable(self::NODE);
$constFetch = new ConstFetch(new Name('true'));
$args = [new Arg($variable), new Arg($this->createClassReference($nodeClass)), new Arg($constFetch)];
return new FuncCall(new Name('is_a'), $args);
}
private function completeNewArgs(New_ $new, string $phpDocParserNodeClass): void
{
// ...
$reflectionClass = new ReflectionClass($phpDocParserNodeClass);
$constructorReflectionMethod = $reflectionClass->getConstructor();
// no constructor → no params to add
if ($constructorReflectionMethod === null) {
return;
}
$phpDocParserNodeVariable = new Variable(self::NODE);
foreach ($constructorReflectionMethod->getParameters() as $reflectionParameter) {
$parameterName = $reflectionParameter->getName();
$new->args[] = new Arg(new PropertyFetch($phpDocParserNodeVariable, $parameterName));
}
}
}

View File

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Utils\PHPStanAttributeTypeSyncer\ValueObject;
final class Paths
{
/**
* @var string
*/
public const NAMESPACE_PHPDOC_NODE = 'Rector\AttributeAwarePhpDoc\Ast\PhpDoc';
/**
* @var string
*/
public const NAMESPACE_TYPE_NODE = 'Rector\AttributeAwarePhpDoc\Ast\Type';
/**
* @var string
*/
public const NAMESPACE_PHPDOC_NODE_FACTORY = 'Rector\AttributeAwarePhpDoc\AttributeAwareNodeFactory\PhpDoc';
/**
* @var string
*/
public const NAMESPACE_TYPE_NODE_FACTORY = 'Rector\AttributeAwarePhpDoc\AttributeAwareNodeFactory\Type';
}