Updated Rector to commit 9679ed6d77

9679ed6d77 [DeadCode] Skip using coealesce assign operator on return on RemoveUnusedPrivatePropertyRector (#2476)
This commit is contained in:
Tomas Votruba 2022-06-11 12:21:18 +00:00
parent 6e209432c2
commit 9cf6755b1b
20 changed files with 365 additions and 173 deletions

View File

@ -77,12 +77,12 @@ final class ReadWritePropertyAnalyzer
if ($parent instanceof AssignOp) {
return \true;
}
if ($parent instanceof ArrayDimFetch && $parent->dim === $node && $this->isNotInsideIssetUnset($parent)) {
return $this->isArrayDimFetchRead($parent);
}
if (!$parent instanceof ArrayDimFetch) {
return !$this->assignManipulator->isLeftPartOfAssign($node);
}
if ($parent->dim === $node && $this->isNotInsideIssetUnset($parent)) {
return $this->isArrayDimFetchRead($parent);
}
if ($this->assignManipulator->isLeftPartOfAssign($parent)) {
return \false;
}

View File

@ -76,7 +76,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node) : ?Node
{
$hasChanged = \false;
$hasRemoved = \false;
foreach ($node->getProperties() as $property) {
if ($this->shouldSkipProperty($property)) {
continue;
@ -84,10 +84,14 @@ CODE_SAMPLE
if ($this->propertyManipulator->isPropertyUsedInReadContext($node, $property)) {
continue;
}
$this->complexNodeRemover->removePropertyAndUsages($node, $property, $this->removeAssignSideEffect);
$hasChanged = \true;
// use different variable to avoid re-assign back $hasRemoved to false
// when already asssigned to true
$isRemoved = $this->complexNodeRemover->removePropertyAndUsages($node, $property, $this->removeAssignSideEffect);
if ($isRemoved) {
$hasRemoved = \true;
}
}
return $hasChanged ? $node : null;
return $hasRemoved ? $node : null;
}
private function shouldSkipProperty(Property $property) : bool
{

View File

@ -16,11 +16,13 @@ use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\ValueObject\MethodName;
use Rector\DeadCode\SideEffect\SideEffectNodeDetector;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeRemoval\NodeRemover;
use Rector\NodeTypeResolver\Node\AttributeKey;
use RectorPrefix20220611\Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class ComplexNodeRemover
{
@ -54,7 +56,12 @@ final class ComplexNodeRemover
* @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
*/
private $propertyFetchAnalyzer;
public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, NodeRemover $nodeRemover, SideEffectNodeDetector $sideEffectNodeDetector, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, PropertyFetchAnalyzer $propertyFetchAnalyzer)
/**
* @readonly
* @var \Rector\Core\PhpParser\Comparing\NodeComparator
*/
private $nodeComparator;
public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, NodeRemover $nodeRemover, SideEffectNodeDetector $sideEffectNodeDetector, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, PropertyFetchAnalyzer $propertyFetchAnalyzer, NodeComparator $nodeComparator)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->betterNodeFinder = $betterNodeFinder;
@ -62,13 +69,13 @@ final class ComplexNodeRemover
$this->sideEffectNodeDetector = $sideEffectNodeDetector;
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
$this->nodeComparator = $nodeComparator;
}
public function removePropertyAndUsages(Class_ $class, Property $property, bool $removeAssignSideEffect) : void
public function removePropertyAndUsages(Class_ $class, Property $property, bool $removeAssignSideEffect) : bool
{
$propertyName = $this->nodeNameResolver->getName($property);
$hasSideEffect = \false;
$isPartOfAnotherAssign = \false;
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($class->stmts, function (Node $node) use($removeAssignSideEffect, $propertyName, &$hasSideEffect, &$isPartOfAnotherAssign) {
$totalPropertyFetch = $this->propertyFetchAnalyzer->countLocalPropertyFetchName($class, $propertyName);
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($class->stmts, function (Node $node) use($removeAssignSideEffect, $propertyName, &$totalPropertyFetch) : ?Node {
// here should be checked all expr like stmts that can hold assign, e.f. if, foreach etc. etc.
if (!$node instanceof Expression) {
return null;
@ -81,33 +88,38 @@ final class ComplexNodeRemover
$assign = $nodeExpr;
// skip double assigns
if ($assign->expr instanceof Assign) {
$isPartOfAnotherAssign = \true;
return null;
}
$originalNode = $assign->getAttribute(AttributeKey::ORIGINAL_NODE);
if (!$this->nodeComparator->areNodesEqual($originalNode, $assign)) {
return null;
}
$propertyFetches = $this->resolvePropertyFetchFromDimFetch($assign->var);
if ($propertyFetches === []) {
return null;
}
$currentTotalPropertyFetch = $totalPropertyFetch;
foreach ($propertyFetches as $propertyFetch) {
if ($this->nodeNameResolver->isName($propertyFetch->name, $propertyName)) {
if (!$removeAssignSideEffect && $this->sideEffectNodeDetector->detect($assign->expr)) {
$hasSideEffect = \true;
return null;
}
$this->nodeRemover->removeNode($node);
--$totalPropertyFetch;
}
}
if ($totalPropertyFetch < $currentTotalPropertyFetch) {
$this->nodeRemover->removeNode($node);
return $node;
}
return null;
});
// do not remove anyhting in case of side-effect
if ($hasSideEffect) {
return;
}
if ($isPartOfAnotherAssign) {
return;
// not all property fetch with name removed
if ($totalPropertyFetch > 0) {
return \false;
}
$this->removeConstructorDependency($class, $propertyName);
$this->nodeRemover->removeNode($property);
return \true;
}
/**
* @param Param[] $params

View File

@ -16,11 +16,11 @@ final class VersionResolver
/**
* @var string
*/
public const PACKAGE_VERSION = 'a8dae7ff8ffaf1a1c80c54d64d9a9eb1cc21a886';
public const PACKAGE_VERSION = '9679ed6d77dcb4061aef35b8e4fa778217d466e8';
/**
* @var string
*/
public const RELEASE_DATE = '2022-06-11 13:54:48';
public const RELEASE_DATE = '2022-06-11 14:14:26';
/**
* @var int
*/

View File

@ -22,6 +22,7 @@ use Rector\Core\PhpParser\AstResolver;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeNameResolver\NodeNameResolver;
use RectorPrefix20220611\Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class PropertyFetchAnalyzer
{
/**
@ -43,11 +44,17 @@ final class PropertyFetchAnalyzer
* @var \Rector\Core\PhpParser\AstResolver
*/
private $astResolver;
public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, AstResolver $astResolver)
/**
* @readonly
* @var \Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser
*/
private $simpleCallableNodeTraverser;
public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, AstResolver $astResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->betterNodeFinder = $betterNodeFinder;
$this->astResolver = $astResolver;
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
}
public function isLocalPropertyFetch(Node $node) : bool
{
@ -73,10 +80,38 @@ final class PropertyFetchAnalyzer
/** @var PropertyFetch|StaticPropertyFetch $node */
return $this->nodeNameResolver->isName($node->name, $desiredPropertyName);
}
public function countLocalPropertyFetchName(ClassLike $classLike, string $propertyName) : int
{
$total = 0;
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($classLike->stmts, function (Node $subNode) use($classLike, $propertyName, &$total) : ?Node {
if (!$this->isLocalPropertyFetchName($subNode, $propertyName)) {
return null;
}
$parentClassLike = $this->betterNodeFinder->findParentType($subNode, ClassLike::class);
// property fetch in Trait cannot get parent ClassLike
if (!$parentClassLike instanceof ClassLike) {
++$total;
}
if ($parentClassLike === $classLike) {
++$total;
}
return $subNode;
});
return $total;
}
public function containsLocalPropertyFetchName(Node $node, string $propertyName) : bool
{
return (bool) $this->betterNodeFinder->findFirst($node, function (Node $node) use($propertyName) : bool {
return $this->isLocalPropertyFetchName($node, $propertyName);
$classLike = $node instanceof ClassLike ? $node : $this->betterNodeFinder->findParentType($node, ClassLike::class);
return (bool) $this->betterNodeFinder->findFirst($node, function (Node $node) use($classLike, $propertyName) : bool {
if (!$this->isLocalPropertyFetchName($node, $propertyName)) {
return \false;
}
$parentClassLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
// property fetch in Trait cannot get parent ClassLike
if (!$parentClassLike instanceof ClassLike) {
return \true;
}
return $parentClassLike === $classLike;
});
}
/**

2
vendor/autoload.php vendored
View File

@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitb36ebaf2a6f968d6abf092d6a46e04ea::getLoader();
return ComposerAutoloaderInitee7b259754326c29dc8e86aed55a5a42::getLoader();

View File

@ -2770,7 +2770,8 @@ return array(
'Rector\\Symfony\\Exception\\XmlContainerNotExistsException' => $vendorDir . '/rector/rector-symfony/src/Exception/XmlContainerNotExistsException.php',
'Rector\\Symfony\\FormHelper\\FormTypeStringToTypeProvider' => $vendorDir . '/rector/rector-symfony/src/FormHelper/FormTypeStringToTypeProvider.php',
'Rector\\Symfony\\Helper\\TemplateGuesser' => $vendorDir . '/rector/rector-symfony/src/Helper/TemplateGuesser.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\ConstraintAnnotationResolver' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/ConstraintAnnotationResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\MethodCallAnnotationAssertResolver' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/MethodCallAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\PropertyAnnotationAssertResolver' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/PropertyAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\DependencyInjectionMethodCallAnalyzer' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/DependencyInjectionMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormAddMethodCallAnalyzer' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/FormAddMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormCollectionAnalyzer' => $vendorDir . '/rector/rector-symfony/src/NodeAnalyzer/FormCollectionAnalyzer.php',
@ -2878,12 +2879,14 @@ return array(
'Rector\\Symfony\\TypeAnalyzer\\JMSDITypeResolver' => $vendorDir . '/rector/rector-symfony/src/TypeAnalyzer/JMSDITypeResolver.php',
'Rector\\Symfony\\TypeDeclaration\\ReturnTypeDeclarationUpdater' => $vendorDir . '/rector/rector-symfony/src/TypeDeclaration/ReturnTypeDeclarationUpdater.php',
'Rector\\Symfony\\ValueObjectFactory\\ServiceMapFactory' => $vendorDir . '/rector/rector-symfony/src/ValueObjectFactory/ServiceMapFactory.php',
'Rector\\Symfony\\ValueObject\\ClassMethodAndAnnotation' => $vendorDir . '/rector/rector-symfony/src/ValueObject/ClassMethodAndAnnotation.php',
'Rector\\Symfony\\ValueObject\\ConstantMap\\SymfonyRequestConstantMap' => $vendorDir . '/rector/rector-symfony/src/ValueObject/ConstantMap/SymfonyRequestConstantMap.php',
'Rector\\Symfony\\ValueObject\\ConstantMap\\SymfonyResponseConstantMap' => $vendorDir . '/rector/rector-symfony/src/ValueObject/ConstantMap/SymfonyResponseConstantMap.php',
'Rector\\Symfony\\ValueObject\\EventNameToClassAndConstant' => $vendorDir . '/rector/rector-symfony/src/ValueObject/EventNameToClassAndConstant.php',
'Rector\\Symfony\\ValueObject\\EventReferenceToMethodName' => $vendorDir . '/rector/rector-symfony/src/ValueObject/EventReferenceToMethodName.php',
'Rector\\Symfony\\ValueObject\\EventReferenceToMethodNameWithPriority' => $vendorDir . '/rector/rector-symfony/src/ValueObject/EventReferenceToMethodNameWithPriority.php',
'Rector\\Symfony\\ValueObject\\InvokableController\\ActiveClassElements' => $vendorDir . '/rector/rector-symfony/src/ValueObject/InvokableController/ActiveClassElements.php',
'Rector\\Symfony\\ValueObject\\PropertyAndAnnotation' => $vendorDir . '/rector/rector-symfony/src/ValueObject/PropertyAndAnnotation.php',
'Rector\\Symfony\\ValueObject\\ReplaceServiceArgument' => $vendorDir . '/rector/rector-symfony/src/ValueObject/ReplaceServiceArgument.php',
'Rector\\Symfony\\ValueObject\\ServiceDefinition' => $vendorDir . '/rector/rector-symfony/src/ValueObject/ServiceDefinition.php',
'Rector\\Symfony\\ValueObject\\ServiceMap\\ServiceMap' => $vendorDir . '/rector/rector-symfony/src/ValueObject/ServiceMap/ServiceMap.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitb36ebaf2a6f968d6abf092d6a46e04ea
class ComposerAutoloaderInitee7b259754326c29dc8e86aed55a5a42
{
private static $loader;
@ -22,19 +22,19 @@ class ComposerAutoloaderInitb36ebaf2a6f968d6abf092d6a46e04ea
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitb36ebaf2a6f968d6abf092d6a46e04ea', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInitee7b259754326c29dc8e86aed55a5a42', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitb36ebaf2a6f968d6abf092d6a46e04ea', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInitee7b259754326c29dc8e86aed55a5a42', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInitee7b259754326c29dc8e86aed55a5a42::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$includeFiles = \Composer\Autoload\ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea::$files;
$includeFiles = \Composer\Autoload\ComposerStaticInitee7b259754326c29dc8e86aed55a5a42::$files;
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequireb36ebaf2a6f968d6abf092d6a46e04ea($fileIdentifier, $file);
composerRequireee7b259754326c29dc8e86aed55a5a42($fileIdentifier, $file);
}
return $loader;
@ -46,7 +46,7 @@ class ComposerAutoloaderInitb36ebaf2a6f968d6abf092d6a46e04ea
* @param string $file
* @return void
*/
function composerRequireb36ebaf2a6f968d6abf092d6a46e04ea($fileIdentifier, $file)
function composerRequireee7b259754326c29dc8e86aed55a5a42($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea
class ComposerStaticInitee7b259754326c29dc8e86aed55a5a42
{
public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
@ -3071,7 +3071,8 @@ class ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea
'Rector\\Symfony\\Exception\\XmlContainerNotExistsException' => __DIR__ . '/..' . '/rector/rector-symfony/src/Exception/XmlContainerNotExistsException.php',
'Rector\\Symfony\\FormHelper\\FormTypeStringToTypeProvider' => __DIR__ . '/..' . '/rector/rector-symfony/src/FormHelper/FormTypeStringToTypeProvider.php',
'Rector\\Symfony\\Helper\\TemplateGuesser' => __DIR__ . '/..' . '/rector/rector-symfony/src/Helper/TemplateGuesser.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\ConstraintAnnotationResolver' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/ConstraintAnnotationResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\MethodCallAnnotationAssertResolver' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/MethodCallAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\Annotations\\PropertyAnnotationAssertResolver' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/Annotations/PropertyAnnotationAssertResolver.php',
'Rector\\Symfony\\NodeAnalyzer\\DependencyInjectionMethodCallAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/DependencyInjectionMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormAddMethodCallAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/FormAddMethodCallAnalyzer.php',
'Rector\\Symfony\\NodeAnalyzer\\FormCollectionAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/NodeAnalyzer/FormCollectionAnalyzer.php',
@ -3179,12 +3180,14 @@ class ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea
'Rector\\Symfony\\TypeAnalyzer\\JMSDITypeResolver' => __DIR__ . '/..' . '/rector/rector-symfony/src/TypeAnalyzer/JMSDITypeResolver.php',
'Rector\\Symfony\\TypeDeclaration\\ReturnTypeDeclarationUpdater' => __DIR__ . '/..' . '/rector/rector-symfony/src/TypeDeclaration/ReturnTypeDeclarationUpdater.php',
'Rector\\Symfony\\ValueObjectFactory\\ServiceMapFactory' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObjectFactory/ServiceMapFactory.php',
'Rector\\Symfony\\ValueObject\\ClassMethodAndAnnotation' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/ClassMethodAndAnnotation.php',
'Rector\\Symfony\\ValueObject\\ConstantMap\\SymfonyRequestConstantMap' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/ConstantMap/SymfonyRequestConstantMap.php',
'Rector\\Symfony\\ValueObject\\ConstantMap\\SymfonyResponseConstantMap' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/ConstantMap/SymfonyResponseConstantMap.php',
'Rector\\Symfony\\ValueObject\\EventNameToClassAndConstant' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/EventNameToClassAndConstant.php',
'Rector\\Symfony\\ValueObject\\EventReferenceToMethodName' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/EventReferenceToMethodName.php',
'Rector\\Symfony\\ValueObject\\EventReferenceToMethodNameWithPriority' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/EventReferenceToMethodNameWithPriority.php',
'Rector\\Symfony\\ValueObject\\InvokableController\\ActiveClassElements' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/InvokableController/ActiveClassElements.php',
'Rector\\Symfony\\ValueObject\\PropertyAndAnnotation' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/PropertyAndAnnotation.php',
'Rector\\Symfony\\ValueObject\\ReplaceServiceArgument' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/ReplaceServiceArgument.php',
'Rector\\Symfony\\ValueObject\\ServiceDefinition' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/ServiceDefinition.php',
'Rector\\Symfony\\ValueObject\\ServiceMap\\ServiceMap' => __DIR__ . '/..' . '/rector/rector-symfony/src/ValueObject/ServiceMap/ServiceMap.php',
@ -3390,9 +3393,9 @@ class ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitb36ebaf2a6f968d6abf092d6a46e04ea::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInitee7b259754326c29dc8e86aed55a5a42::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitee7b259754326c29dc8e86aed55a5a42::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitee7b259754326c29dc8e86aed55a5a42::$classMap;
}, null, ClassLoader::class);
}

View File

@ -2347,12 +2347,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-symfony.git",
"reference": "36747ba4063abc3fa60df3fb96679183a8b1cbb3"
"reference": "86505d3316684056b2c91abcaa547b2caf15d2c0"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/36747ba4063abc3fa60df3fb96679183a8b1cbb3",
"reference": "36747ba4063abc3fa60df3fb96679183a8b1cbb3",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/86505d3316684056b2c91abcaa547b2caf15d2c0",
"reference": "86505d3316684056b2c91abcaa547b2caf15d2c0",
"shasum": ""
},
"require": {
@ -2381,7 +2381,7 @@
"symplify\/rule-doc-generator": "^10.2",
"symplify\/vendor-patches": "^10.2"
},
"time": "2022-06-08T10:01:46+00:00",
"time": "2022-06-11T12:14:45+00:00",
"default-branch": true,
"type": "rector-extension",
"extra": {

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ namespace Rector\RectorInstaller;
*/
final class GeneratedConfig
{
public const EXTENSIONS = array('rector/rector-cakephp' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-cakephp', 'relative_install_path' => '../../rector-cakephp', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main f84ea17'), 'rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main b695bf6'), 'rector/rector-generator' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-generator', 'relative_install_path' => '../../rector-generator', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 623c9e2'), 'rector/rector-laravel' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-laravel', 'relative_install_path' => '../../rector-laravel', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 1194b1b'), 'rector/rector-nette' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-nette', 'relative_install_path' => '../../rector-nette', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main f29fa56'), 'rector/rector-phpoffice' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpoffice', 'relative_install_path' => '../../rector-phpoffice', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 15ee440'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main b220a7f'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 36747ba'));
public const EXTENSIONS = array('rector/rector-cakephp' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-cakephp', 'relative_install_path' => '../../rector-cakephp', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main f84ea17'), 'rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main b695bf6'), 'rector/rector-generator' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-generator', 'relative_install_path' => '../../rector-generator', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 623c9e2'), 'rector/rector-laravel' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-laravel', 'relative_install_path' => '../../rector-laravel', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 1194b1b'), 'rector/rector-nette' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-nette', 'relative_install_path' => '../../rector-nette', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main f29fa56'), 'rector/rector-phpoffice' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpoffice', 'relative_install_path' => '../../rector-phpoffice', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 15ee440'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main b220a7f'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => array('includes' => array(0 => 'config/config.php')), 'version' => 'dev-main 86505d3'));
private function __construct()
{
}

