235 lines
8.9 KiB
PHP
235 lines
8.9 KiB
PHP
<?php
|
|
/**
|
|
* Processes single and multi-line arrays.
|
|
*
|
|
* @author Greg Sherwood <gsherwood@squiz.net>
|
|
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
|
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
|
*/
|
|
|
|
namespace PHP_CodeSniffer\Sniffs;
|
|
|
|
use PHP_CodeSniffer\Files\File;
|
|
use PHP_CodeSniffer\Util\Tokens;
|
|
|
|
abstract class AbstractArraySniff implements Sniff
|
|
{
|
|
|
|
|
|
/**
|
|
* Returns an array of tokens this test wants to listen for.
|
|
*
|
|
* @return array
|
|
*/
|
|
final public function register()
|
|
{
|
|
return [
|
|
T_ARRAY,
|
|
T_OPEN_SHORT_ARRAY,
|
|
];
|
|
|
|
}//end register()
|
|
|
|
|
|
/**
|
|
* Processes this sniff, when one of its tokens is encountered.
|
|
*
|
|
* @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked.
|
|
* @param int $stackPtr The position of the current token in
|
|
* the stack passed in $tokens.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function process(File $phpcsFile, $stackPtr)
|
|
{
|
|
$tokens = $phpcsFile->getTokens();
|
|
|
|
if ($tokens[$stackPtr]['code'] === T_ARRAY) {
|
|
$phpcsFile->recordMetric($stackPtr, 'Short array syntax used', 'no');
|
|
|
|
$arrayStart = $tokens[$stackPtr]['parenthesis_opener'];
|
|
if (isset($tokens[$arrayStart]['parenthesis_closer']) === false) {
|
|
// Incomplete array.
|
|
return;
|
|
}
|
|
|
|
$arrayEnd = $tokens[$arrayStart]['parenthesis_closer'];
|
|
} else {
|
|
$phpcsFile->recordMetric($stackPtr, 'Short array syntax used', 'yes');
|
|
$arrayStart = $stackPtr;
|
|
$arrayEnd = $tokens[$stackPtr]['bracket_closer'];
|
|
}
|
|
|
|
$lastContent = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($arrayEnd - 1), null, true);
|
|
if ($tokens[$lastContent]['code'] === T_COMMA) {
|
|
// Last array item ends with a comma.
|
|
$phpcsFile->recordMetric($stackPtr, 'Array end comma', 'yes');
|
|
$lastArrayToken = $lastContent;
|
|
} else {
|
|
$phpcsFile->recordMetric($stackPtr, 'Array end comma', 'no');
|
|
$lastArrayToken = $arrayEnd;
|
|
}
|
|
|
|
if ($tokens[$stackPtr]['code'] === T_ARRAY) {
|
|
$lastToken = $tokens[$stackPtr]['parenthesis_opener'];
|
|
} else {
|
|
$lastToken = $stackPtr;
|
|
}
|
|
|
|
$keyUsed = false;
|
|
$indices = [];
|
|
|
|
for ($checkToken = ($stackPtr + 1); $checkToken <= $lastArrayToken; $checkToken++) {
|
|
// Skip bracketed statements, like function calls.
|
|
if ($tokens[$checkToken]['code'] === T_OPEN_PARENTHESIS
|
|
&& (isset($tokens[$checkToken]['parenthesis_owner']) === false
|
|
|| $tokens[$checkToken]['parenthesis_owner'] !== $stackPtr)
|
|
) {
|
|
$checkToken = $tokens[$checkToken]['parenthesis_closer'];
|
|
continue;
|
|
}
|
|
|
|
if ($tokens[$checkToken]['code'] === T_ARRAY
|
|
|| $tokens[$checkToken]['code'] === T_OPEN_SHORT_ARRAY
|
|
|| $tokens[$checkToken]['code'] === T_CLOSURE
|
|
) {
|
|
// Let subsequent calls of this test handle nested arrays.
|
|
if ($tokens[$lastToken]['code'] !== T_DOUBLE_ARROW) {
|
|
$indices[] = ['value_start' => $checkToken];
|
|
$lastToken = $checkToken;
|
|
}
|
|
|
|
if ($tokens[$checkToken]['code'] === T_ARRAY) {
|
|
$checkToken = $tokens[$tokens[$checkToken]['parenthesis_opener']]['parenthesis_closer'];
|
|
} else if ($tokens[$checkToken]['code'] === T_OPEN_SHORT_ARRAY) {
|
|
$checkToken = $tokens[$checkToken]['bracket_closer'];
|
|
} else {
|
|
// T_CLOSURE.
|
|
$checkToken = $tokens[$checkToken]['scope_closer'];
|
|
}
|
|
|
|
$checkToken = $phpcsFile->findNext(T_WHITESPACE, ($checkToken + 1), null, true);
|
|
$lastToken = $checkToken;
|
|
if ($tokens[$checkToken]['code'] !== T_COMMA) {
|
|
$checkToken--;
|
|
}
|
|
|
|
continue;
|
|
}//end if
|
|
|
|
if ($tokens[$checkToken]['code'] !== T_DOUBLE_ARROW
|
|
&& $tokens[$checkToken]['code'] !== T_COMMA
|
|
&& $checkToken !== $arrayEnd
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
if ($tokens[$checkToken]['code'] === T_COMMA
|
|
|| $checkToken === $arrayEnd
|
|
) {
|
|
$stackPtrCount = 0;
|
|
if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) {
|
|
$stackPtrCount = count($tokens[$stackPtr]['nested_parenthesis']);
|
|
}
|
|
|
|
$commaCount = 0;
|
|
if (isset($tokens[$checkToken]['nested_parenthesis']) === true) {
|
|
$commaCount = count($tokens[$checkToken]['nested_parenthesis']);
|
|
if ($tokens[$stackPtr]['code'] === T_ARRAY) {
|
|
// Remove parenthesis that are used to define the array.
|
|
$commaCount--;
|
|
}
|
|
}
|
|
|
|
if ($commaCount > $stackPtrCount) {
|
|
// This comma is inside more parenthesis than the ARRAY keyword,
|
|
// so it is actually a comma used to do things like
|
|
// separate arguments in a function call.
|
|
continue;
|
|
}
|
|
|
|
if ($keyUsed === false) {
|
|
$valueContent = $phpcsFile->findNext(
|
|
Tokens::$emptyTokens,
|
|
($lastToken + 1),
|
|
$checkToken,
|
|
true
|
|
);
|
|
|
|
$indices[] = ['value_start' => $valueContent];
|
|
}
|
|
|
|
$lastToken = $checkToken;
|
|
$keyUsed = false;
|
|
continue;
|
|
}//end if
|
|
|
|
if ($tokens[$checkToken]['code'] === T_DOUBLE_ARROW) {
|
|
$keyUsed = true;
|
|
|
|
// Find the start of index that uses this double arrow.
|
|
$indexEnd = $phpcsFile->findPrevious(T_WHITESPACE, ($checkToken - 1), $arrayStart, true);
|
|
$indexStart = $phpcsFile->findStartOfStatement($indexEnd);
|
|
|
|
// Find the value of this index.
|
|
$nextContent = $phpcsFile->findNext(
|
|
Tokens::$emptyTokens,
|
|
($checkToken + 1),
|
|
$arrayEnd,
|
|
true
|
|
);
|
|
|
|
$indices[] = [
|
|
'index_start' => $indexStart,
|
|
'index_end' => $indexEnd,
|
|
'arrow' => $checkToken,
|
|
'value_start' => $nextContent,
|
|
];
|
|
|
|
$lastToken = $checkToken;
|
|
}//end if
|
|
}//end for
|
|
|
|
if ($tokens[$arrayStart]['line'] === $tokens[$arrayEnd]['line']) {
|
|
$this->processSingleLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices);
|
|
} else {
|
|
$this->processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices);
|
|
}
|
|
|
|
}//end process()
|
|
|
|
|
|
/**
|
|
* Processes a single-line array definition.
|
|
*
|
|
* @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked.
|
|
* @param int $stackPtr The position of the current token
|
|
* in the stack passed in $tokens.
|
|
* @param int $arrayStart The token that starts the array definition.
|
|
* @param int $arrayEnd The token that ends the array definition.
|
|
* @param array $indices An array of token positions for the array keys,
|
|
* double arrows, and values.
|
|
*
|
|
* @return void
|
|
*/
|
|
abstract protected function processSingleLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices);
|
|
|
|
|
|
/**
|
|
* Processes a multi-line array definition.
|
|
*
|
|
* @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked.
|
|
* @param int $stackPtr The position of the current token
|
|
* in the stack passed in $tokens.
|
|
* @param int $arrayStart The token that starts the array definition.
|
|
* @param int $arrayEnd The token that ends the array definition.
|
|
* @param array $indices An array of token positions for the array keys,
|
|
* double arrows, and values.
|
|
*
|
|
* @return void
|
|
*/
|
|
abstract protected function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $arrayEnd, $indices);
|
|
|
|
|
|
}//end class
|