1111use PhpParser \Node \Expr \MethodCall ;
1212use PhpParser \Node \Expr \New_ ;
1313use PhpParser \Node \Expr \StaticCall ;
14+ use PhpParser \Node \Expr \Variable ;
1415use PhpParser \Node \Stmt \ClassMethod ;
1516use Rector \Arguments \Contract \ReplaceArgumentDefaultValueInterface ;
1617use Rector \Arguments \ValueObject \ReplaceArgumentDefaultValue ;
18+ use Rector \NodeAnalyzer \ArgsAnalyzer ;
19+ use Rector \PhpParser \AstResolver ;
1720use Rector \PhpParser \Node \NodeFactory ;
1821use Rector \PhpParser \Node \Value \ValueResolver ;
1922final class ArgumentDefaultValueReplacer
@@ -26,10 +29,20 @@ final class ArgumentDefaultValueReplacer
2629 * @readonly
2730 */
2831 private ValueResolver $ valueResolver ;
29- public function __construct (NodeFactory $ nodeFactory , ValueResolver $ valueResolver )
32+ /**
33+ * @readonly
34+ */
35+ private ArgsAnalyzer $ argsAnalyzer ;
36+ /**
37+ * @readonly
38+ */
39+ private AstResolver $ astResolver ;
40+ public function __construct (NodeFactory $ nodeFactory , ValueResolver $ valueResolver , ArgsAnalyzer $ argsAnalyzer , AstResolver $ astResolver )
3041 {
3142 $ this ->nodeFactory = $ nodeFactory ;
3243 $ this ->valueResolver = $ valueResolver ;
44+ $ this ->argsAnalyzer = $ argsAnalyzer ;
45+ $ this ->astResolver = $ astResolver ;
3346 }
3447 /**
3548 * @template TCall as (MethodCall|StaticCall|ClassMethod|FuncCall|New_)
@@ -45,9 +58,6 @@ public function processReplaces($node, ReplaceArgumentDefaultValueInterface $rep
4558 }
4659 return $ this ->processParams ($ node , $ replaceArgumentDefaultValue );
4760 }
48- if (!isset ($ node ->args [$ replaceArgumentDefaultValue ->getPosition ()])) {
49- return null ;
50- }
5161 return $ this ->processArgs ($ node , $ replaceArgumentDefaultValue );
5262 }
5363 /**
@@ -89,13 +99,47 @@ private function processArgs($expr, ReplaceArgumentDefaultValueInterface $replac
8999 return null ;
90100 }
91101 $ position = $ replaceArgumentDefaultValue ->getPosition ();
92- $ particularArg = $ expr ->getArgs ()[$ position ] ?? null ;
102+ $ arguments = $ expr ->getArgs ();
103+ $ firstNamedArgPosition = $ this ->argsAnalyzer ->resolveFirstNamedArgPosition ($ arguments );
104+ // if the call has named argyments and we want to replace an array of values
105+ // we cannot replace it as we cannot really match this array of values to
106+ // the existing arguments, it would be too complex
107+ if ($ firstNamedArgPosition !== null && is_array ($ replaceArgumentDefaultValue ->getValueBefore ())) {
108+ return null ;
109+ }
110+ // if the call has named arguments and the argument that we want to replace is not
111+ // before any named argument, we need to check if it is in the list of named arguments
112+ // if it is, we use the position of the named argyment as the position to replace
113+ // if it is not, we cannot replace it
114+ if ($ firstNamedArgPosition !== null && $ position >= $ firstNamedArgPosition ) {
115+ $ call = $ this ->astResolver ->resolveClassMethodOrFunctionFromCall ($ expr );
116+ if ($ call === null ) {
117+ return null ;
118+ }
119+ $ paramName = null ;
120+ $ variable = $ call ->params [$ position ]->var ;
121+ if ($ variable instanceof Variable) {
122+ $ paramName = $ variable ->name ;
123+ }
124+ $ newPosition = -1 ;
125+ if (is_string ($ paramName )) {
126+ $ newPosition = $ this ->argsAnalyzer ->resolveArgPosition ($ arguments , $ paramName , $ newPosition );
127+ }
128+ if ($ newPosition === -1 ) {
129+ return null ;
130+ }
131+ $ position = $ newPosition ;
132+ }
133+ if (!isset ($ arguments [$ position ])) {
134+ return null ;
135+ }
136+ $ particularArg = $ arguments [$ position ] ?? null ;
93137 if (!$ particularArg instanceof Arg) {
94138 return null ;
95139 }
96140 $ argValue = $ this ->valueResolver ->getValue ($ particularArg ->value );
97141 if (is_scalar ($ replaceArgumentDefaultValue ->getValueBefore ()) && $ argValue === $ replaceArgumentDefaultValue ->getValueBefore ()) {
98- $ expr -> args [ $ position ] = $ this ->normalizeValueToArgument ($ replaceArgumentDefaultValue ->getValueAfter ());
142+ $ particularArg -> value = $ this ->normalizeValue ($ replaceArgumentDefaultValue ->getValueAfter ());
99143 return $ expr ;
100144 }
101145 if (is_array ($ replaceArgumentDefaultValue ->getValueBefore ())) {
0 commit comments