Passed
Push — main ( e311fa...d6e945 )
by mikhail
03:20
created

AddNamedArgumentsRector::getParameters()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 15
ccs 11
cts 11
cp 1
crap 5
rs 9.6111
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SavinMikhail\AddNamedArgumentsRector;
6
7
use InvalidArgumentException;
8
use PhpParser\Node;
9
use PhpParser\Node\Expr\FuncCall;
10
use PhpParser\Node\Expr\MethodCall;
11
use PhpParser\Node\Expr\New_;
12
use PhpParser\Node\Expr\StaticCall;
13
use PhpParser\Node\Identifier;
14
use PHPStan\Reflection\ExtendedParameterReflection;
0 ignored issues
show
Bug introduced by
The type PHPStan\Reflection\ExtendedParameterReflection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use PHPStan\Reflection\ReflectionProvider;
0 ignored issues
show
Bug introduced by
The type PHPStan\Reflection\ReflectionProvider was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Rector\Contract\Rector\ConfigurableRectorInterface;
17
use Rector\NodeNameResolver\NodeNameResolver;
18
use Rector\NodeTypeResolver\NodeTypeResolver;
19
use Rector\Rector\AbstractRector;
20
use Rector\ValueObject\PhpVersion;
21
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
22
use SavinMikhail\AddNamedArgumentsRector\Config\ConfigStrategy;
23
use SavinMikhail\AddNamedArgumentsRector\Config\DefaultStrategy;
0 ignored issues
show
Bug introduced by
The type SavinMikhail\AddNamedArg...\Config\DefaultStrategy was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use SavinMikhail\AddNamedArgumentsRector\Reflection\ReflectionService;
0 ignored issues
show
Bug introduced by
The type SavinMikhail\AddNamedArg...ction\ReflectionService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
26
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
27
use Webmozart\Assert\Assert;
28
29
use function count;
30
31
/**
32
 * @see AddNamedArgumentsRectorTest
33
 */
34
final class AddNamedArgumentsRector extends AbstractRector implements MinPhpVersionInterface, ConfigurableRectorInterface
35
{
36
    private string $configStrategy = DefaultStrategy::class;
37
38
    private ReflectionService $reflectionService;
39
40 1
    public function __construct(
41
        ReflectionProvider $reflectionProvider,
42
        NodeNameResolver $nodeNameResolver,
43
        NodeTypeResolver $nodeTypeResolver,
44
        ?ReflectionService $reflectionService = null,
45
    ) {
46 1
        if ($reflectionService === null) {
47
            $reflectionService = new ReflectionService(
48
                $reflectionProvider,
49
                $nodeNameResolver,
50
                $nodeTypeResolver,
51
            );
52
        }
53 1
        $this->reflectionService = $reflectionService;
54
    }
55
56
    public function getRuleDefinition(): RuleDefinition
57
    {
58
        return new RuleDefinition('Convert all arguments to named arguments', codeSamples: [
59
            new CodeSample(
60
                badCode: '$user->setPassword("123456");',
61
                goodCode: '$user->changePassword(password: "123456");',
62
            ),
63
        ]);
64
    }
65
66 10
    public function getNodeTypes(): array
67
    {
68 10
        return [FuncCall::class, StaticCall::class, MethodCall::class, New_::class];
69
    }
70
71 10
    public function refactor(Node $node): ?Node
72
    {
73
        /** @var FuncCall|StaticCall|MethodCall|New_ $node */
74 10
        $parameters = $this->reflectionService->getParameters($node);
75 10
        $classReflection = $this->reflectionService->getClassReflection($node);
76
77 10
        if (!$this->configStrategy::shouldApply($node, $parameters, $classReflection)) {
78 6
            return null;
79
        }
80
81 4
        $this->addNamesToArgs($node, $parameters);
82
83 4
        return $node;
84
    }
85
86
    /**
87
     * @param ExtendedParameterReflection[] $parameters
88
     */
89 4
    private function addNamesToArgs(
90
        FuncCall|StaticCall|MethodCall|New_ $node,
91
        array $parameters,
92
    ): void {
93 4
        $argNames = [];
94 4
        foreach ($node->args as $index => $arg) {
95 4
            $argNames[$index] = new Identifier($parameters[$index]->getName());
96
        }
97
98 4
        foreach ($node->args as $index => $arg) {
99 4
            $arg->name = $argNames[$index];
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on PhpParser\Node\VariadicPlaceholder.
Loading history...
100
        }
101
    }
102
103 1
    public function provideMinPhpVersion(): int
104
    {
105 1
        return PhpVersion::PHP_80;
106
    }
107
108
    public function configure(array $configuration): void
109
    {
110
        Assert::lessThan(count($configuration), 2, 'You can pass only 1 strategy');
111
        if ($configuration === []) {
112
            return;
113
        }
114
        $strategyClass = $configuration[0];
115
116
        if (!class_exists($strategyClass)) {
117
            throw new InvalidArgumentException("Class {$strategyClass} does not exist.");
118
        }
119
120
        $strategy = new $strategyClass();
121
122
        Assert::isInstanceOf($strategy, ConfigStrategy::class, 'Your strategy must implement ConfigStrategy interface');
123
124
        $this->configStrategy = $strategyClass;
125
    }
126
}
127