Skip to content

Commit 5fae8d9

Browse files
committed
Fix multiline array newline detection for multiline values
1 parent 6c31390 commit 5fae8d9

File tree

6 files changed

+166
-71
lines changed

6 files changed

+166
-71
lines changed

src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php

Lines changed: 62 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,6 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array
441441
&& $tokens[$prev]['code'] !== T_END_NOWDOC)
442442
|| $tokens[($nextToken - 1)]['line'] === $tokens[$nextToken]['line']
443443
) {
444-
$content = $tokens[($nextToken - 2)]['content'];
445444
if ($tokens[($nextToken - 1)]['content'] === $phpcsFile->eolChar) {
446445
$spaceLength = 'newline';
447446
} else {
@@ -611,29 +610,40 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array
611610
$phpcsFile->recordMetric($stackPtr, 'Array end comma', 'yes');
612611
}
613612

614-
$lastValueLine = false;
615-
foreach ($indices as $value) {
613+
foreach ($indices as $valuePosition => $value) {
616614
if (empty($value['value']) === true) {
617615
// Array was malformed and we couldn't figure out
618616
// the array value correctly, so we have to ignore it.
619617
// Other parts of this sniff will correct the error.
620618
continue;
621619
}
622620

623-
if ($lastValueLine !== false && $tokens[$value['value']]['line'] === $lastValueLine) {
621+
$valuePointer = $value['value'];
622+
623+
$previous = $phpcsFile->findPrevious([T_WHITESPACE, T_COMMA], ($valuePointer - 1), ($arrayStart + 1), true);
624+
if ($previous === false) {
625+
$previous = $stackPtr;
626+
}
627+
628+
$previousIsWhitespace = $tokens[($valuePointer - 1)]['code'] === T_WHITESPACE;
629+
if ($tokens[$previous]['line'] === $tokens[$valuePointer]['line']) {
624630
$error = 'Each value in a multi-line array must be on a new line';
625-
$fix = $phpcsFile->addFixableError($error, $value['value'], 'ValueNoNewline');
631+
if ($valuePosition === 0) {
632+
$error = 'The first value in a multi-value array must be on a new line';
633+
}
634+
635+
$fix = $phpcsFile->addFixableError($error, $valuePointer, 'ValueNoNewline');
626636
if ($fix === true) {
627-
if ($tokens[($value['value'] - 1)]['code'] === T_WHITESPACE) {
628-
$phpcsFile->fixer->replaceToken(($value['value'] - 1), '');
637+
if ($previousIsWhitespace === true) {
638+
$phpcsFile->fixer->replaceToken(($valuePointer - 1), $phpcsFile->eolChar);
639+
} else {
640+
$phpcsFile->fixer->addNewlineBefore($valuePointer);
629641
}
630-
631-
$phpcsFile->fixer->addNewlineBefore($value['value']);
632642
}
633-
} else if ($tokens[($value['value'] - 1)]['code'] === T_WHITESPACE) {
643+
} else if ($previousIsWhitespace === true) {
634644
$expected = $keywordStart;
635645

636-
$first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $value['value'], true);
646+
$first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $valuePointer, true);
637647
$found = ($tokens[$first]['column'] - 1);
638648
if ($found !== $expected) {
639649
$error = 'Array value not aligned correctly; expected %s spaces but found %s';
@@ -642,18 +652,16 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array
642652
$found,
643653
];
644654

645-
$fix = $phpcsFile->addFixableError($error, $value['value'], 'ValueNotAligned', $data);
655+
$fix = $phpcsFile->addFixableError($error, $valuePointer, 'ValueNotAligned', $data);
646656
if ($fix === true) {
647657
if ($found === 0) {
648-
$phpcsFile->fixer->addContent(($value['value'] - 1), str_repeat(' ', $expected));
658+
$phpcsFile->fixer->addContent(($valuePointer - 1), str_repeat(' ', $expected));
649659
} else {
650-
$phpcsFile->fixer->replaceToken(($value['value'] - 1), str_repeat(' ', $expected));
660+
$phpcsFile->fixer->replaceToken(($valuePointer - 1), str_repeat(' ', $expected));
651661
}
652662
}
653663
}
654664
}//end if
655-
656-
$lastValueLine = $tokens[$value['value']]['line'];
657665
}//end foreach
658666
}//end if
659667

