PHPStan updated and static fixes (#192)

This commit is contained in:
Tomas Votruba 2021-06-10 12:33:49 +02:00 committed by GitHub
parent 7bd6b3a0b9
commit 1a3afef04d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 512 additions and 612 deletions

View File

@ -181,18 +181,18 @@ Replaces defined map of arguments in defined methods and their calls.
- class: [`Rector\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector`](../rules/Arguments/Rector/ClassMethod/ArgumentDefaultValueReplacerRector.php)
```php
use Rector\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector;
use Rector\Arguments\ValueObject\ArgumentDefaultValueReplacer;
use Rector\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector;
use Rector\Arguments\ValueObject\ReplaceArgumentDefaultValue;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ArgumentDefaultValueReplacerRector::class)
$services->set(ReplaceArgumentDefaultValueRector::class)
->call('configure', [[
ArgumentDefaultValueReplacerRector::REPLACED_ARGUMENTS => ValueObjectInliner::inline([
new ArgumentDefaultValueReplacer('SomeExampleClass', 'someMethod', 0, 'SomeClass::OLD_CONSTANT', false),
ReplaceArgumentDefaultValueRector::REPLACED_ARGUMENTS => ValueObjectInliner::inline([
new ReplaceArgumentDefaultValue('SomeExampleClass', 'someMethod', 0, 'SomeClass::OLD_CONSTANT', false),
]),
]]);
};
@ -218,7 +218,7 @@ Streamline the operator arguments of version_compare function
```php
use Rector\Arguments\Rector\FuncCall\FunctionArgumentDefaultValueReplacerRector;
use Rector\Arguments\ValueObject\FuncCallArgumentDefaultValueReplacer;
use Rector\Arguments\ValueObject\ReplaceFuncCallArgumentDefaultValue;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
@ -228,7 +228,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(FunctionArgumentDefaultValueReplacerRector::class)
->call('configure', [[
FunctionArgumentDefaultValueReplacerRector::REPLACED_ARGUMENTS => ValueObjectInliner::inline([
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'gte', 'ge'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'),
]),
]]);
};

View File

@ -20,7 +20,7 @@
"nette/utils": "^3.2",
"nikic/php-parser": "4.10.5",
"phpstan/phpdoc-parser": "^0.5.4",
"phpstan/phpstan": ">=0.12.86 <=0.12.88",
"phpstan/phpstan": ">=0.12.86 <=0.12.89",
"phpstan/phpstan-phpunit": "^0.12.19",
"rector/extension-installer": "^0.10.2",
"rector/rector-cakephp": "^0.11.2",
@ -38,16 +38,16 @@
"symfony/http-kernel": "^5.3",
"symfony/process": "^5.3",
"symfony/yaml": "^5.3",
"symplify/astral": "^9.3.15",
"symplify/autowire-array-parameter": "^9.3.15",
"symplify/composer-json-manipulator": "^9.3.15",
"symplify/console-color-diff": "^9.3.15",
"symplify/package-builder": "^9.3.15",
"symplify/rule-doc-generator-contracts": "^9.3.15",
"symplify/simple-php-doc-parser": "^9.3.15",
"symplify/skipper": "^9.3.15",
"symplify/smart-file-system": "^9.3.10",
"symplify/symfony-php-config": "^9.3.10",
"symplify/astral": "^9.3.22",
"symplify/autowire-array-parameter": "^9.3.22",
"symplify/composer-json-manipulator": "^9.3.22",
"symplify/console-color-diff": "^9.3.22",
"symplify/package-builder": "^9.3.22",
"symplify/rule-doc-generator-contracts": "^9.3.22",
"symplify/simple-php-doc-parser": "^9.3.22",
"symplify/skipper": "^9.3.22",
"symplify/smart-file-system": "^9.3.22",
"symplify/symfony-php-config": "^9.3.22",
"tracy/tracy": "^2.8",
"webmozart/assert": "^1.10"
},
@ -57,13 +57,13 @@
"phpunit/phpunit": "^9.5",
"rector/rector-generator": "^0.1.7",
"rector/phpstan-rules": "^0.3",
"symplify/coding-standard": "^9.3.15",
"symplify/easy-ci": "^9.3.15",
"symplify/easy-coding-standard": "^9.3.15",
"symplify/easy-testing": "^9.3.15",
"symplify/phpstan-extensions": "^9.3.15",
"symplify/phpstan-rules": "^9.3.15",
"symplify/rule-doc-generator": "^9.3.15"
"symplify/coding-standard": "^9.3.22",
"symplify/easy-ci": "^9.3.22",
"symplify/easy-coding-standard": "^9.3.22",
"symplify/easy-testing": "^9.3.22",
"symplify/phpstan-extensions": "^9.3.22",
"symplify/phpstan-rules": "^9.3.22",
"symplify/rule-doc-generator": "^9.3.22"
},
"replace": {
"rector/rector": "self.version"

View File

@ -5,7 +5,7 @@ declare(strict_types=1);
use Rector\Arguments\Rector\ClassMethod\ArgumentAdderRector;
use Rector\Arguments\Rector\FuncCall\FunctionArgumentDefaultValueReplacerRector;
use Rector\Arguments\ValueObject\ArgumentAdder;
use Rector\Arguments\ValueObject\FuncCallArgumentDefaultValueReplacer;
use Rector\Arguments\ValueObject\ReplaceFuncCallArgumentDefaultValue;
use Rector\DeadCode\Rector\StaticCall\RemoveParentCallWithoutParentRector;
use Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector;
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
@ -97,15 +97,15 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(Rector\Arguments\Rector\FuncCall\FunctionArgumentDefaultValueReplacerRector::class)
->call('configure', [[
FunctionArgumentDefaultValueReplacerRector::REPLACED_ARGUMENTS => ValueObjectInliner::inline([
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'gte', 'ge'),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'lte', 'le'),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, '', '!='),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, '!', '!='),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'g', 'gt'),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'l', 'lt'),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'gte', 'ge'),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'lte', 'le'),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'n', 'ne'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, '', '!='),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, '!', '!='),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'g', 'gt'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'l', 'lt'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'n', 'ne'),
]),
]]);
};

View File

@ -9,7 +9,7 @@ use PhpParser\Node\AttributeGroup;
use Rector\PhpAttribute\Printer\PhpAttributeGroupFactory;
use Rector\Testing\PHPUnit\AbstractTestCase;
class PhpAttributeGroupFactoryTest extends AbstractTestCase
final class PhpAttributeGroupFactoryTest extends AbstractTestCase
{
private PhpAttributeGroupFactory $phpAttributeGroupFactory;
@ -24,20 +24,23 @@ class PhpAttributeGroupFactoryTest extends AbstractTestCase
{
$attributeGroup = $this->phpAttributeGroupFactory->createFromClassWithItems(
'Symfony\Component\Routing\Annotation\Route',
['path' => '/path', 'name' => 'action']
[
'path' => '/path',
'name' => 'action',
]
);
self::assertInstanceOf(AttributeGroup::class, $attributeGroup);
$this->assertInstanceOf(AttributeGroup::class, $attributeGroup);
}
public function testCreateArgsFromItems(): void
{
$method = new \ReflectionMethod($this->phpAttributeGroupFactory, 'createArgsFromItems');
$method->setAccessible(true);
$args = $method->invokeArgs($this->phpAttributeGroupFactory, [['path' => '/path', 'name' => 'action']]);
$args = $this->phpAttributeGroupFactory->createArgsFromItems([
'path' => '/path',
'name' => 'action',
]);
self::assertIsArray($args);
self::assertCount(2, $args);
self::assertContainsOnlyInstancesOf(Arg::class, $args);
$this->assertCount(2, $args);
$this->assertContainsOnlyInstancesOf(Arg::class, $args);
}
}