View File

@ -1,98 +0,0 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\NodeAnalyzer\Annotations;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\Symfony\NodeFactory\Annotations\DoctrineAnnotationFromNewFactory;
final class ConstraintAnnotationResolver
{
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\Value\ValueResolver
*/
private $valueResolver;
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
*/
private $betterNodeFinder;
/**
* @readonly
* @var \Rector\Symfony\NodeFactory\Annotations\DoctrineAnnotationFromNewFactory
*/
private $doctrineAnnotationFromNewFactory;
public function __construct(NodeNameResolver $nodeNameResolver, ValueResolver $valueResolver, BetterNodeFinder $betterNodeFinder, DoctrineAnnotationFromNewFactory $doctrineAnnotationFromNewFactory)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->valueResolver = $valueResolver;
$this->betterNodeFinder = $betterNodeFinder;
$this->doctrineAnnotationFromNewFactory = $doctrineAnnotationFromNewFactory;
}
/**
* @return array<string, DoctrineAnnotationTagValueNode>
*/
public function resolvePropertyTagValueNodes(ClassMethod $classMethod) : array
{
$constraintsMethodCalls = $this->findMethodCallsByName($classMethod, 'addPropertyConstraint');
$annotationsToPropertyNames = [];
foreach ($constraintsMethodCalls as $constraintMethodCall) {
$args = $constraintMethodCall->getArgs();
$constraintsExpr = $args[1]->value;
$propertyName = $this->valueResolver->getValue($args[0]->value);
if (!\is_string($propertyName)) {
continue;
}
if (!$constraintsExpr instanceof New_) {
// nothing we can do... or can we?
continue;
}
$assertTagValueNode = $this->doctrineAnnotationFromNewFactory->create($constraintsExpr);
$annotationsToPropertyNames[$propertyName] = $assertTagValueNode;
}
return $annotationsToPropertyNames;
}
/**
* @return array<string, DoctrineAnnotationTagValueNode>
*/
public function resolveGetterTagValueNodes(ClassMethod $classMethod) : array
{
$constraintsMethodCalls = $this->findMethodCallsByName($classMethod, 'addGetterConstraint');
$annotationsToMethodNames = [];
foreach ($constraintsMethodCalls as $constraintMethodCall) {
$args = $constraintMethodCall->getArgs();
$firstArgValue = $args[0]->value;
$propertyName = $this->valueResolver->getValue($firstArgValue);
$getterMethodName = 'get' . \ucfirst($propertyName);
$secondArgValue = $args[1]->value;
if (!$secondArgValue instanceof New_) {
// nothing we can do... or can we?
continue;
}
$assertTagValueNode = $this->doctrineAnnotationFromNewFactory->create($secondArgValue);
$annotationsToMethodNames[$getterMethodName] = $assertTagValueNode;
}
return $annotationsToMethodNames;
}
/**
* @return MethodCall[]
*/
private function findMethodCallsByName(ClassMethod $classMethod, string $methodName) : array
{
$methodCalls = $this->betterNodeFinder->findInstanceOf($classMethod, MethodCall::class);
return \array_filter($methodCalls, function (MethodCall $methodCall) use($methodName) : bool {
return $this->nodeNameResolver->isName($methodCall->name, $methodName);
});
}
}

