1212use PhpCsFixer \FixerDefinition \CodeSample ;
1313use PhpCsFixer \FixerDefinition \FixerDefinition ;
1414use PhpCsFixer \FixerDefinition \FixerDefinitionInterface ;
15+ use PhpCsFixer \Tokenizer \Analyzer \Analysis \TypeAnalysis ;
1516use PhpCsFixer \Tokenizer \Analyzer \FunctionsAnalyzer ;
1617use PhpCsFixer \Tokenizer \Analyzer \WhitespacesAnalyzer ;
1718use PhpCsFixer \Tokenizer \CT ;
@@ -127,7 +128,7 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
127128 $ typeAnalysis = $ argument ->getTypeAnalysis ();
128129 if ($ typeAnalysis ) {
129130 $ hasAtLeastOneTypedArgument = true ;
130- $ typeLength = $ this ->getFullTypeLength ($ tokens , $ typeAnalysis-> getStartIndex () );
131+ $ typeLength = $ this ->getFullTypeLength ($ tokens , $ typeAnalysis );
131132 if ($ typeLength > $ longestType ) {
132133 $ longestType = $ typeLength ;
133134 }
@@ -140,13 +141,31 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
140141 }
141142
142143 $ argsIndent = WhitespacesAnalyzer::detectIndent ($ tokens , $ i ) . $ this ->whitespacesConfig ->getIndent ();
143- foreach ($ arguments as $ argument ) {
144+ // Since we perform insertion of new tokens in this loop, if we go sequentially,
145+ // at each new iteration the token indices will shift due to the addition of new whitespaces.
146+ // If we go from the end, this problem will not occur.
147+ foreach (array_reverse ($ arguments ) as $ argument ) {
148+ if ($ this ->configuration [self ::C_DEFAULTS ] !== null ) {
149+ // Can't use $argument->hasDefault() because it's null when it's default for a type (e.g. 0 for int)
150+ $ equalToken = $ tokens [$ tokens ->getNextMeaningfulToken ($ argument ->getNameIndex ())];
151+ if ($ equalToken ->getContent () === '= ' ) {
152+ $ nameLen = mb_strlen ($ argument ->getName ());
153+ $ whitespaceIndex = $ argument ->getNameIndex () + 1 ;
154+ if ($ this ->configuration [self ::C_DEFAULTS ] === true ) {
155+ $ tokens ->ensureWhitespaceAtIndex ($ whitespaceIndex , 0 , str_repeat (' ' , $ longestVariableName - $ nameLen + 1 ));
156+ } else {
157+ $ tokens ->ensureWhitespaceAtIndex ($ whitespaceIndex , 0 , ' ' );
158+ }
159+ }
160+ }
161+
144162 if ($ this ->configuration [self ::C_VARIABLES ] !== null ) {
145163 $ whitespaceIndex = $ argument ->getNameIndex () - 1 ;
146164 if ($ this ->configuration [self ::C_VARIABLES ] === true ) {
147165 $ typeLen = 0 ;
148- if ($ argument ->getTypeAnalysis () !== null ) {
149- $ typeLen = $ this ->getFullTypeLength ($ tokens , $ argument ->getTypeAnalysis ()->getStartIndex ());
166+ $ typeAnalysis = $ argument ->getTypeAnalysis ();
167+ if ($ typeAnalysis !== null ) {
168+ $ typeLen = $ this ->getFullTypeLength ($ tokens , $ typeAnalysis );
150169 }
151170
152171 $ appendix = str_repeat (' ' , $ longestType - $ typeLen + (int )$ hasAtLeastOneTypedArgument );
@@ -163,22 +182,7 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
163182 }
164183 }
165184
166- $ tokens ->ensureWhitespaceAtIndex ($ whitespaceIndex , 0 , $ whitespaceToken );
167- }
168-
169- if ($ this ->configuration [self ::C_DEFAULTS ] !== null ) {
170- // Can't use $argument->hasDefault() because it's null when it's default for a type (e.g. 0 for int)
171- /** @var \PhpCsFixer\Tokenizer\Token $equalToken */
172- $ equalToken = $ tokens [$ tokens ->getNextMeaningfulToken ($ argument ->getNameIndex ())];
173- if ($ equalToken ->getContent () === '= ' ) {
174- $ nameLen = mb_strlen ($ argument ->getName ());
175- $ whitespaceIndex = $ argument ->getNameIndex () + 1 ;
176- if ($ this ->configuration [self ::C_DEFAULTS ] === true ) {
177- $ tokens ->ensureWhitespaceAtIndex ($ whitespaceIndex , 0 , str_repeat (' ' , $ longestVariableName - $ nameLen + 1 ));
178- } else {
179- $ tokens ->ensureWhitespaceAtIndex ($ whitespaceIndex , 0 , ' ' );
180- }
181- }
185+ $ tokens ->ensureWhitespaceAtIndex ($ whitespaceIndex , 1 , $ whitespaceToken );
182186 }
183187 }
184188 }
@@ -187,25 +191,22 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
187191 /**
188192 * TODO: The declaration might be split across multiple lines.
189193 * In such case we need to find the longest line and return it as the full type length
190- *
191- * @param int $typeIndex points to the beginning of the type
192194 */
193- private function getFullTypeLength (Tokens $ tokens , int $ typeIndex ): int {
195+ private function getFullTypeLength (Tokens $ tokens , TypeAnalysis $ typeAnalysis ): int {
194196 $ typeLength = 0 ;
195- $ varNameTokenIndex = $ tokens ->getNextTokenOfKind ($ typeIndex , [[T_VARIABLE ]]);
196- for ($ i = $ typeIndex ; $ i < $ varNameTokenIndex - 1 ; $ i ++) { // -1 to avoid whitespace between param name and type
197+ for ($ i = $ typeAnalysis ->getStartIndex (); $ i <= $ typeAnalysis ->getEndIndex (); $ i ++) {
197198 $ typeLength += mb_strlen ($ tokens [$ i ]->getContent ());
198199 }
199200
200- $ possiblyReadonlyToken = $ tokens [$ typeIndex - 2 ];
201+ $ possiblyReadonlyToken = $ tokens [$ typeAnalysis -> getStartIndex () - 2 ];
201202 if ($ possiblyReadonlyToken ->isGivenKind ($ this ->parameterModifiers )) {
202- $ whitespaceToken = $ tokens [$ typeIndex - 1 ];
203+ $ whitespaceToken = $ tokens [$ typeAnalysis -> getStartIndex () - 1 ];
203204 $ typeLength += strlen ($ possiblyReadonlyToken ->getContent () . $ whitespaceToken ->getContent ());
204205 }
205206
206- $ possiblyPromotionToken = $ tokens [$ typeIndex - 4 ];
207+ $ possiblyPromotionToken = $ tokens [$ typeAnalysis -> getStartIndex () - 4 ];
207208 if ($ possiblyPromotionToken ->isGivenKind ($ this ->parameterModifiers )) {
208- $ whitespaceToken = $ tokens [$ typeIndex - 3 ];
209+ $ whitespaceToken = $ tokens [$ typeAnalysis -> getStartIndex () - 3 ];
209210 $ typeLength += strlen ($ possiblyPromotionToken ->getContent () . $ whitespaceToken ->getContent ());
210211 }
211212
0 commit comments