Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move is_use_of_global_constant() utility method to dedicated ConstantsHelper #2248

Merged
merged 3 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions WordPress/Helpers/ConstantsHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php
/**
* WordPress Coding Standard.
*
* @package WPCS\WordPressCodingStandards
* @link https://github.com/WordPress/WordPress-Coding-Standards
* @license https://opensource.org/licenses/MIT MIT
*/

namespace WordPressCS\WordPress\Helpers;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Tokens\Collections;
use PHPCSUtils\Utils\Scopes;
use WordPressCS\WordPress\Helpers\ContextHelper;

/**
* Helper utilities for checking the context in which a token is used.
*
* ---------------------------------------------------------------------------------------------
* This class is only intended for internal use by WordPressCS and is not part of the public API.
* This also means that it has no promise of backward compatibility. Use at your own risk.
* ---------------------------------------------------------------------------------------------
*
* {@internal The functionality in this class will likely be replaced at some point in
* the future by functions from PHPCSUtils.}
*
* @package WPCS\WordPressCodingStandards
* @since 3.0.0 The method in this class was previously contained in the
* `WordPressCS\WordPress\Sniff` class and has been moved here.
*/
final class ConstantsHelper {

/**
* Determine whether an arbitrary T_STRING token is the use of a global constant.
*
* @since 1.0.0
* @since 3.0.0 - Moved from the Sniff class to this class.
* - The method was changed to be `static`.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the function call token.
*
* @return bool
*/
public static function is_use_of_global_constant( File $phpcsFile, $stackPtr ) {
$tokens = $phpcsFile->getTokens();

// Check for the existence of the token.
if ( ! isset( $tokens[ $stackPtr ] ) ) {
return false;
}

// Is this one of the tokens this function handles ?
if ( \T_STRING !== $tokens[ $stackPtr ]['code'] ) {
return false;
}

$next = $phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );
if ( false !== $next
&& ( \T_OPEN_PARENTHESIS === $tokens[ $next ]['code']
|| \T_DOUBLE_COLON === $tokens[ $next ]['code'] )
) {
// Function call or declaration.
return false;
}

// Array of tokens which if found preceding the $stackPtr indicate that a T_STRING is not a global constant.
$tokens_to_ignore = array(
\T_NAMESPACE => true,
\T_USE => true,
\T_EXTENDS => true,
\T_IMPLEMENTS => true,
\T_NEW => true,
\T_FUNCTION => true,
\T_INSTANCEOF => true,
\T_INSTEADOF => true,
\T_GOTO => true,
\T_AS => true,
);
$tokens_to_ignore += Tokens::$ooScopeTokens;
$tokens_to_ignore += Collections::objectOperators();
$tokens_to_ignore += Tokens::$scopeModifiers;

$prev = $phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );
if ( isset( $tokens_to_ignore[ $tokens[ $prev ]['code'] ] ) ) {
// Not the use of a constant.
return false;
}

if ( ContextHelper::is_token_namespaced( $phpcsFile, $stackPtr ) === true ) {
// Namespaced constant of the same name.
return false;
}

if ( \T_CONST === $tokens[ $prev ]['code']
&& Scopes::isOOConstant( $phpcsFile, $prev )
) {
// Class constant declaration of the same name.
return false;
}

/*
* Deal with a number of variations of use statements.
*/
for ( $i = $stackPtr; $i > 0; $i-- ) {
if ( $tokens[ $i ]['line'] !== $tokens[ $stackPtr ]['line'] ) {
break;
}
}

$firstOnLine = $phpcsFile->findNext( Tokens::$emptyTokens, ( $i + 1 ), null, true );
if ( false !== $firstOnLine && \T_USE === $tokens[ $firstOnLine ]['code'] ) {
$nextOnLine = $phpcsFile->findNext( Tokens::$emptyTokens, ( $firstOnLine + 1 ), null, true );
if ( false !== $nextOnLine ) {
if ( \T_STRING === $tokens[ $nextOnLine ]['code']
&& 'const' === $tokens[ $nextOnLine ]['content']
) {
$hasNsSep = $phpcsFile->findNext( \T_NS_SEPARATOR, ( $nextOnLine + 1 ), $stackPtr );
if ( false !== $hasNsSep ) {
// Namespaced const (group) use statement.
return false;
}
} else {
// Not a const use statement.
return false;
}
}
}

return true;
}
}
104 changes: 0 additions & 104 deletions WordPress/Sniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Utils\PassedParameters;
use PHPCSUtils\Utils\Scopes;
use PHPCSUtils\Utils\TextStrings;
use WordPressCS\WordPress\Helpers\ContextHelper;
use WordPressCS\WordPress\Helpers\VariableHelper;
Expand Down Expand Up @@ -820,107 +819,4 @@ protected function is_validated( $stackPtr, $array_keys = array(), $in_condition

return false;
}