@@ -684,82 +692,68 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array
684692
to be moved back one space however, then both errors would be fixed.
685693
*/
686694

687-
$numValues = count($indices);
688-
689-
$indicesStart = ($keywordStart + 1);
690-
$indexLine = $tokens[$stackPtr]['line'];
691-
$lastIndexLine = null;
692-
foreach ($indices as $index) {
693-
if ($index['value'] === false) {
695+
$indicesStart = ($keywordStart + 1);
696+
foreach ($indices as $valuePosition => $index) {
697+
$valuePointer = $index['value'];
698+
if ($valuePointer === false) {
694699
// Syntax error or live coding.
695700
continue;
696701
}
697702

698703
if (isset($index['index']) === false) {
699704
// Array value only.
700-
if ($tokens[$index['value']]['line'] === $tokens[$stackPtr]['line'] && $numValues > 1) {
701-
$error = 'The first value in a multi-value array must be on a new line';
702-
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'FirstValueNoNewline');
703-
if ($fix === true) {
704-
$phpcsFile->fixer->addNewlineBefore($index['value']);
705-
}
706-
}
707-
708705
continue;
709706
}
710707

711-
$lastIndexLine = $indexLine;
712-
$indexLine = $tokens[$index['index']]['line'];
708+
$indexPointer = $index['index'];
709+
$indexLine = $tokens[$indexPointer]['line'];
713710

714-
if ($indexLine === $tokens[$stackPtr]['line']) {
715-
$error = 'The first index in a multi-value array must be on a new line';
716-
$fix = $phpcsFile->addFixableError($error, $index['index'], 'FirstIndexNoNewline');
717-
if ($fix === true) {
718-
$phpcsFile->fixer->addNewlineBefore($index['index']);
719-
}
720-
721-
continue;
711+
$previous = $phpcsFile->findPrevious([T_WHITESPACE, T_COMMA], ($indexPointer - 1), ($arrayStart + 1), true);
712+
if ($previous === false) {
713+
$previous = $stackPtr;
722714
}
723715

724-
if ($indexLine === $lastIndexLine) {
716+
if ($tokens[$previous]['line'] === $indexLine) {
725717
$error = 'Each index in a multi-line array must be on a new line';
726-
$fix = $phpcsFile->addFixableError($error, $index['index'], 'IndexNoNewline');
718+
if ($valuePosition === 0) {
719+
$error = 'The first index in a multi-value array must be on a new line';
720+
}
721+
722+
$fix = $phpcsFile->addFixableError($error, $indexPointer, 'IndexNoNewline');
727723
if ($fix === true) {
728-
if ($tokens[($index['index'] - 1)]['code'] === T_WHITESPACE) {
729-
$phpcsFile->fixer->replaceToken(($index['index'] - 1), '');
724+
if ($tokens[($indexPointer - 1)]['code'] === T_WHITESPACE) {
725+
$phpcsFile->fixer->replaceToken(($indexPointer - 1), $phpcsFile->eolChar);
726+
} else {
727+
$phpcsFile->fixer->addNewlineBefore($indexPointer);
730728
}
731-
732-
$phpcsFile->fixer->addNewlineBefore($index['index']);
733729
}
734730

735731
continue;
736732
}
737733

738-
if ($tokens[$index['index']]['column'] !== $indicesStart
739-
&& ($index['index'] - 1) !== $arrayStart
740-
) {
734+
if ($tokens[$indexPointer]['column'] !== $indicesStart && ($indexPointer - 1) !== $arrayStart) {
741735
$expected = ($indicesStart - 1);
742-
$found = ($tokens[$index['index']]['column'] - 1);
736+
$found = ($tokens[$indexPointer]['column'] - 1);
743737
$error = 'Array key not aligned correctly; expected %s spaces but found %s';
744738
$data = [
745739
$expected,
746740
$found,
747741
];
748742

749-
$fix = $phpcsFile->addFixableError($error, $index['index'], 'KeyNotAligned', $data);
743+
$fix = $phpcsFile->addFixableError($error, $indexPointer, 'KeyNotAligned', $data);
750744
if ($fix === true) {
751-
if ($found === 0 || $tokens[($index['index'] - 1)]['code'] !== T_WHITESPACE) {
752-
$phpcsFile->fixer->addContent(($index['index'] - 1), str_repeat(' ', $expected));
745+
if ($found === 0 || $tokens[($indexPointer - 1)]['code'] !== T_WHITESPACE) {
746+
$phpcsFile->fixer->addContent(($indexPointer - 1), str_repeat(' ', $expected));
753747
} else {
754-
$phpcsFile->fixer->replaceToken(($index['index'] - 1), str_repeat(' ', $expected));
748+
$phpcsFile->fixer->replaceToken(($indexPointer - 1), str_repeat(' ', $expected));
755749
}
756750
}
757751
}
758752

759-
$arrowStart = ($tokens[$index['index']]['column'] + $maxLength + 1);
753+
$arrowStart = ($tokens[$indexPointer]['column'] + $maxLength + 1);
760754
if ($tokens[$index['arrow']]['column'] !== $arrowStart) {
761-
$expected = ($arrowStart - ($index['index_length'] + $tokens[$index['index']]['column']));
762-
$found = ($tokens[$index['arrow']]['column'] - ($index['index_length'] + $tokens[$index['index']]['column']));
755+
$expected = ($arrowStart - ($index['index_length'] + $tokens[$indexPointer]['column']));
756+
$found = ($tokens[$index['arrow']]['column'] - ($index['index_length'] + $tokens[$indexPointer]['column']));
763757
$error = 'Array double arrow not aligned correctly; expected %s space(s) but found %s';
764758
$data = [
765759
$expected,
@@ -779,9 +773,9 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array
779773
}
780774

781775
$valueStart = ($arrowStart + 3);
782-
if ($tokens[$index['value']]['column'] !== $valueStart) {
776+
if ($tokens[$valuePointer]['column'] !== $valueStart) {
783777
$expected = ($valueStart - ($tokens[$index['arrow']]['length'] + $tokens[$index['arrow']]['column']));
784-
$found = ($tokens[$index['value']]['column'] - ($tokens[$index['arrow']]['length'] + $tokens[$index['arrow']]['column']));
778+
$found = ($tokens[$valuePointer]['column'] - ($tokens[$index['arrow']]['length'] + $tokens[$index['arrow']]['column']));
785779
if ($found < 0) {
786780
$found = 'newline';
787781
}
@@ -795,25 +789,24 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array
795789
$fix = $phpcsFile->addFixableError($error, $index['arrow'], 'ValueNotAligned', $data);
796790
if ($fix === true) {
797791
if ($found === 'newline') {
798-
$prev = $phpcsFile->findPrevious(T_WHITESPACE, ($index['value'] - 1), null, true);
792+
$prev = $phpcsFile->findPrevious(T_WHITESPACE, ($valuePointer - 1), null, true);
799793
$phpcsFile->fixer->beginChangeset();
800-
for ($i = ($prev + 1); $i < $index['value']; $i++) {
794+
for ($i = ($prev + 1); $i < $valuePointer; $i++) {
801795
$phpcsFile->fixer->replaceToken($i, '');
802796
}
803797

804-
$phpcsFile->fixer->replaceToken(($index['value'] - 1), str_repeat(' ', $expected));
798+
$phpcsFile->fixer->replaceToken(($valuePointer - 1), str_repeat(' ', $expected));
805799
$phpcsFile->fixer->endChangeset();
806800
} else if ($found === 0) {
807-
$phpcsFile->fixer->addContent(($index['value'] - 1), str_repeat(' ', $expected));
801+
$phpcsFile->fixer->addContent(($valuePointer - 1), str_repeat(' ', $expected));
808802
} else {
809-
$phpcsFile->fixer->replaceToken(($index['value'] - 1), str_repeat(' ', $expected));
803+
$phpcsFile->fixer->replaceToken(($valuePointer - 1), str_repeat(' ', $expected));
810804
}
811805
}
812806
}//end if
813807

814808
// Check each line ends in a comma.
815-
$valueStart = $index['value'];
816-
$valueLine = $tokens[$index['value']]['line'];
809+
$valueStart = $valuePointer;
817810
$nextComma = false;
818811

819812
$end = $phpcsFile->findEndOfStatement($valueStart);
@@ -837,11 +830,11 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array
837830

838831
if ($nextComma === false || ($tokens[$nextComma]['line'] !== $valueLine)) {
839832
$error = 'Each line in an array declaration must end in a comma';
840-
$fix = $phpcsFile->addFixableError($error, $index['value'], 'NoComma');
833+
$fix = $phpcsFile->addFixableError($error, $valuePointer, 'NoComma');
841834

842835
if ($fix === true) {
843836
// Find the end of the line and put a comma there.
844-
for ($i = ($index['value'] + 1); $i <= $arrayEnd; $i++) {
837+
for ($i = ($valuePointer + 1); $i <= $arrayEnd; $i++) {
845838
if ($tokens[$i]['line'] > $valueLine) {
846839
break;
847840
}

src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,18 @@ HERE
394394
,
395395
);
396396

397+
array(
398+
lorem(
399+
1
400+
), 2,
401+
);
402+
403+
array(
404+
1 => lorem(
405+
1
406+
), 2 => 2,
407+
);
408+
397409
$foo = array(
398410
'тип' => 'авто',
399411
'цвет' => 'синий',
@@ -429,6 +441,12 @@ $foo = array(
429441
$foo->fn => 'value',
430442
);
431443

444+
array($a, $b,
445+
$c);
446+
447+
array('a' => $a, 'b' => $b,
448+
'c' => $c);
449+
432450
// Intentional syntax error.
433451
$a = array(
434452
'a' =>

src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,20 @@ HERE
422422
,
423423
);
424424

425+
array(
426+
lorem(
427+
1
428+
),
429+
2,
430+
);
431+
432+
array(
433+
1 => lorem(
434+
1
435+
),
436+
2 => 2,
437+
);
438+
425439
$foo = array(
426440
'тип' => 'авто',
427441
'цвет' => 'синий',
@@ -457,6 +471,18 @@ $foo = array(
457471
$foo->fn => 'value',
458472
);
459473

474+
array(
475+
$a,
476+
$b,
477+
$c,
478+
);
479+
480+
array(
481+
'a' => $a,
482+
'b' => $b,
483+
'c' => $c,
484+
);
485+
460486
// Intentional syntax error.
461487
$a = array(
462488
'a' =>

src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,18 @@ HERE
383383
,
384384
];
385385

386+
[
387+
lorem(
388+
1
389+
), 2,
390+
];
391+
392+
[
393+
1 => lorem(
394+
1
395+
), 2 => 2,
396+
];
397+
386398
$foo = [
387399
'тип' => 'авто',
388400
'цвет' => 'синий',
@@ -418,6 +430,12 @@ $foo = [
418430
$foo->fn => 'value',
419431
];
420432

433+
[$a, $b,
434+
$c];
435+
436+
['a' => $a, 'b' => $b,
437+
'c' => $c];
438+
421439
// Intentional syntax error.
422440
$a = [
423441
'a' =>

src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,20 @@ HERE
409409
,
410410
];
411411

412+
[
413+
lorem(
414+
1
415+
),
416+
2,
417+
];
418+
419+
[
420+
1 => lorem(
421+
1
422+
),
423+
2 => 2,
424+
];
425+
412426
$foo = [
413427
'тип' => 'авто',
414428
'цвет' => 'синий',
@@ -444,6 +458,18 @@ $foo = [
444458
$foo->fn => 'value',
445459
];
446460

461+
[
462+
$a,
463+
$b,
464+
$c,
465+
];
466+
467+
[
468+
'a' => $a,
469+
'b' => $b,
470+
'c' => $c,
471+
];
472+
447473
// Intentional syntax error.
448474
$a = [
449475
'a' =>

0 commit comments

Comments
 (0)