Skip to content

Commit

Permalink
Merge pull request #2226 from WordPress/feature/move-is-class-object-…
Browse files Browse the repository at this point in the history
…call-to-helper-class

Move is_class_object_call() utility method to dedicated `ContextHelper` + support nullsafe object operator
  • Loading branch information
dingo-d committed Apr 19, 2023
2 parents de872bb + 40d5ac9 commit 942bb72
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 36 deletions.
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,
);
}

}

0 comments on commit 942bb72

Please sign in to comment.