View File

@ -0,0 +1,61 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\NodeAnalyzer\Annotations;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\Symfony\NodeFactory\Annotations\DoctrineAnnotationFromNewFactory;
use Rector\Symfony\ValueObject\ClassMethodAndAnnotation;
final class MethodCallAnnotationAssertResolver
{
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\Value\ValueResolver
*/
private $valueResolver;
/**
* @readonly
* @var \Rector\Symfony\NodeFactory\Annotations\DoctrineAnnotationFromNewFactory
*/
private $doctrineAnnotationFromNewFactory;
public function __construct(NodeNameResolver $nodeNameResolver, ValueResolver $valueResolver, DoctrineAnnotationFromNewFactory $doctrineAnnotationFromNewFactory)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->valueResolver = $valueResolver;
$this->doctrineAnnotationFromNewFactory = $doctrineAnnotationFromNewFactory;
}
public function resolve(Stmt $stmt) : ?ClassMethodAndAnnotation
{
if (!$stmt instanceof Expression) {
return null;
}
if (!$stmt->expr instanceof MethodCall) {
return null;
}
$methodCall = $stmt->expr;
if (!$this->nodeNameResolver->isName($methodCall->name, 'addGetterConstraint')) {
return null;
}
$args = $methodCall->getArgs();
$firstArgValue = $args[0]->value;
$propertyName = $this->valueResolver->getValue($firstArgValue);
$getterMethodName = 'get' . \ucfirst($propertyName);
$secondArgValue = $args[1]->value;
if (!$secondArgValue instanceof New_) {
// nothing we can do... or can we?
return null;
}
$doctrineAnnotationTagValueNode = $this->doctrineAnnotationFromNewFactory->create($secondArgValue);
return new ClassMethodAndAnnotation($getterMethodName, $doctrineAnnotationTagValueNode);
}
}