/**
* Determine whether an arbitrary T_STRING token is the use of a global constant.
*
* @since 1.0.0
*
* @param int $stackPtr The position of the function call token.
*
* @return bool
*/
public function is_use_of_global_constant( $stackPtr ) {
// Check for the existence of the token.
if ( ! isset( $this->tokens[ $stackPtr ] ) ) {
return false;
}

// Is this one of the tokens this function handles ?
if ( \T_STRING !== $this->tokens[ $stackPtr ]['code'] ) {
return false;
}

$next = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );
if ( false !== $next
&& ( \T_OPEN_PARENTHESIS === $this->tokens[ $next ]['code']
|| \T_DOUBLE_COLON === $this->tokens[ $next ]['code'] )
) {
// Function call or declaration.
return false;
}

// Array of tokens which if found preceding the $stackPtr indicate that a T_STRING is not a global constant.
$tokens_to_ignore = array(
'T_NAMESPACE' => true,
'T_USE' => true,
'T_CLASS' => true,
'T_TRAIT' => true,
'T_INTERFACE' => true,
'T_EXTENDS' => true,
'T_IMPLEMENTS' => true,
'T_NEW' => true,
'T_FUNCTION' => true,
'T_DOUBLE_COLON' => true,
'T_OBJECT_OPERATOR' => true,
'T_INSTANCEOF' => true,
'T_INSTEADOF' => true,
'T_GOTO' => true,
'T_AS' => true,
'T_PUBLIC' => true,
'T_PROTECTED' => true,
'T_PRIVATE' => true,
);

$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );
if ( false !== $prev
&& isset( $tokens_to_ignore[ $this->tokens[ $prev ]['type'] ] )
) {
// Not the use of a constant.
return false;
}

if ( ContextHelper::is_token_namespaced( $this->phpcsFile, $stackPtr ) === true ) {
// Namespaced constant of the same name.
return false;
}

if ( false !== $prev
&& \T_CONST === $this->tokens[ $prev ]['code']
&& Scopes::isOOConstant( $this->phpcsFile, $prev )
) {
// Class constant declaration of the same name.
return false;
}

/*
* Deal with a number of variations of use statements.
*/
for ( $i = $stackPtr; $i > 0; $i-- ) {
if ( $this->tokens[ $i ]['line'] !== $this->tokens[ $stackPtr ]['line'] ) {
break;
}
}

$firstOnLine = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $i + 1 ), null, true );
if ( false !== $firstOnLine && \T_USE === $this->tokens[ $firstOnLine ]['code'] ) {
$nextOnLine = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $firstOnLine + 1 ), null, true );
if ( false !== $nextOnLine ) {
if ( \T_STRING === $this->tokens[ $nextOnLine ]['code']
&& 'const' === $this->tokens[ $nextOnLine ]['content']
) {
$hasNsSep = $this->phpcsFile->findNext( \T_NS_SEPARATOR, ( $nextOnLine + 1 ), $stackPtr );
if ( false !== $hasNsSep ) {
// Namespaced const (group) use statement.
return false;
}
} else {
// Not a const use statement.
return false;
}
}
}

return true;
}
}
3 changes: 2 additions & 1 deletion WordPress/Sniffs/Security/EscapeOutputSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPCSUtils\Utils\TextStrings;
use WordPressCS\WordPress\Helpers\ContextHelper;
use WordPressCS\WordPress\Helpers\RulesetPropertyHelper;
use WordPressCS\WordPress\Helpers\ConstantsHelper;
use WordPressCS\WordPress\Helpers\VariableHelper;
use WordPressCS\WordPress\Sniff;

Expand Down Expand Up @@ -339,7 +340,7 @@ public function process_token( $stackPtr ) {
// Handle safe PHP native constants.
if ( \T_STRING === $this->tokens[ $i ]['code']
&& isset( $this->safe_php_constants[ $this->tokens[ $i ]['content'] ] )
&& $this->is_use_of_global_constant( $i )
&& ConstantsHelper::is_use_of_global_constant( $this->phpcsFile, $i )
) {
continue;
}
Expand Down
1 change: 1 addition & 0 deletions WordPress/Tests/Security/EscapeOutputUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @since 0.13.0 Class name changed: this class is now namespaced.
* @since 1.0.0 This sniff has been moved from the `XSS` category to the `Security` category.
*
* @covers \WordPressCS\WordPress\Helpers\ConstantsHelper::is_use_of_global_constant
* @covers \WordPressCS\WordPress\Sniffs\Security\EscapeOutputSniff
*/
final class EscapeOutputUnitTest extends AbstractSniffUnitTest {
Expand Down