View File

@ -7,7 +7,7 @@ namespace Rector\ListReporting\Output;
use Rector\Core\Contract\Console\OutputStyleInterface;
use Rector\ListReporting\Contract\Output\ShowOutputFormatterInterface;
final class ConsoleOutputFormatter implements ShowOutputFormatterInterface
final class ConsoleShowOutputFormatter implements ShowOutputFormatterInterface
{
/**
* @var string

View File

@ -67,7 +67,7 @@ final class PhpAttributeGroupFactory
* @param mixed[] $items
* @return Arg[]
*/
private function createArgsFromItems(array $items, ?string $silentKey = null): array
public function createArgsFromItems(array $items, ?string $silentKey = null): array
{
$args = [];

View File

@ -12,7 +12,7 @@ use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class ReadExprAnalyzer
final class JustReadExprAnalyzer
{
public function isReadContext(Expr $expr): bool
{

View File

@ -12,7 +12,7 @@ use Rector\ReadWrite\NodeFinder\NodeUsageFinder;
final class PropertyFetchReadNodeAnalyzer implements ReadNodeAnalyzerInterface
{
public function __construct(
private ReadExprAnalyzer $readExprAnalyzer,
private JustReadExprAnalyzer $justReadExprAnalyzer,
private NodeUsageFinder $nodeUsageFinder
) {
}
@ -29,7 +29,7 @@ final class PropertyFetchReadNodeAnalyzer implements ReadNodeAnalyzerInterface
{
$propertyFetchUsages = $this->nodeUsageFinder->findPropertyFetchUsages($node);
foreach ($propertyFetchUsages as $propertyFetchUsage) {
if ($this->readExprAnalyzer->isReadContext($propertyFetchUsage)) {
if ($this->justReadExprAnalyzer->isReadContext($propertyFetchUsage)) {
return true;
}
}

View File

@ -15,7 +15,7 @@ final class VariableReadNodeAnalyzer implements ReadNodeAnalyzerInterface
public function __construct(
private ParentScopeFinder $parentScopeFinder,
private NodeUsageFinder $nodeUsageFinder,
private ReadExprAnalyzer $readExprAnalyzer
private JustReadExprAnalyzer $justReadExprAnalyzer
) {
}
@ -36,7 +36,7 @@ final class VariableReadNodeAnalyzer implements ReadNodeAnalyzerInterface
$variableUsages = $this->nodeUsageFinder->findVariableUsages((array) $parentScope->stmts, $node);
foreach ($variableUsages as $variableUsage) {
if ($this->readExprAnalyzer->isReadContext($variableUsage)) {
if ($this->justReadExprAnalyzer->isReadContext($variableUsage)) {
return true;
}
}

View File

@ -164,7 +164,6 @@ parameters:
paths:
- rules/Renaming/Rector/FileWithoutNamespace/PseudoNamespaceToNamespaceRector.php
- rules/CodeQuality/Rector/Concat/JoinStringConcatRector.php
- rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php
- packages/NodeNestingScope/NodeFinder/ScopeAwareNodeFinder.php
-
@ -309,11 +308,6 @@ parameters:
- '#Parameter \#1 \$stmts of method Rector\\EarlyReturn\\Rector\\Return_\\PreparedValueToEarlyReturnRector\:\:collectIfs\(\) expects array<PhpParser\\Node\\Stmt\\If_\>, array<PhpParser\\Node\\Stmt\> given#'
- '#Access to an undefined property PhpParser\\Node\\FunctionLike\|PhpParser\\Node\\Stmt\\If_\:\:\$stmts#'
-
message: '#Function "get_declared_classes\(\)" cannot be used/left in the code#'
paths:
- rules/Restoration/ClassMap/ExistingClassesProvider.php
-
message: '#Parameter \#1 \$types of method Rector\\Defluent\\NodeAnalyzer\\FluentCallStaticTypeResolver\:\:filterOutAlreadyPresentParentClasses\(\) expects array<class\-string\>, array<int, string\> given#'
paths:
@ -332,8 +326,6 @@ parameters:
paths:
- src/Console/Command/ProcessCommand.php
- '#Parameter \#2 \$returnedStrictTypeNode of method Rector\\TypeDeclaration\\Rector\\ClassMethod\\ReturnTypeFromStrictTypedCallRector\:\:refactorSingleReturnType\(\) expects PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType, PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PHPStan\\Type\\UnionType given#'
- '#(.*?) class\-string, string given#'
# part of refactor() API, node must be returned, or does bring any value
@ -342,11 +334,6 @@ parameters:
paths:
- '*Rector.php'
-
message: '#Cannot cast array<string\>\|string\|null to string#'
paths:
- utils/compiler/src/Command/DowngradePathsCommand.php
# PHP 7_4 literal syntax
- '#Property PhpParser\\Node\\Scalar\\DNumber\:\:\$value \(float\|int\) does not accept string#'
@ -414,21 +401,13 @@ parameters:
- '#Method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:findParentTypes\(\) should return T of PhpParser\\Node\|null but returns class\-string<T of PhpParser\\Node\>\|T of PhpParser\\Node#'
-
message: '#Assign in loop is not allowed#'
paths:
- rules/DowngradePhp72/NodeAnalyzer/ParamContravariantDetector.php
# doc typo in php-parser
- '#Parameter \#2 \$args of class PhpParser\\Node\\Expr\\FuncCall constructor expects array<PhpParser\\Node\\Arg\>, array<int, PhpParser\\Node\\Arg\|null\> given#'
- '#Class with base "(.*?)" name is already used in "Symplify\\(.*?)", "Rector\\(.*?)"\. Use unique name to make classes easy to recognize#'
# php-parser bug
- '#Parameter \#1 \$type of method PhpParser\\Builder\\FunctionLike\:\:setReturnType\(\) expects PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|string, PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType given#'
- '#Method Rector\\Core\\Tests\\DependencyInjection\\ConfigurableRectorImportConfigCallsMergeTest\:\:provideData\(\) return type has no value type specified in iterable type Iterator#'
- '#Class with base "PhpVersion" name is already used in "PHPStan\\Php\\PhpVersion", "Rector\\Core\\ValueObject\\PhpVersion"\. Use unique name to make classes easy to recognize#'
-
message: '#Use separate function calls with readable variable names#'
@ -446,8 +425,6 @@ parameters:
paths:
- rules/EarlyReturn/Rector/If_/ChangeAndIfToEarlyReturnRector.php
- '#Class with base "PhpVersionFactory" name is already used in "PHPStan\\Php\\PhpVersionFactory", "Rector\\Core\\Util\\PhpVersionFactory"\. Use unique name to make classes easy to recognize#'
-
message: '#Function "function_exists\(\)" cannot be used/left in the code#'
paths:
@ -466,7 +443,6 @@ parameters:
- '#Method Rector\\BetterPhpDocParser\\PhpDocParser\\BetterPhpDocParser\:\:parseChildAndStoreItsPositions\(\) should return PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode\|PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode but returns PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode#'
- '#Method Rector\\Core\\Application\\VersionResolver\:\:resolvePackageData\(\) return type has no value type specified in iterable type array#'
- '#Cognitive complexity for "Rector\\Core\\Rector\\AbstractRector\:\:enterNode\(\)" is \d+, keep it under 9#'
-

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\Fixture;
namespace Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\Fixture;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -15,7 +15,7 @@ function argumentDefalutValue()
-----
<?php
namespace Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\Fixture;
namespace Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\Fixture;
use Symfony\Component\DependencyInjection\ContainerBuilder;

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\Fixture;
namespace Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\Fixture;
use Symfony\Component\Yaml\Yaml;
@ -16,7 +16,7 @@ function argumentDefaultValue2()
-----
<?php
namespace Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\Fixture;
namespace Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\Fixture;
use Symfony\Component\Yaml\Yaml;

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\Fixture;
namespace Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\Fixture;
use Symfony\Component\Yaml\Yaml;
@ -15,7 +15,7 @@ function argumentDefaultValue3()
-----
<?php
namespace Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\Fixture;
namespace Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\Fixture;
use Symfony\Component\Yaml\Yaml;

View File

@ -2,13 +2,13 @@
declare(strict_types=1);
namespace Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector;
namespace Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class ArgumentDefaultValueReplacerRectorTest extends AbstractRectorTestCase
final class ReplaceArgumentDefaultValueRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()

View File

@ -2,46 +2,46 @@
declare(strict_types=1);
use Rector\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector;
use Rector\Arguments\ValueObject\ArgumentDefaultValueReplacer;
use Rector\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector;
use Rector\Arguments\ValueObject\ReplaceArgumentDefaultValue;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ArgumentDefaultValueReplacerRector::class)
$services->set(ReplaceArgumentDefaultValueRector::class)
->call('configure', [[
ArgumentDefaultValueReplacerRector::REPLACED_ARGUMENTS => ValueObjectInliner::inline([
ReplaceArgumentDefaultValueRector::REPLACED_ARGUMENTS => ValueObjectInliner::inline([
new ArgumentDefaultValueReplacer(
new ReplaceArgumentDefaultValue(
'Symfony\Component\DependencyInjection\Definition',
'setScope',
0,
'Symfony\Component\DependencyInjection\ContainerBuilder::SCOPE_PROTOTYPE',
false
),
new ArgumentDefaultValueReplacer('Symfony\Component\Yaml\Yaml', 'parse', 1, [
new ReplaceArgumentDefaultValue('Symfony\Component\Yaml\Yaml', 'parse', 1, [
false,
false,
true,
], 'Symfony\Component\Yaml\Yaml::PARSE_OBJECT_FOR_MAP'),
new ArgumentDefaultValueReplacer('Symfony\Component\Yaml\Yaml', 'parse', 1, [
new ReplaceArgumentDefaultValue('Symfony\Component\Yaml\Yaml', 'parse', 1, [
false,
true,
], 'Symfony\Component\Yaml\Yaml::PARSE_OBJECT'),
new ArgumentDefaultValueReplacer('Symfony\Component\Yaml\Yaml', 'parse', 1, false, 0),
new ArgumentDefaultValueReplacer(
new ReplaceArgumentDefaultValue('Symfony\Component\Yaml\Yaml', 'parse', 1, false, 0),
new ReplaceArgumentDefaultValue(
'Symfony\Component\Yaml\Yaml',
'parse',
1,
true,
'Symfony\Component\Yaml\Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE'
),
new ArgumentDefaultValueReplacer('Symfony\Component\Yaml\Yaml', 'dump', 3, [
new ReplaceArgumentDefaultValue('Symfony\Component\Yaml\Yaml', 'dump', 3, [
false,
true,
], 'Symfony\Component\Yaml\Yaml::DUMP_OBJECT'),
new ArgumentDefaultValueReplacer(
new ReplaceArgumentDefaultValue(
'Symfony\Component\Yaml\Yaml',
'dump',
3,

View File

@ -3,7 +3,7 @@
declare(strict_types=1);
use Rector\Arguments\Rector\FuncCall\FunctionArgumentDefaultValueReplacerRector;
use Rector\Arguments\ValueObject\FuncCallArgumentDefaultValueReplacer;
use Rector\Arguments\ValueObject\ReplaceFuncCallArgumentDefaultValue;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
@ -12,9 +12,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(FunctionArgumentDefaultValueReplacerRector::class)
->call('configure', [[
FunctionArgumentDefaultValueReplacerRector::REPLACED_ARGUMENTS => ValueObjectInliner::inline([
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'lte', 'le'),
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, '', '!='),
new FuncCallArgumentDefaultValueReplacer(
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'lte', 'le'),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, '', '!='),
new ReplaceFuncCallArgumentDefaultValue(
'some_function',
0,
true,

View File

@ -12,7 +12,7 @@ use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Arguments\Contract\ArgumentDefaultValueReplacerInterface;
use Rector\Arguments\Contract\ReplaceArgumentDefaultValueInterface;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
@ -29,14 +29,14 @@ final class ArgumentDefaultValueReplacer
*/
public function processReplaces(
Node $node,
ArgumentDefaultValueReplacerInterface $argumentDefaultValueReplacer
ReplaceArgumentDefaultValueInterface $replaceArgumentDefaultValue
): ?Node {
if ($node instanceof ClassMethod) {
if (! isset($node->params[$argumentDefaultValueReplacer->getPosition()])) {
if (! isset($node->params[$replaceArgumentDefaultValue->getPosition()])) {
return null;
}
} elseif (isset($node->args[$argumentDefaultValueReplacer->getPosition()])) {
$this->processArgs($node, $argumentDefaultValueReplacer);
} elseif (isset($node->args[$replaceArgumentDefaultValue->getPosition()])) {
$this->processArgs($node, $replaceArgumentDefaultValue);
}
return $node;
@ -45,18 +45,18 @@ final class ArgumentDefaultValueReplacer
/**
* @param MethodCall|StaticCall|FuncCall $expr
*/
private function processArgs(Expr $expr, ArgumentDefaultValueReplacerInterface $argumentDefaultValueReplacer): void
private function processArgs(Expr $expr, ReplaceArgumentDefaultValueInterface $replaceArgumentDefaultValue): void
{
$position = $argumentDefaultValueReplacer->getPosition();
$position = $replaceArgumentDefaultValue->getPosition();
$argValue = $this->valueResolver->getValue($expr->args[$position]->value);
if (is_scalar(
$argumentDefaultValueReplacer->getValueBefore()
) && $argValue === $argumentDefaultValueReplacer->getValueBefore()) {
$expr->args[$position] = $this->normalizeValueToArgument($argumentDefaultValueReplacer->getValueAfter());
} elseif (is_array($argumentDefaultValueReplacer->getValueBefore())) {
$newArgs = $this->processArrayReplacement($expr->args, $argumentDefaultValueReplacer);
$replaceArgumentDefaultValue->getValueBefore()
) && $argValue === $replaceArgumentDefaultValue->getValueBefore()) {
$expr->args[$position] = $this->normalizeValueToArgument($replaceArgumentDefaultValue->getValueAfter());
} elseif (is_array($replaceArgumentDefaultValue->getValueBefore())) {
$newArgs = $this->processArrayReplacement($expr->args, $replaceArgumentDefaultValue);
if ($newArgs) {
$expr->args = $newArgs;
@ -86,21 +86,21 @@ final class ArgumentDefaultValueReplacer
*/
private function processArrayReplacement(
array $argumentNodes,
ArgumentDefaultValueReplacerInterface $argumentDefaultValueReplacer
ReplaceArgumentDefaultValueInterface $replaceArgumentDefaultValue
): ?array {
$argumentValues = $this->resolveArgumentValuesToBeforeRecipe($argumentNodes, $argumentDefaultValueReplacer);
if ($argumentValues !== $argumentDefaultValueReplacer->getValueBefore()) {
$argumentValues = $this->resolveArgumentValuesToBeforeRecipe($argumentNodes, $replaceArgumentDefaultValue);
if ($argumentValues !== $replaceArgumentDefaultValue->getValueBefore()) {
return null;
}
if (is_string($argumentDefaultValueReplacer->getValueAfter())) {
$argumentNodes[$argumentDefaultValueReplacer->getPosition()] = $this->normalizeValueToArgument(
$argumentDefaultValueReplacer->getValueAfter()
if (is_string($replaceArgumentDefaultValue->getValueAfter())) {
$argumentNodes[$replaceArgumentDefaultValue->getPosition()] = $this->normalizeValueToArgument(
$replaceArgumentDefaultValue->getValueAfter()
);
// clear following arguments
$argumentCountToClear = count($argumentDefaultValueReplacer->getValueBefore());
for ($i = $argumentDefaultValueReplacer->getPosition() + 1; $i <= $argumentDefaultValueReplacer->getPosition() + $argumentCountToClear; ++$i) {
$argumentCountToClear = count($replaceArgumentDefaultValue->getValueBefore());
for ($i = $replaceArgumentDefaultValue->getPosition() + 1; $i <= $replaceArgumentDefaultValue->getPosition() + $argumentCountToClear; ++$i) {
unset($argumentNodes[$i]);
}
}
@ -114,20 +114,20 @@ final class ArgumentDefaultValueReplacer
*/
private function resolveArgumentValuesToBeforeRecipe(
array $argumentNodes,
ArgumentDefaultValueReplacerInterface $argumentDefaultValueReplacer
ReplaceArgumentDefaultValueInterface $replaceArgumentDefaultValue
): array {
$argumentValues = [];
/** @var mixed[] $valueBefore */
$valueBefore = $argumentDefaultValueReplacer->getValueBefore();
$valueBefore = $replaceArgumentDefaultValue->getValueBefore();
$beforeArgumentCount = count($valueBefore);
for ($i = 0; $i < $beforeArgumentCount; ++$i) {
if (! isset($argumentNodes[$argumentDefaultValueReplacer->getPosition() + $i])) {
if (! isset($argumentNodes[$replaceArgumentDefaultValue->getPosition() + $i])) {
continue;
}
$nextArg = $argumentNodes[$argumentDefaultValueReplacer->getPosition() + $i];
$nextArg = $argumentNodes[$replaceArgumentDefaultValue->getPosition() + $i];
$argumentValues[] = $this->valueResolver->getValue($nextArg->value);
}

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Rector\Arguments\Contract;
interface ArgumentDefaultValueReplacerInterface
interface ReplaceArgumentDefaultValueInterface
{
public function getPosition(): int;

View File

@ -8,7 +8,8 @@ use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Arguments\ValueObject\ArgumentDefaultValueReplacer;
use Rector\Arguments\ArgumentDefaultValueReplacer;
use Rector\Arguments\ValueObject\ReplaceArgumentDefaultValue;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@ -16,9 +17,9 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Webmozart\Assert\Assert;
/**
* @see \Rector\Tests\Arguments\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\ArgumentDefaultValueReplacerRectorTest
* @see \Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\ReplaceArgumentDefaultValueRectorTest
*/
final class ArgumentDefaultValueReplacerRector extends AbstractRector implements ConfigurableRectorInterface
final class ReplaceArgumentDefaultValueRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var string
@ -26,12 +27,12 @@ final class ArgumentDefaultValueReplacerRector extends AbstractRector implements
public const REPLACED_ARGUMENTS = 'replaced_arguments';
/**
* @var ArgumentDefaultValueReplacer[]
* @var ReplaceArgumentDefaultValue[]
*/
private array $replacedArguments = [];
public function __construct(
private \Rector\Arguments\ArgumentDefaultValueReplacer $argumentDefaultValueReplacer
private ArgumentDefaultValueReplacer $argumentDefaultValueReplacer
) {
}
@ -53,7 +54,7 @@ CODE_SAMPLE
,
[
self::REPLACED_ARGUMENTS => [
new ArgumentDefaultValueReplacer(
new ReplaceArgumentDefaultValue(
'SomeExampleClass',
'someMethod',
0,
@ -99,12 +100,12 @@ CODE_SAMPLE
}
/**
* @param array<string, ArgumentDefaultValueReplacer[]> $configuration
* @param array<string, ReplaceArgumentDefaultValue[]> $configuration
*/
public function configure(array $configuration): void
{
$replacedArguments = $configuration[self::REPLACED_ARGUMENTS] ?? [];
Assert::allIsInstanceOf($replacedArguments, ArgumentDefaultValueReplacer::class);
Assert::allIsInstanceOf($replacedArguments, ReplaceArgumentDefaultValue::class);
$this->replacedArguments = $replacedArguments;
}
}

View File

@ -7,7 +7,7 @@ namespace Rector\Arguments\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use Rector\Arguments\ArgumentDefaultValueReplacer;
use Rector\Arguments\ValueObject\FuncCallArgumentDefaultValueReplacer;
use Rector\Arguments\ValueObject\ReplaceFuncCallArgumentDefaultValue;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@ -28,7 +28,7 @@ final class FunctionArgumentDefaultValueReplacerRector extends AbstractRector im
public const REPLACED_ARGUMENTS = 'replaced_arguments';
/**
* @var FuncCallArgumentDefaultValueReplacer[]
* @var ReplaceFuncCallArgumentDefaultValue[]
*/
private mixed $replacedArguments = [];
@ -52,7 +52,7 @@ CODE_SAMPLE
,
[
self::REPLACED_ARGUMENTS => [
new FuncCallArgumentDefaultValueReplacer('version_compare', 2, 'gte', 'ge',),
new ReplaceFuncCallArgumentDefaultValue('version_compare', 2, 'gte', 'ge',),
],
]
),
@ -84,12 +84,12 @@ CODE_SAMPLE
}
/**
* @param array<string, FuncCallArgumentDefaultValueReplacer[]> $configuration
* @param array<string, ReplaceFuncCallArgumentDefaultValue[]> $configuration
*/
public function configure(array $configuration): void
{
$replacedArguments = $configuration[self::REPLACED_ARGUMENTS] ?? [];
Assert::allIsInstanceOf($replacedArguments, FuncCallArgumentDefaultValueReplacer::class);
Assert::allIsInstanceOf($replacedArguments, ReplaceFuncCallArgumentDefaultValue::class);
$this->replacedArguments = $replacedArguments;
}
}

View File

@ -5,9 +5,9 @@ declare(strict_types=1);
namespace Rector\Arguments\ValueObject;
use PHPStan\Type\ObjectType;
use Rector\Arguments\Contract\ArgumentDefaultValueReplacerInterface;
use Rector\Arguments\Contract\ReplaceArgumentDefaultValueInterface;
final class ArgumentDefaultValueReplacer implements ArgumentDefaultValueReplacerInterface
final class ReplaceArgumentDefaultValue implements ReplaceArgumentDefaultValueInterface
{
/**
* @param mixed $valueBefore

View File

@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Rector\Arguments\ValueObject;
use Rector\Arguments\Contract\ArgumentDefaultValueReplacerInterface;
use Rector\Arguments\Contract\ReplaceArgumentDefaultValueInterface;
final class FuncCallArgumentDefaultValueReplacer implements ArgumentDefaultValueReplacerInterface
final class ReplaceFuncCallArgumentDefaultValue implements ReplaceArgumentDefaultValueInterface
{
/**
* @param mixed $valueBefore

View File

@ -1,92 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\CodeQuality\NodeFactory;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\ClosureUse;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PHPStan\Reflection\FunctionVariantWithPhpDocs;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\Php\PhpMethodReflection;
use PHPStan\Type\MixedType;
use PHPStan\Type\VoidType;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class AnonymousFunctionFactory
{
public function __construct(
private NodeFactory $nodeFactory,
private NodeNameResolver $nodeNameResolver,
private StaticTypeMapper $staticTypeMapper
) {
}
/**
* @param Variable|PropertyFetch $expr
*/
public function create(PhpMethodReflection $phpMethodReflection, Expr $expr): Closure
{
/** @var FunctionVariantWithPhpDocs $functionVariantWithPhpDoc */
$functionVariantWithPhpDoc = $phpMethodReflection->getVariants()[0];
$anonymousFunction = new Closure();
$newParams = $this->createParams($functionVariantWithPhpDoc->getParameters());
$anonymousFunction->params = $newParams;
$innerMethodCall = new MethodCall($expr, $phpMethodReflection->getName());
$innerMethodCall->args = $this->nodeFactory->createArgsFromParams($newParams);
if (! $functionVariantWithPhpDoc->getReturnType() instanceof MixedType) {
$returnType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
$functionVariantWithPhpDoc->getReturnType()
);
$anonymousFunction->returnType = $returnType;
}
// does method return something?
if (! $functionVariantWithPhpDoc->getReturnType() instanceof VoidType) {
$anonymousFunction->stmts[] = new Return_($innerMethodCall);
} else {
$anonymousFunction->stmts[] = new Expression($innerMethodCall);
}
if ($expr instanceof Variable && ! $this->nodeNameResolver->isName($expr, 'this')) {
$anonymousFunction->uses[] = new ClosureUse($expr);
}
return $anonymousFunction;
}
/**
* @param ParameterReflection[] $parameterReflections
* @return Param[]
*/
private function createParams(array $parameterReflections): array
{
$params = [];
foreach ($parameterReflections as $parameterReflection) {
$param = new Param(new Variable($parameterReflection->getName()));
if (! $parameterReflection->getType() instanceof MixedType) {
$paramType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($parameterReflection->getType());
$param->type = $paramType;
}
$params[] = $param;
}
return $params;
}
}

View File

@ -14,9 +14,9 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\String_;
use PHPStan\Reflection\Php\PhpMethodReflection;
use Rector\CodeQuality\NodeAnalyzer\CallableClassMethodMatcher;
use Rector\CodeQuality\NodeFactory\AnonymousFunctionFactory;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php72\NodeFactory\AnonymousFunctionFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -125,7 +125,7 @@ CODE_SAMPLE
return null;
}
return $this->anonymousFunctionFactory->create($phpMethodReflection, $objectVariable);
return $this->anonymousFunctionFactory->createFromPhpMethodReflection($phpMethodReflection, $objectVariable);
}
private function shouldSkipArray(Array_ $array): bool

View File

@ -10,8 +10,8 @@ use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\For_;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\VariableNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php70\NodeAnalyzer\VariableNaming;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

View File

@ -20,8 +20,8 @@ use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\VariableNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php70\NodeAnalyzer\VariableNaming;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Traversable;

View File

@ -21,8 +21,8 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\VariableNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php70\NodeAnalyzer\VariableNaming;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

View File

@ -147,7 +147,7 @@ CODE_SAMPLE
$stmts = [];
if ($node instanceof Expression) {
/** @var Assign */
/** @var Assign $assign */
$assign = $node->expr;
$stmts[] = new Expression(new Assign($assign->var, $matchArm->body));
$stmts[] = new Break_();

View File

@ -13,8 +13,8 @@ use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Expr\Variable;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\VariableNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php70\NodeAnalyzer\VariableNaming;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

View File

@ -4,8 +4,10 @@ declare(strict_types=1);
namespace Rector\Naming\Naming;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\FuncCall;
@ -18,6 +20,7 @@ use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar;
use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\Scope;
use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
@ -31,15 +34,15 @@ final class VariableNaming
public function __construct(
private NodeNameResolver $nodeNameResolver,
private ValueResolver $valueResolver,
private NodeTypeResolver $nodeTypeResolver
private NodeTypeResolver $nodeTypeResolver,
) {
}
public function resolveFromNode(Node $node): ?string
{
$nodeType = $this->nodeTypeResolver->getStaticType($node);
return $this->resolveFromNodeAndType($node, $nodeType);
}
// public function resolveFromNode(Node $node): ?string
// {
// $nodeType = $this->nodeTypeResolver->getStaticType($node);
// return $this->resolveFromNodeAndType($node, $nodeType);
// }
public function resolveFromNodeAndType(Node $node, Type $type): ?string
{
@ -58,6 +61,79 @@ final class VariableNaming
return (string) $stringy->camelize();
}
public function resolveFromNodeWithScopeCountAndFallbackName(
Expr $expr,
Scope $scope,
string $fallbackName
): string {
$name = $this->resolveFromNode($expr);
if ($name === null) {
$name = $fallbackName;
}
if (\str_contains($name, '\\')) {
$name = (string) Strings::after($name, '\\', - 1);
}
$countedValueName = $this->createCountedValueName($name, $scope);
return lcfirst($countedValueName);
}
public function createCountedValueName(string $valueName, ?Scope $scope): string
{
if ($scope === null) {
return $valueName;
}
// make sure variable name is unique
if (! $scope->hasVariableType($valueName)->yes()) {
return $valueName;
}
// we need to add number suffix until the variable is unique
$i = 2;
$countedValueNamePart = $valueName;
while ($scope->hasVariableType($valueName)->yes()) {
$valueName = $countedValueNamePart . $i;
++$i;
}
return $valueName;
}
public function resolveFromFuncCallFirstArgumentWithSuffix(
FuncCall $funcCall,
string $suffix,
string $fallbackName,
?Scope $scope
): string {
$bareName = $this->resolveBareFuncCallArgumentName($funcCall, $fallbackName, $suffix);
return $this->createCountedValueName($bareName, $scope);
}
// private function resolveFromNodeAndType(Node $node, Type $type): ?string
// {
// $variableName = $this->resolveBareFromNode($node);
// if ($variableName === null) {
// return null;
// }
//
// // adjust static to specific class
// if ($variableName === 'this' && $type instanceof ThisType) {
// $shortClassName = $this->nodeNameResolver->getShortName($type->getClassName());
// $variableName = lcfirst($shortClassName);
// }
//
// $stringy = new Stringy($variableName);
// return (string) $stringy->camelize();
// }
public function resolveFromNode(Node $node): ?string
{
$nodeType = $this->nodeTypeResolver->getStaticType($node);
return $this->resolveFromNodeAndType($node, $nodeType);
}
private function resolveBareFromNode(Node $node): ?string
{
$node = $this->unwrapNode($node);
@ -98,22 +174,22 @@ final class VariableNaming
return null;
}
private function unwrapNode(Node $node): ?Node
{
if ($node instanceof Arg) {
return $node->value;
}
if ($node instanceof Cast) {
return $node->expr;
}
if ($node instanceof Ternary) {
return $node->if;
}
return $node;
}
// private function unwrapNode(Node $node): ?Node
// {
// if ($node instanceof Arg) {
// return $node->value;
// }
//
// if ($node instanceof Cast) {
// return $node->expr;
// }
//
// if ($node instanceof Ternary) {
// return $node->if;
// }
//
// return $node;
// }
private function resolveParamNameFromArrayDimFetch(ArrayDimFetch $arrayDimFetch): ?string
{
@ -179,4 +255,145 @@ final class VariableNaming
throw new NotImplementedYetException();
}
private function unwrapNode(Node $node): ?Node
{
if ($node instanceof Arg) {
return $node->value;
}
if ($node instanceof Cast) {
return $node->expr;
}
if ($node instanceof Ternary) {
return $node->if;
}
return $node;
}
// private function resolveParamNameFromArrayDimFetch(ArrayDimFetch $arrayDimFetch): ?string
// {
// while ($arrayDimFetch instanceof ArrayDimFetch) {
// if ($arrayDimFetch->dim instanceof Scalar) {
// $valueName = $this->nodeNameResolver->getName($arrayDimFetch->var);
// $dimName = $this->valueResolver->getValue($arrayDimFetch->dim);
//
// $stringy = new Stringy($dimName);
// $dimName = (string) $stringy->upperCamelize();
//
// return $valueName . $dimName;
// }
//
// $arrayDimFetch = $arrayDimFetch->var;
// }
//
// return $this->resolveBareFromNode($arrayDimFetch);
// }
// private function resolveBareFromNode(Node $node): ?string
// {
// $node = $this->unwrapNode($node);
//
// if ($node instanceof ArrayDimFetch) {
// return $this->resolveParamNameFromArrayDimFetch($node);
// }
//
// if ($node instanceof PropertyFetch) {
// return $this->resolveFromPropertyFetch($node);
// }
//
// if ($node instanceof MethodCall || $node instanceof NullsafeMethodCall || $node instanceof StaticCall) {
// return $this->resolveFromMethodCall($node);
// }
//
// if ($node instanceof New_) {
// return $this->resolveFromNew($node);
// }
//
// if ($node instanceof FuncCall) {
// return $this->resolveFromNode($node->name);
// }
//
// if (! $node instanceof Node) {
// throw new NotImplementedYetException();
// }
//
// $paramName = $this->nodeNameResolver->getName($node);
// if ($paramName !== null) {
// return $paramName;
// }
//
// if ($node instanceof String_) {
// return $node->value;
// }
//
// return null;
// }
// private function resolveFromNew(New_ $new): string
// {
// if ($new->class instanceof Name) {
// $className = $this->nodeNameResolver->getName($new->class);
// return $this->nodeNameResolver->getShortName($className);
// }
//
// throw new NotImplementedYetException();
// }
//
// /**
// * @param MethodCall|NullsafeMethodCall|StaticCall $node
// */
// private function resolveFromMethodCall(Node $node): ?string
// {
// if ($node->name instanceof MethodCall) {
// return $this->resolveFromMethodCall($node->name);
// }
//
// $methodName = $this->nodeNameResolver->getName($node->name);
// if (! is_string($methodName)) {
// return null;
// }
//
// return $methodName;
// }
//
// private function resolveFromPropertyFetch(PropertyFetch $propertyFetch): string
// {
// $varName = $this->nodeNameResolver->getName($propertyFetch->var);
// if (! is_string($varName)) {
// throw new NotImplementedYetException();
// }
//
// $propertyName = $this->nodeNameResolver->getName($propertyFetch->name);
// if (! is_string($propertyName)) {
// throw new NotImplementedYetException();
// }
//
// if ($varName === 'this') {
// return $propertyName;
// }
//
// return $varName . ucfirst($propertyName);
// }
private function resolveBareFuncCallArgumentName(
FuncCall $funcCall,
string $fallbackName,
string $suffix
): string {
$argumentValue = $funcCall->args[0]->value;
if ($argumentValue instanceof MethodCall || $argumentValue instanceof StaticCall) {
$name = $this->nodeNameResolver->getName($argumentValue->name);
} else {
$name = $this->nodeNameResolver->getName($argumentValue);
}
if ($name === null) {
return $fallbackName;
}
return $name . $suffix;
}
}

View File

@ -1,75 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Php55\NodeFactory;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Parser;
use Rector\Core\Exception\ShouldNotHappenException;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class AnonymousFunctionNodeFactory
{
/**
* @var string
* @see https://regex101.com/r/jkLLlM/2
*/
private const DIM_FETCH_REGEX = '#(\\$|\\\\|\\x0)(?<number>\d+)#';
public function __construct(
private SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private Parser $parser
) {
}
public function createAnonymousFunctionFromString(Expr $expr): ?Closure
{
if (! $expr instanceof String_) {
// not supported yet
throw new ShouldNotHappenException();
}
$phpCode = '<?php ' . $expr->value . ';';
$contentNodes = (array) $this->parser->parse($phpCode);
$anonymousFunction = new Closure();
$firstNode = $contentNodes[0] ?? null;
if (! $firstNode instanceof Expression) {
return null;
}
$stmt = $firstNode->expr;
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmt, function (Node $node): Node {
if (! $node instanceof String_) {
return $node;
}
$match = Strings::match($node->value, self::DIM_FETCH_REGEX);
if (! $match) {
return $node;
}
$matchesVariable = new Variable('matches');
return new ArrayDimFetch($matchesVariable, new LNumber((int) $match['number']));
});
$anonymousFunction->stmts[] = new Return_($stmt);
$anonymousFunction->params[] = new Param(new Variable('matches'));
return $anonymousFunction;
}
}

View File

@ -10,8 +10,8 @@ use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use Rector\Core\Rector\AbstractRector;
use Rector\Php55\NodeFactory\AnonymousFunctionNodeFactory;
use Rector\Php55\RegexMatcher;
use Rector\Php72\NodeFactory\AnonymousFunctionFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -23,7 +23,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class PregReplaceEModifierRector extends AbstractRector
{
public function __construct(
private AnonymousFunctionNodeFactory $anonymousFunctionNodeFactory,
private AnonymousFunctionFactory $anonymousFunctionFactory,
private RegexMatcher $regexMatcher
) {
}
@ -84,7 +84,7 @@ CODE_SAMPLE
}
$secondArgumentValue = $node->args[1]->value;
$anonymousFunction = $this->anonymousFunctionNodeFactory->createAnonymousFunctionFromString(
$anonymousFunction = $this->anonymousFunctionFactory->createAnonymousFunctionFromString(
$secondArgumentValue
);
if (! $anonymousFunction instanceof Closure) {

View File

@ -1,257 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Php70\NodeAnalyzer;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\NullsafeMethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar;
use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\Scope;
use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Stringy\Stringy;
/**
* @todo extract to own service with collector
*/
final class VariableNaming
{
public function __construct(
private NodeTypeResolver $nodeTypeResolver,
private NodeNameResolver $nodeNameResolver,
private ValueResolver $valueResolver
) {
}
public function resolveFromNodeWithScopeCountAndFallbackName(
Expr $expr,
Scope $scope,
string $fallbackName
): string {
$name = $this->resolveFromNode($expr);
if ($name === null) {
$name = $fallbackName;
}
if (\str_contains($name, '\\')) {
$name = (string) Strings::after($name, '\\', - 1);
}
$countedValueName = $this->createCountedValueName($name, $scope);
return lcfirst($countedValueName);
}
public function createCountedValueName(string $valueName, ?Scope $scope): string
{
if ($scope === null) {
return $valueName;
}
// make sure variable name is unique
if (! $scope->hasVariableType($valueName)->yes()) {
return $valueName;
}
// we need to add number suffix until the variable is unique
$i = 2;
$countedValueNamePart = $valueName;
while ($scope->hasVariableType($valueName)->yes()) {
$valueName = $countedValueNamePart . $i;
++$i;
}
return $valueName;
}
public function resolveFromNodeAndType(Node $node, Type $type): ?string
{
$variableName = $this->resolveBareFromNode($node);
if ($variableName === null) {
return null;
}
// adjust static to specific class
if ($variableName === 'this' && $type instanceof ThisType) {
$shortClassName = $this->nodeNameResolver->getShortName($type->getClassName());
$variableName = lcfirst($shortClassName);
}
$stringy = new Stringy($variableName);
return (string) $stringy->camelize();
}
public function resolveFromFuncCallFirstArgumentWithSuffix(
FuncCall $funcCall,
string $suffix,
string $fallbackName,
?Scope $scope
): string {
$bareName = $this->resolveBareFuncCallArgumentName($funcCall, $fallbackName, $suffix);
return $this->createCountedValueName($bareName, $scope);
}
private function resolveFromNode(Node $node): ?string
{
$nodeType = $this->nodeTypeResolver->getStaticType($node);
return $this->resolveFromNodeAndType($node, $nodeType);
}
private function unwrapNode(Node $node): ?Node
{
if ($node instanceof Arg) {
return $node->value;
}
if ($node instanceof Cast) {
return $node->expr;
}
if ($node instanceof Ternary) {
return $node->if;
}
return $node;
}
private function resolveParamNameFromArrayDimFetch(ArrayDimFetch $arrayDimFetch): ?string
{
while ($arrayDimFetch instanceof ArrayDimFetch) {
if ($arrayDimFetch->dim instanceof Scalar) {
$valueName = $this->nodeNameResolver->getName($arrayDimFetch->var);
$dimName = $this->valueResolver->getValue($arrayDimFetch->dim);
$stringy = new Stringy($dimName);
$dimName = (string) $stringy->upperCamelize();
return $valueName . $dimName;
}
$arrayDimFetch = $arrayDimFetch->var;
}
return $this->resolveBareFromNode($arrayDimFetch);
}
private function resolveBareFromNode(Node $node): ?string
{
$node = $this->unwrapNode($node);
if ($node instanceof ArrayDimFetch) {
return $this->resolveParamNameFromArrayDimFetch($node);
}
if ($node instanceof PropertyFetch) {
return $this->resolveFromPropertyFetch($node);
}
if ($node instanceof MethodCall || $node instanceof NullsafeMethodCall || $node instanceof StaticCall) {
return $this->resolveFromMethodCall($node);
}
if ($node instanceof New_) {
return $this->resolveFromNew($node);
}
if ($node instanceof FuncCall) {
return $this->resolveFromNode($node->name);
}
if (! $node instanceof Node) {
throw new NotImplementedYetException();
}
$paramName = $this->nodeNameResolver->getName($node);
if ($paramName !== null) {
return $paramName;
}
if ($node instanceof String_) {
return $node->value;
}
return null;
}
private function resolveFromNew(New_ $new): string
{
if ($new->class instanceof Name) {
$className = $this->nodeNameResolver->getName($new->class);
return $this->nodeNameResolver->getShortName($className);
}
throw new NotImplementedYetException();
}
/**
* @param MethodCall|NullsafeMethodCall|StaticCall $node
*/
private function resolveFromMethodCall(Node $node): ?string
{
if ($node->name instanceof MethodCall) {
return $this->resolveFromMethodCall($node->name);
}
$methodName = $this->nodeNameResolver->getName($node->name);
if (! is_string($methodName)) {
return null;
}
return $methodName;
}
private function resolveFromPropertyFetch(PropertyFetch $propertyFetch): string
{
$varName = $this->nodeNameResolver->getName($propertyFetch->var);
if (! is_string($varName)) {
throw new NotImplementedYetException();
}
$propertyName = $this->nodeNameResolver->getName($propertyFetch->name);
if (! is_string($propertyName)) {
throw new NotImplementedYetException();
}
if ($varName === 'this') {
return $propertyName;
}
return $varName . ucfirst($propertyName);
}
private function resolveBareFuncCallArgumentName(
FuncCall $funcCall,
string $fallbackName,
string $suffix
): string {
$argumentValue = $funcCall->args[0]->value;
if ($argumentValue instanceof MethodCall || $argumentValue instanceof StaticCall) {
$name = $this->nodeNameResolver->getName($argumentValue->name);
} else {
$name = $this->nodeNameResolver->getName($argumentValue);
}
if ($name === null) {
return $fallbackName;
}
return $name . $suffix;
}
}

View File

@ -24,9 +24,9 @@ use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Type\MixedType;
use Rector\Core\PHPStan\Reflection\CallReflectionResolver;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\VariableNaming;
use Rector\NodeNestingScope\ParentScopeFinder;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php70\NodeAnalyzer\VariableNaming;
use Rector\Php70\ValueObject\VariableAssignPair;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -77,7 +77,7 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
}
$currentScope = $scopeNode->getAttribute(AttributeKey::SCOPE);
if (! $currentScope instanceof MutatingScope) {
if (! $currentScope instanceof Scope) {
return null;
}
@ -147,24 +147,22 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
return $arguments;
}
private function getReplacementsFor(Expr $expr, MutatingScope $mutatingScope, Node $scopeNode): VariableAssignPair
private function getReplacementsFor(Expr $expr, Scope $scope, Node $scopeNode): VariableAssignPair
{
/** @var Assign|AssignOp|AssignRef $expr */
if ($this->isAssign($expr) && $this->isVariableLikeNode($expr->var)) {
return new VariableAssignPair($expr->var, $expr);
}
$variableName = $this->variableNaming->resolveFromNodeWithScopeCountAndFallbackName(
$expr,
$mutatingScope,
'tmp'
);
$variableName = $this->variableNaming->resolveFromNodeWithScopeCountAndFallbackName($expr, $scope, 'tmp');
$variable = new Variable($variableName);
// add a new scope with this variable
$newVariableAwareScope = $mutatingScope->assignExpression($variable, new MixedType());
$scopeNode->setAttribute(AttributeKey::SCOPE, $newVariableAwareScope);
if ($scope instanceof MutatingScope) {
$mutatingScope = $scope->assignExpression($variable, new MixedType());
$scopeNode->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
return new VariableAssignPair($variable, new Assign($variable, $expr));
}

View File

@ -4,26 +4,55 @@ declare(strict_types=1);
namespace Rector\Php72\NodeFactory;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\ClosureUse;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\UnionType;
use PhpParser\Parser;
use PHPStan\Reflection\FunctionVariantWithPhpDocs;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\Php\PhpMethodReflection;
use PHPStan\Type\MixedType;
use PHPStan\Type\VoidType;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class AnonymousFunctionFactory
{
/**
* @var string
* @see https://regex101.com/r/jkLLlM/2
*/
private const DIM_FETCH_REGEX = '#(\\$|\\\\|\\x0)(?<number>\d+)#';
public function __construct(
private NodeNameResolver $nodeNameResolver,
private BetterNodeFinder $betterNodeFinder
private BetterNodeFinder $betterNodeFinder,
private NodeFactory $nodeFactory,
private StaticTypeMapper $staticTypeMapper,
private SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private Parser $parser
) {
}
@ -51,6 +80,84 @@ final class AnonymousFunctionFactory
return $anonymousFunctionNode;
}
/**
* @param Variable|PropertyFetch $expr
*/
public function createFromPhpMethodReflection(PhpMethodReflection $phpMethodReflection, Expr $expr): Closure
{
/** @var FunctionVariantWithPhpDocs $functionVariantWithPhpDoc */
$functionVariantWithPhpDoc = $phpMethodReflection->getVariants()[0];
$anonymousFunction = new Closure();
$newParams = $this->createParams($functionVariantWithPhpDoc->getParameters());
$anonymousFunction->params = $newParams;
$innerMethodCall = new MethodCall($expr, $phpMethodReflection->getName());
$innerMethodCall->args = $this->nodeFactory->createArgsFromParams($newParams);
if (! $functionVariantWithPhpDoc->getReturnType() instanceof MixedType) {
$returnType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
$functionVariantWithPhpDoc->getReturnType()
);
$anonymousFunction->returnType = $returnType;
}
// does method return something?
if (! $functionVariantWithPhpDoc->getReturnType() instanceof VoidType) {
$anonymousFunction->stmts[] = new Return_($innerMethodCall);
} else {
$anonymousFunction->stmts[] = new Expression($innerMethodCall);
}
if ($expr instanceof Variable && ! $this->nodeNameResolver->isName($expr, 'this')) {
$anonymousFunction->uses[] = new ClosureUse($expr);
}
return $anonymousFunction;
}
public function createAnonymousFunctionFromString(Expr $expr): ?Closure
{
if (! $expr instanceof String_) {
// not supported yet
throw new ShouldNotHappenException();
}
$phpCode = '<?php ' . $expr->value . ';';
$contentNodes = (array) $this->parser->parse($phpCode);
$anonymousFunction = new Closure();
$firstNode = $contentNodes[0] ?? null;
if (! $firstNode instanceof Expression) {
return null;
}
$stmt = $firstNode->expr;
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmt, function (Node $node): Node {
if (! $node instanceof String_) {
return $node;
}
$match = Strings::match($node->value, self::DIM_FETCH_REGEX);
if (! $match) {
return $node;
}
$matchesVariable = new Variable('matches');
return new ArrayDimFetch($matchesVariable, new LNumber((int) $match['number']));
});
$anonymousFunction->stmts[] = new Return_($stmt);
$anonymousFunction->params[] = new Param(new Variable('matches'));
return $anonymousFunction;
}
/**
* @param Node[] $nodes
* @param Param[] $paramNodes
@ -97,4 +204,25 @@ final class AnonymousFunctionFactory
return $filteredVariables;
}
/**
* @param ParameterReflection[] $parameterReflections
* @return Param[]
*/
private function createParams(array $parameterReflections): array
{
$params = [];
foreach ($parameterReflections as $parameterReflection) {
$param = new Param(new Variable($parameterReflection->getName()));
if (! $parameterReflection->getType() instanceof MixedType) {
$paramType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($parameterReflection->getType());
$param->type = $paramType;
}
$params[] = $param;
}
return $params;
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\Php80\NodeResolver;
namespace Rector\Php80\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
@ -23,7 +23,7 @@ use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
use Rector\Php80\ValueObject\PropertyPromotionCandidate;
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
final class PromotedPropertyResolver
final class PromotedPropertyCandidateResolver
{
public function __construct(
private NodeNameResolver $nodeNameResolver,
@ -48,7 +48,8 @@ final class PromotedPropertyResolver
$propertyPromotionCandidates = [];
foreach ($class->getProperties() as $property) {
if (count($property->props) !== 1) {
$propertyCount = count($property->props);
if ($propertyCount !== 1) {
continue;
}

View File

@ -18,7 +18,7 @@ use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
use Rector\Naming\VariableRenamer;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\NodeResolver\PromotedPropertyResolver;
use Rector\Php80\NodeAnalyzer\PromotedPropertyCandidateResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -30,7 +30,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class ClassPropertyAssignToConstructorPromotionRector extends AbstractRector
{
public function __construct(
private PromotedPropertyResolver $promotedPropertyResolver,
private PromotedPropertyCandidateResolver $promotedPropertyResolver,
private VariableRenamer $variableRenamer,
private VarTagRemover $varTagRemover
) {