View File

@ -0,0 +1,62 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\NodeAnalyzer\Annotations;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\Symfony\NodeFactory\Annotations\DoctrineAnnotationFromNewFactory;
use Rector\Symfony\ValueObject\PropertyAndAnnotation;
final class PropertyAnnotationAssertResolver
{
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\Value\ValueResolver
*/
private $valueResolver;
/**
* @readonly
* @var \Rector\Symfony\NodeFactory\Annotations\DoctrineAnnotationFromNewFactory
*/
private $doctrineAnnotationFromNewFactory;
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(ValueResolver $valueResolver, DoctrineAnnotationFromNewFactory $doctrineAnnotationFromNewFactory, NodeNameResolver $nodeNameResolver)
{
$this->valueResolver = $valueResolver;
$this->doctrineAnnotationFromNewFactory = $doctrineAnnotationFromNewFactory;
$this->nodeNameResolver = $nodeNameResolver;
}
public function resolve(Stmt $stmt) : ?PropertyAndAnnotation
{
if (!$stmt instanceof Expression) {
return null;
}
if (!$stmt->expr instanceof MethodCall) {
return null;
}
$methodCall = $stmt->expr;
if (!$this->nodeNameResolver->isName($methodCall->name, 'addPropertyConstraint')) {
return null;
}
$args = $methodCall->getArgs();
$constraintsExpr = $args[1]->value;
$propertyName = $this->valueResolver->getValue($args[0]->value);
if (!\is_string($propertyName)) {
return null;
}
if (!$constraintsExpr instanceof New_) {
// nothing we can do... or can we?
return null;
}
$doctrineAnnotationTagValueNode = $this->doctrineAnnotationFromNewFactory->create($constraintsExpr);
return new PropertyAndAnnotation($propertyName, $doctrineAnnotationTagValueNode);
}
}

