Skip to content

Commit

Permalink
Merge pull request #1570 from PHPCompatibility/feature/move-is-variab…
Browse files Browse the repository at this point in the history
…le-to-tokengroup

Sniff: move isVariable() method to TokenGroup
  • Loading branch information
wimg committed May 21, 2023
2 parents de59c49 + 6db3898 commit 3716094
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 95 deletions.
92 changes: 92 additions & 0 deletions PHPCompatibility/Helpers/TokenGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,96 @@ public static function isNumericCalculation(File $phpcsFile, $start, $end)

return false;
}

/**
* Determine whether the tokens between $start and $end could together represent a variable.
*
* @since 9.0.0
* @since 10.0.0 This method is now static.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $start Starting point stack pointer. Inclusive.
* I.e. this token should be taken into
* account.
* @param int $end End point stack pointer. Exclusive.
* I.e. this token should not be taken
* into account.
* @param int $targetNestingLevel The nesting level the variable should be at.
*
* @return bool
*/
public static function isVariable(File $phpcsFile, $start, $end, $targetNestingLevel)
{
static $disallowedTokens, $bracketTokens;

// Create the token arrays only once.
if (isset($disallowedTokens, $bracketTokens) === false) {
$disallowedTokens = [
\T_OPEN_PARENTHESIS => \T_OPEN_PARENTHESIS,
\T_STRING_CONCAT => \T_STRING_CONCAT,
];
$disallowedTokens += Tokens::$assignmentTokens;
$disallowedTokens += Tokens::$equalityTokens;
$disallowedTokens += Tokens::$comparisonTokens;
$disallowedTokens += Tokens::$operators;
$disallowedTokens += Tokens::$booleanOperators;
$disallowedTokens += Tokens::$castTokens;

/*
* List of brackets which can be part of a variable variable.
*
* Key is the open bracket token, value the close bracket token.
*/
$bracketTokens = [
\T_OPEN_CURLY_BRACKET => \T_CLOSE_CURLY_BRACKET,
\T_OPEN_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET,
];
}

$tokens = $phpcsFile->getTokens();

// If no variable at all was found, then it's definitely a no-no.
$hasVariable = $phpcsFile->findNext(\T_VARIABLE, $start, $end);
if ($hasVariable === false) {
return false;
}

// Check if the variable found is at the right level. Deeper levels are always an error.
if (isset($tokens[$hasVariable]['nested_parenthesis'])
&& \count($tokens[$hasVariable]['nested_parenthesis']) !== $targetNestingLevel
) {
return false;
}

// Ok, so the first variable is at the right level, now are there any
// disallowed tokens within the empty() ?
$hasBadToken = $phpcsFile->findNext($disallowedTokens, $start, $end);
if ($hasBadToken === false) {
return true;
}

// If there are also bracket tokens, the disallowed token might be part of a variable
// variable, but if there are no bracket tokens, we know we have an error.
$hasBrackets = $phpcsFile->findNext($bracketTokens, $start, $end);
if ($hasBrackets === false) {
return false;
}

// Ok, we have both a disallowed token as well as brackets, so we need to walk
// the tokens of the variable variable.
for ($i = $start; $i < $end; $i++) {
// If this is a bracket token, skip to the end of the bracketed expression.
if (isset($bracketTokens[$tokens[$i]['code']], $tokens[$i]['bracket_closer'])) {
$i = $tokens[$i]['bracket_closer'];
continue;
}

// If it's a disallowed token, not within brackets, we have an error.
if (isset($disallowedTokens[$tokens[$i]['code']])) {
return false;
}
}

return true;
}
}
91 changes: 0 additions & 91 deletions PHPCompatibility/Sniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -321,95 +321,4 @@ public function isUseOfGlobalConstant(File $phpcsFile, $stackPtr)

return true;
}

