View source
<?php
namespace Drupal\Sniffs\Arrays;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;
class ArraySniff implements Sniff {
public $lineLimit = 80;
public function register() {
return [
T_ARRAY,
T_OPEN_SHORT_ARRAY,
];
}
public function process(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile
->getTokens();
$parenthesisOpener = 'parenthesis_opener';
$parenthesisCloser = 'parenthesis_closer';
if ($tokens[$stackPtr]['code'] === T_OPEN_SHORT_ARRAY) {
$parenthesisOpener = 'bracket_opener';
$parenthesisCloser = 'bracket_closer';
}
if ($tokens[$stackPtr][$parenthesisCloser] === null) {
return;
}
$lastItem = $phpcsFile
->findPrevious(Tokens::$emptyTokens, $tokens[$stackPtr][$parenthesisCloser] - 1, $stackPtr, true);
if ($lastItem === $tokens[$stackPtr][$parenthesisOpener]) {
return;
}
$isInlineArray = $tokens[$tokens[$stackPtr][$parenthesisOpener]]['line'] === $tokens[$tokens[$stackPtr][$parenthesisCloser]]['line'];
if ($tokens[$lastItem]['code'] !== T_COMMA && $isInlineArray === false && $tokens[$lastItem + 1]['code'] !== T_CLOSE_PARENTHESIS && $tokens[$lastItem + 1]['code'] !== T_CLOSE_SHORT_ARRAY && isset(Tokens::$heredocTokens[$tokens[$lastItem]['code']]) === false) {
$data = [
$tokens[$lastItem]['content'],
];
$fix = $phpcsFile
->addFixableWarning('A comma should follow the last multiline array item. Found: %s', $lastItem, 'CommaLastItem', $data);
if ($fix === true) {
$phpcsFile->fixer
->addContent($lastItem, ',');
}
return;
}
if ($isInlineArray === true) {
$arrayEnding = $tokens[$tokens[$stackPtr][$parenthesisCloser]]['column'];
if ($arrayEnding > $this->lineLimit) {
$pos = $stackPtr + 1;
while (($comma = $phpcsFile
->findNext(T_COMMA, $pos, $tokens[$stackPtr][$parenthesisCloser])) > 0) {
if (isset($tokens[$comma]['nested_parenthesis']) === false) {
break;
}
$end = array_slice($tokens[$comma]['nested_parenthesis'], -1, 1, true);
if ($end === [
$tokens[$stackPtr][$parenthesisOpener] => $tokens[$stackPtr][$parenthesisCloser],
]) {
break;
}
if (isset($tokens[$lastItem]['nested_parenthesis']) === true && $tokens[$comma]['nested_parenthesis'] === $tokens[$lastItem]['nested_parenthesis']) {
break;
}
$pos = $comma + 1;
}
if ($comma !== false) {
$error = 'The array declaration extends to column %s (the limit is %s). The array content should be split up over multiple lines';
$phpcsFile
->addError($error, $stackPtr, 'LongLineDeclaration', [
$arrayEnding,
$this->lineLimit,
]);
}
}
return;
}
$firstLineColumn = $tokens[$stackPtr]['column'];
for ($i = $stackPtr; $i >= 0; $i--) {
if ($tokens[$i]['code'] === T_OPEN_TAG) {
return;
}
if ($tokens[$i]['code'] !== T_WHITESPACE) {
$firstLineColumn = $tokens[$i]['column'];
$trimmed = ltrim($tokens[$i]['content']);
if ($trimmed !== $tokens[$i]['content']) {
$firstLineColumn = $firstLineColumn + strpos($tokens[$i]['content'], $trimmed);
}
}
if ($tokens[$i]['column'] === 1) {
break;
}
}
$lineStart = $stackPtr;
while ($lineStart < $tokens[$stackPtr][$parenthesisCloser]) {
$newLineStart = $lineStart;
$currentLine = $tokens[$newLineStart]['line'];
while ($currentLine >= $tokens[$newLineStart]['line']) {
$newLineStart = $phpcsFile
->findNext(Tokens::$emptyTokens, $newLineStart + 1, $tokens[$stackPtr][$parenthesisCloser] + 1, true);
if ($newLineStart === false) {
break 2;
}
if ($tokens[$newLineStart]['code'] === T_ARRAY) {
$newLineStart = $tokens[$newLineStart]['parenthesis_closer'];
$currentLine = $tokens[$newLineStart]['line'];
}
if ($tokens[$newLineStart]['code'] === T_OPEN_SHORT_ARRAY) {
$newLineStart = $tokens[$newLineStart]['bracket_closer'];
$currentLine = $tokens[$newLineStart]['line'];
}
if ($tokens[$newLineStart]['conditions'] !== $tokens[$stackPtr]['conditions']) {
$conditionKeys = array_keys($tokens[$newLineStart]['conditions']);
$closureToken = end($conditionKeys);
if (isset($tokens[$closureToken]['scope_closer']) === true) {
$newLineStart = $tokens[$closureToken]['scope_closer'];
$currentLine = $tokens[$closureToken]['line'];
}
else {
$currentLine++;
}
}
}
if ($newLineStart === $tokens[$stackPtr][$parenthesisCloser]) {
if ($tokens[$newLineStart]['column'] !== $firstLineColumn) {
$error = 'Array closing indentation error, expected %s spaces but found %s';
$data = [
$firstLineColumn - 1,
$tokens[$newLineStart]['column'] - 1,
];
$fix = $phpcsFile
->addFixableError($error, $newLineStart, 'ArrayClosingIndentation', $data);
if ($fix === true) {
if ($tokens[$newLineStart]['column'] === 1) {
$phpcsFile->fixer
->addContentBefore($newLineStart, str_repeat(' ', $firstLineColumn - 1));
}
else {
$phpcsFile->fixer
->replaceToken($newLineStart - 1, str_repeat(' ', $firstLineColumn - 1));
}
}
}
break;
}
$expectedColumn = $firstLineColumn + 2;
if ($tokens[$newLineStart]['code'] === T_OBJECT_OPERATOR) {
$expectedColumn += 2;
}
if ($tokens[$newLineStart]['column'] !== $expectedColumn) {
$innerNesting = empty($tokens[$newLineStart]['nested_parenthesis']) === false && end($tokens[$newLineStart]['nested_parenthesis']) < $tokens[$stackPtr][$parenthesisCloser];
$isMultiLineString = $tokens[$newLineStart - 1]['code'] === T_CONSTANT_ENCAPSED_STRING && substr($tokens[$newLineStart - 1]['content'], -1) === $phpcsFile->eolChar;
$nowDoc = isset(Tokens::$heredocTokens[$tokens[$newLineStart]['code']]);
if ($innerNesting === false && $isMultiLineString === false && $nowDoc === false) {
$error = 'Array indentation error, expected %s spaces but found %s';
$data = [
$expectedColumn - 1,
$tokens[$newLineStart]['column'] - 1,
];
$fix = $phpcsFile
->addFixableError($error, $newLineStart, 'ArrayIndentation', $data);
if ($fix === true) {
if ($tokens[$newLineStart]['column'] === 1) {
$phpcsFile->fixer
->addContentBefore($newLineStart, str_repeat(' ', $expectedColumn - 1));
}
else {
$phpcsFile->fixer
->replaceToken($newLineStart - 1, str_repeat(' ', $expectedColumn - 1));
}
}
}
}
$lineStart = $newLineStart;
}
}
}