Skip to content

Commit a513f65

Browse files
✨ Better checks for array rule
1 parent 7bc6fa5 commit a513f65

File tree

4 files changed

+166
-197
lines changed

4 files changed

+166
-197
lines changed

SymfonyCustom/Sniffs/Arrays/ArrayDeclarationSniff.php

Lines changed: 68 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -325,53 +325,35 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
325325

326326
// Find all the double arrows that reside in this scope.
327327
for ($nextToken = ($stackPtr + 1); $nextToken < $arrayEnd; $nextToken++) {
328-
// Skip bracketed statements, like function calls.
329-
if (T_OPEN_PARENTHESIS === $tokens[$nextToken]['code']
330-
&& (false === isset($tokens[$nextToken]['parenthesis_owner'])
331-
|| $tokens[$nextToken]['parenthesis_owner'] !== $stackPtr)
332-
) {
333-
$nextToken = $tokens[$nextToken]['parenthesis_closer'];
334-
continue;
335-
}
336-
337-
if (T_ARRAY === $tokens[$nextToken]['code']
338-
|| T_OPEN_SHORT_ARRAY === $tokens[$nextToken]['code']
339-
|| T_CLOSURE === $tokens[$nextToken]['code']
340-
) {
341-
// Let subsequent calls of this test handle nested arrays.
342-
if (T_DOUBLE_ARROW !== $tokens[$lastToken]['code']) {
343-
$indices[] = ['value' => $nextToken];
344-
$lastToken = $nextToken;
345-
}
346-
347-
if (T_ARRAY === $tokens[$nextToken]['code']) {
328+
// Skip array or function calls
329+
switch ($tokens[$nextToken]['code']) {
330+
case T_ARRAY:
348331
$nextToken = $tokens[$tokens[$nextToken]['parenthesis_opener']]['parenthesis_closer'];
349-
} elseif (T_OPEN_SHORT_ARRAY === $tokens[$nextToken]['code']) {
332+
continue;
333+
case T_OPEN_SHORT_ARRAY:
350334
$nextToken = $tokens[$nextToken]['bracket_closer'];
351-
} else {
352-
// T_CLOSURE.
335+
continue;
336+
case T_CLOSURE:
353337
$nextToken = $tokens[$nextToken]['scope_closer'];
354-
}
355-
356-
$nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextToken + 1), null, true);
357-
if (T_COMMA !== $tokens[$nextToken]['code']) {
358-
$nextToken--;
359-
} else {
360-
$lastToken = $nextToken;
361-
}
362-
363-
continue;
338+
continue;
339+
case T_OPEN_PARENTHESIS:
340+
$parenthesisOwner = $tokens[$nextToken]['parenthesis_owner'];
341+
if (false === isset($parenthesisOwner) || $parenthesisOwner !== $stackPtr) {
342+
$nextToken = $tokens[$nextToken]['parenthesis_closer'];
343+
continue;
344+
}
345+
break;
364346
}
365347