/**
* Determine whether the tokens between $start and $end could together represent a variable.
*
* @since 9.0.0
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $start Starting point stack pointer. Inclusive.
* I.e. this token should be taken into
* account.
* @param int $end End point stack pointer. Exclusive.
* I.e. this token should not be taken
* into account.
* @param int $targetNestingLevel The nesting level the variable should be at.
*
* @return bool
*/
public function isVariable(File $phpcsFile, $start, $end, $targetNestingLevel)
{
static $tokenBlackList, $bracketTokens;

// Create the token arrays only once.
if (isset($tokenBlackList, $bracketTokens) === false) {
$tokenBlackList = [
\T_OPEN_PARENTHESIS => \T_OPEN_PARENTHESIS,
\T_STRING_CONCAT => \T_STRING_CONCAT,
];
$tokenBlackList += Tokens::$assignmentTokens;
$tokenBlackList += Tokens::$equalityTokens;
$tokenBlackList += Tokens::$comparisonTokens;
$tokenBlackList += Tokens::$operators;
$tokenBlackList += Tokens::$booleanOperators;
$tokenBlackList += Tokens::$castTokens;

/*
* List of brackets which can be part of a variable variable.
*
* Key is the open bracket token, value the close bracket token.
*/
$bracketTokens = [
\T_OPEN_CURLY_BRACKET => \T_CLOSE_CURLY_BRACKET,
\T_OPEN_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET,
];
}

$tokens = $phpcsFile->getTokens();

// If no variable at all was found, then it's definitely a no-no.
$hasVariable = $phpcsFile->findNext(\T_VARIABLE, $start, $end);
if ($hasVariable === false) {
return false;
}

// Check if the variable found is at the right level. Deeper levels are always an error.
if (isset($tokens[$hasVariable]['nested_parenthesis'])
&& \count($tokens[$hasVariable]['nested_parenthesis']) !== $targetNestingLevel
) {
return false;
}

// Ok, so the first variable is at the right level, now are there any
// blacklisted tokens within the empty() ?
$hasBadToken = $phpcsFile->findNext($tokenBlackList, $start, $end);
if ($hasBadToken === false) {
return true;
}

// If there are also bracket tokens, the blacklisted token might be part of a variable
// variable, but if there are no bracket tokens, we know we have an error.
$hasBrackets = $phpcsFile->findNext($bracketTokens, $start, $end);
if ($hasBrackets === false) {
return false;
}

// Ok, we have both a blacklisted token as well as brackets, so we need to walk
// the tokens of the variable variable.
for ($i = $start; $i < $end; $i++) {
// If this is a bracket token, skip to the end of the bracketed expression.
if (isset($bracketTokens[$tokens[$i]['code']], $tokens[$i]['bracket_closer'])) {
$i = $tokens[$i]['bracket_closer'];
continue;
}

// If it's a blacklisted token, not within brackets, we have an error.
if (isset($tokenBlackList[$tokens[$i]['code']])) {
return false;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use PHPCompatibility\Helpers\ScannedCode;
use PHPCompatibility\Sniff;
use PHPCompatibility\Helpers\TokenGroup;
use PHP_CodeSniffer\Files\File;

/**
Expand Down Expand Up @@ -86,7 +87,7 @@ public function process(File $phpcsFile, $stackPtr)
$nestingLevel = \count($tokens[$opener + 1]['nested_parenthesis']);
}

if ($this->isVariable($phpcsFile, ($opener + 1), $asToken, $nestingLevel) === true) {
if (TokenGroup::isVariable($phpcsFile, ($opener + 1), $asToken, $nestingLevel) === true) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use PHPCompatibility\Helpers\ScannedCode;
use PHPCompatibility\Sniff;
use PHPCompatibility\Helpers\TokenGroup;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;

Expand Down Expand Up @@ -79,7 +80,7 @@ public function process(File $phpcsFile, $stackPtr)
$nestingLevel = \count($tokens[$open + 1]['nested_parenthesis']);
}

if ($this->isVariable($phpcsFile, ($open + 1), $close, $nestingLevel) === true) {
if (TokenGroup::isVariable($phpcsFile, ($open + 1), $close, $nestingLevel) === true) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* @group controlStructures
*
* @covers \PHPCompatibility\Sniffs\ControlStructures\NewForeachExpressionReferencingSniff
* @covers \PHPCompatibility\Sniff::isVariable
* @covers \PHPCompatibility\Helpers\TokenGroup::isVariable
*
* @since 9.0.0
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* @group languageConstructs
*
* @covers \PHPCompatibility\Sniffs\LanguageConstructs\NewEmptyNonVariableSniff
* @covers \PHPCompatibility\Sniff::isVariable
* @covers \PHPCompatibility\Helpers\TokenGroup::isVariable
*
* @since 7.0.4
*/
Expand Down

0 comments on commit 3716094

Please sign in to comment.