123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- <?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;
- }
- }
|