366-
if (T_DOUBLE_ARROW !== $tokens[$nextToken]['code']
367-
&& T_COMMA !== $tokens[$nextToken]['code']
348+
if (!in_array($tokens[$nextToken]['code'], [T_DOUBLE_ARROW, T_COMMA])
349+
&& $nextToken !== $arrayEnd - 1
368350
) {
369351
continue;
370352
}
371353

372354
$currentEntry = [];
373355

374-
if (T_COMMA === $tokens[$nextToken]['code']) {
356+
if (T_COMMA === $tokens[$nextToken]['code'] || $nextToken === $arrayEnd - 1) {
375357
$stackPtrCount = 0;
376358
if (true === isset($tokens[$stackPtr]['nested_parenthesis'])) {
377359
$stackPtrCount = count($tokens[$stackPtr]['nested_parenthesis']);
@@ -393,43 +375,41 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
393375
continue;
394376
}
395377

396-
if (true === $keyUsed && T_COMMA === $tokens[$lastToken]['code']) {
397-
$error = 'No key specified for array entry; first entry specifies key';
398-
$phpcsFile->addError($error, $nextToken, 'NoKeySpecified');
399-
400-
return;
401-
}
378+
$valueContent = $phpcsFile->findNext(
379+
Tokens::$emptyTokens,
380+
($lastToken + 1),
381+
$nextToken,
382+
true
383+
);
402384

403-
if (false === $keyUsed) {
404-
if (T_WHITESPACE === $tokens[($nextToken - 1)]['code']) {
405-
$content = $tokens[($nextToken - 2)]['content'];
406-
if ($tokens[($nextToken - 1)]['content'] === $phpcsFile->eolChar) {
407-
$spaceLength = 'newline';
408-
} else {
409-
$spaceLength = $tokens[($nextToken - 1)]['length'];
410-
}
385+
if (false !== $valueContent && T_DOUBLE_ARROW !== $tokens[$lastToken]['code']) {
386+
if (true === $keyUsed) {
387+
$error = 'No key specified for array entry; first entry specifies key';
388+
$phpcsFile->addError($error, $nextToken, 'NoKeySpecified');
389+
} else {
390+
$singleUsed = true;
391+
}
411392

412-
$error = 'Expected 0 spaces between "%s" and comma; %s found';
413-
$data = [
414-
$content,
415-
$spaceLength,
416-
];
393+
$indices[] = ['value' => $valueContent];
394+
}
417395

418-
$fix = $phpcsFile->addFixableError($error, $nextToken, 'SpaceBeforeComma', $data);
419-
if (true === $fix) {
420-
$phpcsFile->fixer->replaceToken(($nextToken - 1), '');
421-
}
396+
if (T_COMMA === $tokens[$nextToken]['code']
397+
&& T_WHITESPACE === $tokens[($nextToken - 1)]['code']
398+
) {
399+
$content = $tokens[($nextToken - 2)]['content'];
400+
if ($tokens[($nextToken - 1)]['content'] === $phpcsFile->eolChar) {
401+
$spaceLength = 'newline';
402+
} else {
403+
$spaceLength = $tokens[($nextToken - 1)]['length'];
422404
}
423405

424-
$valueContent = $phpcsFile->findNext(
425-
Tokens::$emptyTokens,
426-
($lastToken + 1),
427-
$nextToken,
428-
true
429-
);
406+
$error = 'Expected 0 spaces between "%s" and comma; %s found';
407+
$data = [$content, $spaceLength];
430408

431-
$indices[] = ['value' => $valueContent];
432-
$singleUsed = true;
409+
$fix = $phpcsFile->addFixableError($error, $nextToken, 'SpaceBeforeComma', $data);
410+
if (true === $fix) {
411+
$phpcsFile->fixer->replaceToken(($nextToken - 1), '');
412+
}
433413
}
434414

435415
$lastToken = $nextToken;
@@ -440,12 +420,11 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
440420
if (true === $singleUsed) {
441421
$error = 'Key specified for array entry; first entry has no key';
442422
$phpcsFile->addError($error, $nextToken, 'KeySpecified');
443-
444-
return;
423+
} else {
424+
$keyUsed = true;
445425
}
446426

447427
$currentEntry['arrow'] = $nextToken;
448-
$keyUsed = true;
449428

450429
// Find the start of index that uses this double arrow.
451430
$indexEnd = $phpcsFile->findPrevious(T_WHITESPACE, ($nextToken - 1), $arrayStart, true);
@@ -481,18 +460,7 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
481460
}
482461
}
483462

484-
/*
485-
This section checks for arrays that don't specify keys.
486-
487-
Arrays such as:
488-
array(
489-
'aaa',
490-
'bbb',
491-
'd',
492-
);
493-
*/
494-
495-
if (false === $keyUsed && false === empty($indices)) {
463+
if (false === empty($indices)) {
496464
$count = count($indices);
497465
$lastIndex = $indices[($count - 1)]['value'];
498466

@@ -514,15 +482,22 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
514482
$phpcsFile->recordMetric($stackPtr, 'Array end comma', 'yes');
515483
}
516484

517-
$lastValueLine = false;
485+
$lastValueLine = $stackPtr;
518486
foreach ($indices as $value) {
487+
if (false === empty($value['arrow'])) {
488+
// Array value with arrow are checked later cause there is more checks.
489+
continue;
490+
}
491+
519492
if (true === empty($value['value'])) {
520-
// Array was malformed and we couldn't figure out
521-
// the array value correctly, so we have to ignore it.
493+
// Array was malformed, so we have to ignore it.
522494
// Other parts of this sniff will correct the error.
523495
continue;
524496
}
525497

498+
$lastValue = $phpcsFile->findPrevious(T_COMMA, $value['value'] - 1, $lastValueLine);
499+
$lastValueLine = $lastValue ? $tokens[$lastValue]['line'] : false;
500+
526501
if (false !== $lastValueLine && $tokens[$value['value']]['line'] === $lastValueLine) {
527502
$error = 'Each value in a multi-line array must be on a new line';
528503
$fix = $phpcsFile->addFixableError($error, $value['value'], 'ValueNoNewline');
@@ -552,8 +527,6 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
552527
}
553528
}
554529
}
555-
556-
$lastValueLine = $tokens[$value['value']]['line'];
557530
}
558531
}
559532

@@ -583,14 +556,12 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
583556
will also cause an error in the value's alignment. If the arrow were
584557
to be moved back one space however, then both errors would be fixed.
585558
*/
586-
587559
$numValues = count($indices);
588560

589561
$indicesStart = ($currentIndent + $this->indent + 1);
590562
$arrowStart = ($indicesStart + $maxLength + 1);
591563
$valueStart = ($arrowStart + 3);
592-
$indexLine = $tokens[$stackPtr]['line'];
593-
$lastIndexLine = null;
564+
$lastIndexLine = $tokens[$stackPtr]['line'];
594565
foreach ($indices as $index) {
595566
if (isset($index['index']) === false) {
596567
// Array value only.
@@ -605,7 +576,8 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
605576
continue;
606577
}
607578

608-
$lastIndexLine = $indexLine;
579+
$lastIndex = $phpcsFile->findPrevious(T_COMMA, $index['index'] - 1, $lastIndexLine);
580+
$lastIndexLine = $lastIndex ? $tokens[$lastIndex]['line'] : false;
609581
$indexLine = $tokens[$index['index']]['line'];
610582

611583
if ($indexLine === $tokens[$stackPtr]['line']) {
@@ -652,16 +624,17 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
652624
}
653625

654626
if ($tokens[$index['arrow']]['column'] !== $arrowStart) {
655-
$expected = ($arrowStart - (mb_strlen($index['index_content']) + $tokens[$index['index']]['column']));
627+
$expected = ($arrowStart
628+
- (mb_strlen($index['index_content']) + $tokens[$index['index']]['column']));
656629
$found = $tokens[$index['arrow']]['column']
657630
- (mb_strlen($index['index_content']) + $tokens[$index['index']]['column']);
658631

659632
if ($found < 0) {
660633
$found = 'newline';
661634
}
662635

663-
$error = 'Array double arrow not aligned correctly; expected %s space(s) but found %s';
664-
$data = [$expected, $found];
636+
$error = 'Array double arrow not aligned correctly; expected %s space(s) but found %s';
637+
$data = [$expected, $found];
665638

666639
if ('newline' !== $found || false === $this->ignoreNewLines) {
667640
$fix = $phpcsFile->addFixableError($error, $index['arrow'], 'DoubleArrowNotAligned', $data);
@@ -697,10 +670,7 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
697670

698671
if ('newline' !== $found || false === $this->ignoreNewLines) {
699672
$error = 'Array value not aligned correctly; expected %s space(s) but found %s';
700-
$data = [
701-
$expected,
702-
$found,
703-
];
673+
$data = [$expected, $found];
704674

705675
$fix = $phpcsFile->addFixableError($error, $index['arrow'], 'ValueNotAligned', $data);
706676
if (true === $fix) {
@@ -721,78 +691,6 @@ public function processMultiLineArray(File $phpcsFile, $stackPtr, $arrayStart, $
721691
}
722692
}
723693
}
724-
725-
// Check each line ends in a comma.
726-
$valueLine = $tokens[$index['value']]['line'];
727-
$nextComma = false;
728-
for ($i = $index['value']; $i < $arrayEnd; $i++) {
729-
// Skip bracketed statements, like function calls.
730-
if (T_OPEN_PARENTHESIS === $tokens[$i]['code']) {
731-
$i = $tokens[$i]['parenthesis_closer'];
732-
$valueLine = $tokens[$i]['line'];
733-
continue;
734-
}
735-
736-
if (T_ARRAY === $tokens[$i]['code']) {
737-
$i = $tokens[$tokens[$i]['parenthesis_opener']]['parenthesis_closer'];
738-
$valueLine = $tokens[$i]['line'];
739-
continue;
740-
}
741-
742-
// Skip to the end of multi-line strings.
743-
if (isset(Tokens::$stringTokens[$tokens[$i]['code']]) === true) {
744-
$i = $phpcsFile->findNext($tokens[$i]['code'], ($i + 1), null, true);
745-
$i--;
746-
$valueLine = $tokens[$i]['line'];
747-
continue;
748-
}
749-
750-
if (T_OPEN_SHORT_ARRAY === $tokens[$i]['code']) {
751-
$i = $tokens[$i]['bracket_closer'];
752-
$valueLine = $tokens[$i]['line'];
753-
continue;
754-
}
755-
756-
if (T_CLOSURE === $tokens[$i]['code']) {
757-
$i = $tokens[$i]['scope_closer'];
758-
$valueLine = $tokens[$i]['line'];
759-
continue;
760-
}
761-
762-
if (T_COMMA === $tokens[$i]['code']) {
763-
$nextComma = $i;
764-
break;
765-
}
766-
}
767-
768-
if (false === $nextComma || ($tokens[$nextComma]['line'] !== $valueLine)) {
769-
$error = 'Each line in an array declaration must end in a comma';
770-
$fix = $phpcsFile->addFixableError($error, $index['value'], 'NoComma');
771-
772-
if (true === $fix) {
773-
// Find the end of the line and put a comma there.
774-
for ($i = ($index['value'] + 1); $i < $arrayEnd; $i++) {
775-
if ($tokens[$i]['line'] > $valueLine) {
776-
break;
777-
}
778-
}
779-
780-
$phpcsFile->fixer->addContentBefore(($i - 1), ',');
781-
}
782-
}
783-
784-
// Check that there is no space before the comma.
785-
if (false !== $nextComma && T_WHITESPACE === $tokens[($nextComma - 1)]['code']) {
786-
$content = $tokens[($nextComma - 2)]['content'];
787-
$spaceLength = $tokens[($nextComma - 1)]['length'];
788-
$error = 'Expected 0 spaces between "%s" and comma; %s found';
789-
$data = [$content, $spaceLength];
790-
791-
$fix = $phpcsFile->addFixableError($error, $nextComma, 'SpaceBeforeComma', $data);
792-
if (true === $fix) {
793-
$phpcsFile->fixer->replaceToken(($nextComma - 1), '');
794-
}
795-
}
796694
}
797695
}
798696
}

SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,41 @@ class TestClass
7070
'short_name' => 'big'
7171
);
7272

73+
$array1 = [
74+
[
75+
'<span>',
76+
]
77+
,
78+
[
79+
'<span>',
80+
],
81+
];
82+
83+
$array2 = array(
84+
[
85+
'<span>',
86+
],[
87+
'<span>',
88+
],
89+
);
90+
91+
$array3 = array(
92+
'a' => ['<span>']
93+
,['<span>'],
94+
'b' => ['<span>']
95+
,['<span>'],
96+
);
97+
98+
$array4 = array(
99+
['<span>']
100+
,'a' => ['<span>'],
101+
['<span>']
102+
,'b' => ['<span>']
103+
);
104+
73105
$utf8 = array(
74-
'/[áàâãªäå]/u' => 'a',
75-
'/[ÁÀÂÃÄÅ]/u' => 'A',
106+
'/[áàâãªäå]/u' => 'a'
107+
,'/[ÁÀÂÃÄÅ]/u' => 'A',
76108
'/[ÍÌÎÏ]/u' => 'I',
77109
'/[íìîï]/u' => 'i',
78110
'/[éèêë]/u' => 'e',

0 commit comments

Comments
 (0)