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_class_object_call() utility method to dedicated ContextHelper + support nullsafe object operator #2226

Merged
merged 2 commits into from
Apr 19, 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
3 changes: 2 additions & 1 deletion WordPress/AbstractFunctionRestrictionsSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Utils\MessageHelper;
use WordPressCS\WordPress\Helpers\ContextHelper;
use WordPressCS\WordPress\Helpers\RulesetPropertyHelper;
use WordPressCS\WordPress\Sniff;

Expand Down Expand Up @@ -219,7 +220,7 @@ public function is_targetted_token( $stackPtr ) {
}

// Exclude function definitions, class methods, and namespaced calls.
if ( $this->is_class_object_call( $stackPtr ) === true ) {
if ( ContextHelper::has_object_operator_before( $this->phpcsFile, $stackPtr ) === true ) {
return false;
}

Expand Down
51 changes: 51 additions & 0 deletions WordPress/Helpers/ContextHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?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;

/**
* 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.
* ---------------------------------------------------------------------------------------------
*
* @package WPCS\WordPressCodingStandards
* @since 3.0.0 The methods in this class were previously contained in the
* `WordPressCS\WordPress\Sniff` class and have been moved here.
*/
final class ContextHelper {

/**
* Check if a particular token acts - statically or non-statically - on an object.
*
* @internal Note: this may still mistake a namespaced function imported via a `use` statement for
* a global function!
*
* @since 2.1.0
* @since 3.0.0 - Moved from the Sniff class to this class.
* - The method visibility was changed from `protected` to `public static`.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The index of the token in the stack.
*
* @return bool
*/
public static function has_object_operator_before( File $phpcsFile, $stackPtr ) {
$tokens = $phpcsFile->getTokens();
$before = $phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );

return isset( Collections::objectOperators()[ $tokens[ $before ]['code'] ] );
}
}
33 changes: 3 additions & 30 deletions WordPress/Sniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
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 @@ -507,34 +508,6 @@ protected function is_in_isset_or_empty( $stackPtr ) {
return false;
}

/**
* Check if a particular token is a (static or non-static) call to a class method or property.
*
* @internal Note: this may still mistake a namespaced function imported via a `use` statement for
* a global function!
*
* @since 2.1.0
*
* @param int $stackPtr The index of the token in the stack.
*
* @return bool
*/
protected function is_class_object_call( $stackPtr ) {
$before = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true, null, true );

if ( false === $before ) {
return false;
}

if ( \T_OBJECT_OPERATOR !== $this->tokens[ $before ]['code']
&& \T_DOUBLE_COLON !== $this->tokens[ $before ]['code']
) {
return false;
}

return true;
}

/**
* Check if a particular token is prefixed with a namespace.
*
Expand Down Expand Up @@ -637,7 +610,7 @@ protected function is_in_function_call( $stackPtr, $valid_functions, $global_fun
/*
* Now, make sure it is a global function.
*/
if ( $this->is_class_object_call( $prev_non_empty ) === true ) {
if ( ContextHelper::has_object_operator_before( $this->phpcsFile, $prev_non_empty ) === true ) {
continue;
}

Expand Down Expand Up @@ -1026,7 +999,7 @@ protected function is_validated( $stackPtr, $array_keys = array(), $in_condition
continue 2;
}

if ( $this->is_class_object_call( $i ) === true ) {
if ( ContextHelper::has_object_operator_before( $this->phpcsFile, $i ) === true ) {
// Method call.
continue 2;
}
Expand Down
3 changes: 2 additions & 1 deletion WordPress/Sniffs/Security/NonceVerificationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Utils\MessageHelper;
use WordPressCS\WordPress\Helpers\ContextHelper;
use WordPressCS\WordPress\Helpers\RulesetPropertyHelper;
use WordPressCS\WordPress\Helpers\VariableHelper;
use WordPressCS\WordPress\Sniff;
Expand Down Expand Up @@ -269,7 +270,7 @@ private function has_nonce_check( $stackPtr ) {
/*
* Now, make sure it is a call to a global function.
*/
if ( $this->is_class_object_call( $i ) === true ) {
if ( ContextHelper::has_object_operator_before( $this->phpcsFile, $i ) === true ) {
continue;
}

Expand Down
3 changes: 2 additions & 1 deletion WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use PHPCSUtils\Utils\Parentheses;
use PHPCSUtils\Utils\Scopes;
use PHPCSUtils\Utils\TextStrings;
use WordPressCS\WordPress\Helpers\ContextHelper;
use WordPressCS\WordPress\Helpers\IsUnitTestTrait;
use WordPressCS\WordPress\Helpers\VariableHelper;
use WordPressCS\WordPress\Helpers\WPGlobalVariablesHelper;
Expand Down Expand Up @@ -393,7 +394,7 @@ protected function process_global_statement( $stackPtr, $in_function_scope ) {
}

// Don't throw false positives for static class properties.
if ( $this->is_class_object_call( $ptr ) === true ) {
if ( ContextHelper::has_object_operator_before( $this->phpcsFile, $ptr ) === true ) {
continue;
}

Expand Down
10 changes: 9 additions & 1 deletion WordPress/Tests/WP/DiscouragedFunctionsUnitTest.inc
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<?php

query_posts(); // Warning, use WP_Query instead.

wp_reset_query(); // Warning, use wp_reset_postdata instead.

/*
* Tests which are more specifically for the AbstractFunctionRestrictionsSniff class and Helper methods.
*/

// Ensure the sniff doesn't act on methods calls.
$obj->query_posts(); // OK, not the global function.
MyClass::wp_reset_query(); // OK, not the global function.
$obj?->query_posts(); // OK, not the global function.
4 changes: 2 additions & 2 deletions WordPress/Tests/WP/DiscouragedFunctionsUnitTest.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.
*
* @covers \WordPressCS\WordPress\AbstractFunctionRestrictionsSniff
* @covers \WordPressCS\WordPress\Helpers\ContextHelper::has_object_operator_before
* @covers \WordPressCS\WordPress\Sniffs\WP\DiscouragedFunctionsSniff
*/
final class DiscouragedFunctionsUnitTest extends AbstractSniffUnitTest {
Expand All @@ -41,8 +42,7 @@ public function getErrorList() {
public function getWarningList() {
return array(
3 => 1,
5 => 1,
4 => 1,
);
}

}