xarxaprod-wp-theme/vendor/phpcompatibility/php-compatibility/PHPCompatibility/PHPCSHelper.php

679 lines
24 KiB
PHP

<?php
/**
* PHPCompatibility, an external standard for PHP_CodeSniffer.
*
* @package PHPCompatibility
* @copyright 2012-2019 PHPCompatibility Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCompatibility/PHPCompatibility
*/
namespace PHPCompatibility;
use PHP_CodeSniffer_Exception as PHPCS_Exception;
use PHP_CodeSniffer_File as File;
use PHP_CodeSniffer_Tokens as Tokens;
/**
* PHPCS cross-version compatibility helper class.
*
* A number of PHPCS classes were split up into several classes in PHPCS 3.x
* Those classes cannot be aliased as they don't represent the same object.
* This class provides helper methods for functions which were contained in
* one of these classes and which are used within the PHPCompatibility library.
*
* Additionally, this class contains some duplicates of PHPCS native methods.
* These methods have received bug fixes or improved functionality between the
* lowest supported PHPCS version and the latest PHPCS stable version and
* to provide the same results cross-version, PHPCompatibility needs to use
* the up-to-date versions of these methods.
*
* @since 8.0.0
* @since 8.2.0 The duplicate PHPCS methods have been moved from the `Sniff`
* base class to this class.
*/
class PHPCSHelper
{
/**
* Get the PHPCS version number.
*
* @since 8.0.0
*
* @return string
*/
public static function getVersion()
{
if (\defined('\PHP_CodeSniffer\Config::VERSION')) {
// PHPCS 3.x.
return \PHP_CodeSniffer\Config::VERSION;
} else {
// PHPCS 2.x.
return \PHP_CodeSniffer::VERSION;
}
}
/**
* Pass config data to PHPCS.
*
* PHPCS cross-version compatibility helper.
*
* @since 8.0.0
*
* @param string $key The name of the config value.
* @param string|null $value The value to set. If null, the config entry
* is deleted, reverting it to the default value.
* @param boolean $temp Set this config data temporarily for this script run.
* This will not write the config data to the config file.
*
* @return void
*/
public static function setConfigData($key, $value, $temp = false)
{
if (method_exists('\PHP_CodeSniffer\Config', 'setConfigData')) {
// PHPCS 3.x.
\PHP_CodeSniffer\Config::setConfigData($key, $value, $temp);
} else {
// PHPCS 2.x.
\PHP_CodeSniffer::setConfigData($key, $value, $temp);
}
}
/**
* Get the value of a single PHPCS config key.
*
* @since 8.0.0
*
* @param string $key The name of the config value.
*
* @return string|null
*/
public static function getConfigData($key)
{
if (method_exists('\PHP_CodeSniffer\Config', 'getConfigData')) {
// PHPCS 3.x.
return \PHP_CodeSniffer\Config::getConfigData($key);
} else {
// PHPCS 2.x.
return \PHP_CodeSniffer::getConfigData($key);
}
}
/**
* Get the value of a single PHPCS config key.
*
* This config key can be set in the `CodeSniffer.conf` file, on the
* command-line or in a ruleset.
*
* @since 8.2.0
*
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param string $key The name of the config value.
*
* @return string|null
*/
public static function getCommandLineData(File $phpcsFile, $key)
{
if (class_exists('\PHP_CodeSniffer\Config')) {
// PHPCS 3.x.
$config = $phpcsFile->config;
if (isset($config->{$key})) {
return $config->{$key};
}
} else {
// PHPCS 2.x.
$config = $phpcsFile->phpcs->cli->getCommandLineValues();
if (isset($config[$key])) {
return $config[$key];
}
}
return null;
}
/**
* Returns the position of the first non-whitespace token in a statement.
*
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
* class and introduced in PHPCS 2.1.0 and improved in PHPCS 2.7.1.
*
* Once the minimum supported PHPCS version for this standard goes beyond
* that, this method can be removed and calls to it replaced with
* `$phpcsFile->findStartOfStatement($start, $ignore)` calls.
*
* Last synced with PHPCS version: PHPCS 3.3.2 at commit 6ad28354c04b364c3c71a34e4a18b629cc3b231e}
*
* @since 9.1.0
*
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
* @param int $start The position to start searching from in the token stack.
* @param int|array $ignore Token types that should not be considered stop points.
*
* @return int
*/
public static function findStartOfStatement(File $phpcsFile, $start, $ignore = null)
{
if (version_compare(self::getVersion(), '2.7.1', '>=') === true) {
return $phpcsFile->findStartOfStatement($start, $ignore);
}
$tokens = $phpcsFile->getTokens();
$endTokens = Tokens::$blockOpeners;
$endTokens[\T_COLON] = true;
$endTokens[\T_COMMA] = true;
$endTokens[\T_DOUBLE_ARROW] = true;
$endTokens[\T_SEMICOLON] = true;
$endTokens[\T_OPEN_TAG] = true;
$endTokens[\T_CLOSE_TAG] = true;
$endTokens[\T_OPEN_SHORT_ARRAY] = true;
if ($ignore !== null) {
$ignore = (array) $ignore;
foreach ($ignore as $code) {
if (isset($endTokens[$code]) === true) {
unset($endTokens[$code]);
}
}
}
$lastNotEmpty = $start;
for ($i = $start; $i >= 0; $i--) {
if (isset($endTokens[$tokens[$i]['code']]) === true) {
// Found the end of the previous statement.
return $lastNotEmpty;
}
if (isset($tokens[$i]['scope_opener']) === true
&& $i === $tokens[$i]['scope_closer']
) {
// Found the end of the previous scope block.
return $lastNotEmpty;
}
// Skip nested statements.
if (isset($tokens[$i]['bracket_opener']) === true
&& $i === $tokens[$i]['bracket_closer']
) {
$i = $tokens[$i]['bracket_opener'];
} elseif (isset($tokens[$i]['parenthesis_opener']) === true
&& $i === $tokens[$i]['parenthesis_closer']
) {
$i = $tokens[$i]['parenthesis_opener'];
}
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) {
$lastNotEmpty = $i;
}
}//end for
return 0;
}
/**
* Returns the position of the last non-whitespace token in a statement.
*
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
* class and introduced in PHPCS 2.1.0 and improved in PHPCS 2.7.1 and 3.3.0.
*
* Once the minimum supported PHPCS version for this standard goes beyond
* that, this method can be removed and calls to it replaced with
* `$phpcsFile->findEndOfStatement($start, $ignore)` calls.
*
* Last synced with PHPCS version: PHPCS 3.3.0-alpha at commit f5d899dcb5c534a1c3cca34668624517856ba823}
*
* @since 8.2.0
*
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
* @param int $start The position to start searching from in the token stack.
* @param int|array $ignore Token types that should not be considered stop points.
*
* @return int
*/
public static function findEndOfStatement(File $phpcsFile, $start, $ignore = null)
{
if (version_compare(self::getVersion(), '3.3.0', '>=') === true) {
return $phpcsFile->findEndOfStatement($start, $ignore);
}
$tokens = $phpcsFile->getTokens();
$endTokens = array(
\T_COLON => true,
\T_COMMA => true,
\T_DOUBLE_ARROW => true,
\T_SEMICOLON => true,
\T_CLOSE_PARENTHESIS => true,
\T_CLOSE_SQUARE_BRACKET => true,
\T_CLOSE_CURLY_BRACKET => true,
\T_CLOSE_SHORT_ARRAY => true,
\T_OPEN_TAG => true,
\T_CLOSE_TAG => true,
);
if ($ignore !== null) {
$ignore = (array) $ignore;
foreach ($ignore as $code) {
if (isset($endTokens[$code]) === true) {
unset($endTokens[$code]);
}
}
}
$lastNotEmpty = $start;
for ($i = $start; $i < $phpcsFile->numTokens; $i++) {
if ($i !== $start && isset($endTokens[$tokens[$i]['code']]) === true) {
// Found the end of the statement.
if ($tokens[$i]['code'] === \T_CLOSE_PARENTHESIS
|| $tokens[$i]['code'] === \T_CLOSE_SQUARE_BRACKET
|| $tokens[$i]['code'] === \T_CLOSE_CURLY_BRACKET
|| $tokens[$i]['code'] === \T_CLOSE_SHORT_ARRAY
|| $tokens[$i]['code'] === \T_OPEN_TAG
|| $tokens[$i]['code'] === \T_CLOSE_TAG
) {
return $lastNotEmpty;
}
return $i;
}
// Skip nested statements.
if (isset($tokens[$i]['scope_closer']) === true
&& ($i === $tokens[$i]['scope_opener']
|| $i === $tokens[$i]['scope_condition'])
) {
if ($i === $start && isset(Tokens::$scopeOpeners[$tokens[$i]['code']]) === true) {
return $tokens[$i]['scope_closer'];
}
$i = $tokens[$i]['scope_closer'];
} elseif (isset($tokens[$i]['bracket_closer']) === true
&& $i === $tokens[$i]['bracket_opener']
) {
$i = $tokens[$i]['bracket_closer'];
} elseif (isset($tokens[$i]['parenthesis_closer']) === true
&& $i === $tokens[$i]['parenthesis_opener']
) {
$i = $tokens[$i]['parenthesis_closer'];
}
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) {
$lastNotEmpty = $i;
}
}//end for
return ($phpcsFile->numTokens - 1);
}
/**
* Returns the name of the class that the specified class extends
* (works for classes, anonymous classes and interfaces).
*
* Returns FALSE on error or if there is no extended class name.
*
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
* class, but with some improvements which have been introduced in
* PHPCS 2.8.0.
* {@link https://github.com/squizlabs/PHP_CodeSniffer/commit/0011d448119d4c568e3ac1f825ae78815bf2cc34}.
*
* Once the minimum supported PHPCS version for this standard goes beyond
* that, this method can be removed and calls to it replaced with
* `$phpcsFile->findExtendedClassName($stackPtr)` calls.
*
* Last synced with PHPCS version: PHPCS 3.1.0-alpha at commit a9efcc9b0703f3f9f4a900623d4e97128a6aafc6}
*
* @since 7.1.4
* @since 8.2.0 Moved from the `Sniff` class to this class.
*
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
* @param int $stackPtr The position of the class token in the stack.
*
* @return string|false
*/
public static function findExtendedClassName(File $phpcsFile, $stackPtr)
{
if (version_compare(self::getVersion(), '3.1.0', '>=') === true) {
return $phpcsFile->findExtendedClassName($stackPtr);
}
$tokens = $phpcsFile->getTokens();
// Check for the existence of the token.
if (isset($tokens[$stackPtr]) === false) {
return false;
}
if ($tokens[$stackPtr]['code'] !== \T_CLASS
&& $tokens[$stackPtr]['type'] !== 'T_ANON_CLASS'
&& $tokens[$stackPtr]['type'] !== 'T_INTERFACE'
) {
return false;
}
if (isset($tokens[$stackPtr]['scope_closer']) === false) {
return false;
}
$classCloserIndex = $tokens[$stackPtr]['scope_closer'];
$extendsIndex = $phpcsFile->findNext(\T_EXTENDS, $stackPtr, $classCloserIndex);
if ($extendsIndex === false) {
return false;
}
$find = array(
\T_NS_SEPARATOR,
\T_STRING,
\T_WHITESPACE,
);
$end = $phpcsFile->findNext($find, ($extendsIndex + 1), $classCloserIndex, true);
$name = $phpcsFile->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1));
$name = trim($name);
if ($name === '') {
return false;
}
return $name;
}
/**
* Returns the name(s) of the interface(s) that the specified class implements.
*
* Returns FALSE on error or if there are no implemented interface names.
*
* {@internal Duplicate of same method as introduced in PHPCS 2.7.
* This method also includes an improvement we use which was only introduced
* in PHPCS 2.8.0, so only defer to upstream for higher versions.
* Once the minimum supported PHPCS version for this sniff library goes beyond
* that, this method can be removed and calls to it replaced with
* `$phpcsFile->findImplementedInterfaceNames($stackPtr)` calls.}
*
* @since 7.0.3
* @since 8.2.0 Moved from the `Sniff` class to this class.
*
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the class token.
*
* @return array|false
*/
public static function findImplementedInterfaceNames(File $phpcsFile, $stackPtr)
{
if (version_compare(self::getVersion(), '2.7.1', '>') === true) {
return $phpcsFile->findImplementedInterfaceNames($stackPtr);
}
$tokens = $phpcsFile->getTokens();
// Check for the existence of the token.
if (isset($tokens[$stackPtr]) === false) {
return false;
}
if ($tokens[$stackPtr]['code'] !== \T_CLASS
&& $tokens[$stackPtr]['type'] !== 'T_ANON_CLASS'
) {
return false;
}
if (isset($tokens[$stackPtr]['scope_closer']) === false) {
return false;
}
$classOpenerIndex = $tokens[$stackPtr]['scope_opener'];
$implementsIndex = $phpcsFile->findNext(\T_IMPLEMENTS, $stackPtr, $classOpenerIndex);
if ($implementsIndex === false) {
return false;
}
$find = array(
\T_NS_SEPARATOR,
\T_STRING,
\T_WHITESPACE,
\T_COMMA,
);
$end = $phpcsFile->findNext($find, ($implementsIndex + 1), ($classOpenerIndex + 1), true);
$name = $phpcsFile->getTokensAsString(($implementsIndex + 1), ($end - $implementsIndex - 1));
$name = trim($name);
if ($name === '') {
return false;
} else {
$names = explode(',', $name);
$names = array_map('trim', $names);
return $names;
}
}
/**
* Returns the method parameters for the specified function token.
*
* Each parameter is in the following format:
*
* <code>
* 0 => array(
* 'name' => '$var', // The variable name.
* 'token' => integer, // The stack pointer to the variable name.
* 'content' => string, // The full content of the variable definition.
* 'pass_by_reference' => boolean, // Is the variable passed by reference?
* 'variable_length' => boolean, // Is the param of variable length through use of `...` ?
* 'type_hint' => string, // The type hint for the variable.
* 'type_hint_token' => integer, // The stack pointer to the type hint
* // or false if there is no type hint.
* 'nullable_type' => boolean, // Is the variable using a nullable type?
* )
* </code>
*
* Parameters with default values have an additional array index of
* 'default' with the value of the default as a string.
*
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File`
* class.
*
* Last synced with PHPCS version: PHPCS 3.3.0-alpha at commit 53a28408d345044c0360c2c1b4a2aaebf4a3b8c9}
*
* @since 7.0.3
* @since 8.2.0 Moved from the `Sniff` class to this class.
*
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile.
* @param int $stackPtr The position in the stack of the
* function token to acquire the
* parameters for.
*
* @return array|false
* @throws \PHP_CodeSniffer_Exception If the specified $stackPtr is not of
* type T_FUNCTION or T_CLOSURE.
*/
public static function getMethodParameters(File $phpcsFile, $stackPtr)
{
if (version_compare(self::getVersion(), '3.3.0', '>=') === true) {
return $phpcsFile->getMethodParameters($stackPtr);
}
$tokens = $phpcsFile->getTokens();
// Check for the existence of the token.
if (isset($tokens[$stackPtr]) === false) {
return false;
}
if ($tokens[$stackPtr]['code'] !== \T_FUNCTION
&& $tokens[$stackPtr]['code'] !== \T_CLOSURE
) {
throw new PHPCS_Exception('$stackPtr must be of type T_FUNCTION or T_CLOSURE');
}
$opener = $tokens[$stackPtr]['parenthesis_opener'];
$closer = $tokens[$stackPtr]['parenthesis_closer'];
$vars = array();
$currVar = null;
$paramStart = ($opener + 1);
$defaultStart = null;
$paramCount = 0;
$passByReference = false;
$variableLength = false;
$typeHint = '';
$typeHintToken = false;
$nullableType = false;
for ($i = $paramStart; $i <= $closer; $i++) {
// Check to see if this token has a parenthesis or bracket opener. If it does
// it's likely to be an array which might have arguments in it. This
// could cause problems in our parsing below, so lets just skip to the
// end of it.
if (isset($tokens[$i]['parenthesis_opener']) === true) {
// Don't do this if it's the close parenthesis for the method.
if ($i !== $tokens[$i]['parenthesis_closer']) {
$i = ($tokens[$i]['parenthesis_closer'] + 1);
}
}
if (isset($tokens[$i]['bracket_opener']) === true) {
// Don't do this if it's the close parenthesis for the method.
if ($i !== $tokens[$i]['bracket_closer']) {
$i = ($tokens[$i]['bracket_closer'] + 1);
}
}
switch ($tokens[$i]['type']) {
case 'T_BITWISE_AND':
if ($defaultStart === null) {
$passByReference = true;
}
break;
case 'T_VARIABLE':
$currVar = $i;
break;
case 'T_ELLIPSIS':
$variableLength = true;
break;
case 'T_ARRAY_HINT': // Pre-PHPCS 3.3.0.
case 'T_CALLABLE':
if ($typeHintToken === false) {
$typeHintToken = $i;
}
$typeHint .= $tokens[$i]['content'];
break;
case 'T_SELF':
case 'T_PARENT':
case 'T_STATIC':
// Self and parent are valid, static invalid, but was probably intended as type hint.
if (isset($defaultStart) === false) {
if ($typeHintToken === false) {
$typeHintToken = $i;
}
$typeHint .= $tokens[$i]['content'];
}
break;
case 'T_STRING':
// This is a string, so it may be a type hint, but it could
// also be a constant used as a default value.
$prevComma = false;
for ($t = $i; $t >= $opener; $t--) {
if ($tokens[$t]['code'] === \T_COMMA) {
$prevComma = $t;
break;
}
}
if ($prevComma !== false) {
$nextEquals = false;
for ($t = $prevComma; $t < $i; $t++) {
if ($tokens[$t]['code'] === \T_EQUAL) {
$nextEquals = $t;
break;
}
}
if ($nextEquals !== false) {
break;
}
}
if ($defaultStart === null) {
if ($typeHintToken === false) {
$typeHintToken = $i;
}
$typeHint .= $tokens[$i]['content'];
}
break;
case 'T_NS_SEPARATOR':
// Part of a type hint or default value.
if ($defaultStart === null) {
if ($typeHintToken === false) {
$typeHintToken = $i;
}
$typeHint .= $tokens[$i]['content'];
}
break;
case 'T_NULLABLE':
case 'T_INLINE_THEN': // Pre-PHPCS 2.8.0.
if ($defaultStart === null) {
$nullableType = true;
$typeHint .= $tokens[$i]['content'];
}
break;
case 'T_CLOSE_PARENTHESIS':
case 'T_COMMA':
// If it's null, then there must be no parameters for this
// method.
if ($currVar === null) {
break;
}
$vars[$paramCount] = array();
$vars[$paramCount]['token'] = $currVar;
$vars[$paramCount]['name'] = $tokens[$currVar]['content'];
$vars[$paramCount]['content'] = trim($phpcsFile->getTokensAsString($paramStart, ($i - $paramStart)));
if ($defaultStart !== null) {
$vars[$paramCount]['default'] = trim(
$phpcsFile->getTokensAsString(
$defaultStart,
($i - $defaultStart)
)
);
}
$vars[$paramCount]['pass_by_reference'] = $passByReference;
$vars[$paramCount]['variable_length'] = $variableLength;
$vars[$paramCount]['type_hint'] = $typeHint;
$vars[$paramCount]['type_hint_token'] = $typeHintToken;
$vars[$paramCount]['nullable_type'] = $nullableType;
// Reset the vars, as we are about to process the next parameter.
$defaultStart = null;
$paramStart = ($i + 1);
$passByReference = false;
$variableLength = false;
$typeHint = '';
$typeHintToken = false;
$nullableType = false;
$paramCount++;
break;
case 'T_EQUAL':
$defaultStart = ($i + 1);
break;
}//end switch
}//end for
return $vars;
}
}