View File

@ -6,6 +6,7 @@ namespace Rector\Symfony\NodeFactory\Annotations;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use Rector\BetterPhpDocParser\ValueObject\PhpDoc\DoctrineAnnotation\CurlyListNode;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
final class DoctrineAnnotationKeyToValuesResolver
{
@ -31,9 +32,7 @@ final class DoctrineAnnotationKeyToValuesResolver
}
$key = $this->resolveKey($arrayItem);
$value = $this->valueResolver->getValue($arrayItem->value);
if (\is_string($value)) {
$value = '"' . $value . '"';
}
$value = $this->wrapStringValuesInQuotes($value, $key);
$annotationKeyToValues[$key] = $value;
}
}
@ -46,4 +45,24 @@ final class DoctrineAnnotationKeyToValuesResolver
}
return $this->valueResolver->getValue($arrayItem->key);
}
/**
* @return mixed
* @param mixed $value
*/
private function wrapStringValuesInQuotes($value, ?string $key)
{
if (\is_string($value)) {
return '"' . $value . '"';
}
if (\is_array($value)) {
// include quotes in groups
if ($key === 'groups') {
foreach ($value as $nestedKey => $nestedValue) {
$value[$nestedKey] = '"' . $nestedValue . '"';
}
}
return new CurlyListNode($value);
}
return $value;
}
}

View File

@ -54,15 +54,20 @@ final class CommandPropertyToAttributeRector extends AbstractRector implements M
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Add Symfony\\Component\\Console\\Attribute\\AsCommand to Symfony Commands and remove the deprecated properties', [new CodeSample(<<<'CODE_SAMPLE'
class SunshineCommand extends \Symfony\Component\Console\Command\Command
use Symfony\Component\Console\Command\Command;
final class SunshineCommand extends Command
{
/** @var string|null */
public static $defaultName = 'sunshine';
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
#[\Symfony\Component\Console\Attribute\AsCommand('sunshine')]
class SunshineCommand extends \Symfony\Component\Console\Command\Command
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
#[AsCommand('sunshine')]
final class SunshineCommand extends Command
{
}
CODE_SAMPLE

View File

@ -8,7 +8,10 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\Core\Rector\AbstractRector;
use Rector\Symfony\NodeAnalyzer\Annotations\ConstraintAnnotationResolver;
use Rector\Symfony\NodeAnalyzer\Annotations\MethodCallAnnotationAssertResolver;
use Rector\Symfony\NodeAnalyzer\Annotations\PropertyAnnotationAssertResolver;
use Rector\Symfony\ValueObject\ClassMethodAndAnnotation;
use Rector\Symfony\ValueObject\PropertyAndAnnotation;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
@ -21,12 +24,18 @@ final class LoadValidatorMetadataToAnnotationRector extends AbstractRector
{
/**
* @readonly
* @var \Rector\Symfony\NodeAnalyzer\Annotations\ConstraintAnnotationResolver
* @var \Rector\Symfony\NodeAnalyzer\Annotations\MethodCallAnnotationAssertResolver
*/
private $constraintAnnotationResolver;
public function __construct(ConstraintAnnotationResolver $constraintAnnotationResolver)
private $methodCallAnnotationAssertResolver;
/**
* @readonly
* @var \Rector\Symfony\NodeAnalyzer\Annotations\PropertyAnnotationAssertResolver
*/
private $propertyAnnotationAssertResolver;
public function __construct(MethodCallAnnotationAssertResolver $methodCallAnnotationAssertResolver, PropertyAnnotationAssertResolver $propertyAnnotationAssertResolver)
{
$this->constraintAnnotationResolver = $constraintAnnotationResolver;
$this->methodCallAnnotationAssertResolver = $methodCallAnnotationAssertResolver;
$this->propertyAnnotationAssertResolver = $propertyAnnotationAssertResolver;
}
public function getRuleDefinition() : RuleDefinition
{
@ -76,27 +85,40 @@ CODE_SAMPLE
if (!$loadValidatorMetadataClassMethod instanceof ClassMethod) {
return null;
}
// @todo extract annotations from loadValidatorMetadata()
$annotationsToMethodNames = $this->constraintAnnotationResolver->resolveGetterTagValueNodes($loadValidatorMetadataClassMethod);
foreach ($annotationsToMethodNames as $methodName => $doctrineTagValueNode) {
$classMethod = $node->getMethod($methodName);
if (!$classMethod instanceof ClassMethod) {
continue;
foreach ((array) $loadValidatorMetadataClassMethod->stmts as $stmtKey => $classStmt) {
$classMethodAndAnnotation = $this->methodCallAnnotationAssertResolver->resolve($classStmt);
if ($classMethodAndAnnotation instanceof ClassMethodAndAnnotation) {
$this->refactorClassMethodAndAnnotation($node, $classMethodAndAnnotation, $loadValidatorMetadataClassMethod, $stmtKey);
}
$getterPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
$getterPhpDocInfo->addTagValueNode($doctrineTagValueNode);
}
$annotationsToPropertyNames = $this->constraintAnnotationResolver->resolvePropertyTagValueNodes($loadValidatorMetadataClassMethod);
foreach ($annotationsToPropertyNames as $propertyName => $doctrineTagValueNode) {
$property = $node->getProperty($propertyName);
if (!$property instanceof Property) {
continue;
$propertyAndAnnotation = $this->propertyAnnotationAssertResolver->resolve($classStmt);
if ($propertyAndAnnotation instanceof PropertyAndAnnotation) {
$this->refactorPropertyAndAnnotation($node, $propertyAndAnnotation, $loadValidatorMetadataClassMethod, $stmtKey);
}
$propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$propertyPhpDocInfo->addTagValueNode($doctrineTagValueNode);
}
// in the end this should be only empty class method removal
$this->removeNode($loadValidatorMetadataClassMethod);
// remove empty class method
if ((array) $loadValidatorMetadataClassMethod->stmts === []) {
$this->removeNode($loadValidatorMetadataClassMethod);
}
return $node;
}
private function refactorClassMethodAndAnnotation(Class_ $class, ClassMethodAndAnnotation $classMethodAndAnnotation, ClassMethod $loadValidatorMetadataClassMethod, int $stmtKey) : void
{
$classMethod = $class->getMethod($classMethodAndAnnotation->getMethodName());
if (!$classMethod instanceof ClassMethod) {
return;
}
$getterPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
$getterPhpDocInfo->addTagValueNode($classMethodAndAnnotation->getDoctrineAnnotationTagValueNode());
unset($loadValidatorMetadataClassMethod->stmts[$stmtKey]);
}
private function refactorPropertyAndAnnotation(Class_ $class, PropertyAndAnnotation $propertyAndAnnotation, ClassMethod $loadValidatorMetadataClassMethod, int $stmtKey) : void
{
$property = $class->getProperty($propertyAndAnnotation->getProperty());
if (!$property instanceof Property) {
return;
}
$propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$propertyPhpDocInfo->addTagValueNode($propertyAndAnnotation->getDoctrineAnnotationTagValueNode());
unset($loadValidatorMetadataClassMethod->stmts[$stmtKey]);
}
}

View File

@ -0,0 +1,32 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\ValueObject;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
final class ClassMethodAndAnnotation
{
/**
* @readonly
* @var string
*/
private $methodName;
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode
*/
private $doctrineAnnotationTagValueNode;
public function __construct(string $methodName, DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode)
{
$this->methodName = $methodName;
$this->doctrineAnnotationTagValueNode = $doctrineAnnotationTagValueNode;
}
public function getMethodName() : string
{
return $this->methodName;
}
public function getDoctrineAnnotationTagValueNode() : DoctrineAnnotationTagValueNode
{
return $this->doctrineAnnotationTagValueNode;
}
}

View File

@ -0,0 +1,32 @@
<?php
declare (strict_types=1);
namespace Rector\Symfony\ValueObject;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
final class PropertyAndAnnotation
{
/**
* @readonly
* @var string
*/
private $property;
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode
*/
private $doctrineAnnotationTagValueNode;
public function __construct(string $property, DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode)
{
$this->property = $property;
$this->doctrineAnnotationTagValueNode = $doctrineAnnotationTagValueNode;
}
public function getProperty() : string
{
return $this->property;
}
public function getDoctrineAnnotationTagValueNode() : DoctrineAnnotationTagValueNode
{
return $this->doctrineAnnotationTagValueNode;
}
}