From 3483648f3d4d483073260515685ca649b4095010 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Thu, 9 Jul 2020 20:15:53 +0100 Subject: [PATCH 01/35] chore: Add `.gitattributes` file Exclude files from release archives. This will also make them unavailable when using Composer with `--prefer-dist`. If you develop for VIPCS using Composer, use `--prefer-source`. See https://blog.madewithlove.be/post/gitattributes/ --- .gitattributes | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..5727a3b9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,29 @@ +# +# Exclude files from release archives. +# This will also make them unavailable when using Composer with `--prefer-dist`. +# If you develop for VIPCS using Composer, use `--prefer-source`. +# https://blog.madewithlove.be/post/gitattributes/ +# +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.phpcs.xml.dist export-ignore +/.travis.yml export-ignore +/phpunit.xml.dist export-ignore +/.github export-ignore +/bin export-ignore +/tests export-ignore +/WordPressVIPMinimum/Tests export-ignore + +# +# Auto detect text files and perform LF normalization +# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ +# +* text=auto + +# +# The above will handle all files NOT found below +# +*.md text +*.php text +*.inc text \ No newline at end of file From 6d08d8646417ddd75f4eafafcb32cff4278bedf2 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Thu, 9 Jul 2020 20:35:47 +0100 Subject: [PATCH 02/35] chore: Add CODEOWNERS file Helps to auto-tag the repo maintainers for reviews when PRs are created. --- .github/CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..496c8d94 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# The following teams will get auto-tagged for a review. +# See https://docs.github.com/en/enterprise/2.15/user/articles/about-code-owners + +* @Automattic/vipcs From a8967290c2049d17abc7bf1dfba15cd19fcf7178 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Thu, 31 Oct 2019 23:30:59 +0000 Subject: [PATCH 03/35] Switch to sirbrillig/phpcs-variable-analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a new dependency of `sirbrillig/phpcs-variable-analysis` which is a more maintained version of the existing `VariableAnalysis` sniff in VIPCS. Requires ^2.8.3, since 2.6.3 – 2.8.2 had PHP 5.6 as the minimum version, but 2.8.3 changes it down to PHP 5.4 as the minimum. The new sniff is added to the `WordPressVIPMinimum` ruleset. `WordPress-VIP-Go` ruleset inherits this, and maintains its dropping of the severity for `UnusedVariable` and `UndefinedVariable` violations. The ruleset tests have set the previously undefined variables (or changed some variable names), so that violations on each line are still specific to the thing being tested, and doesn't include extra violations due to the use of throwaway variables. One of the reasons for changing was the previously false positive with respect to the use of `$this` inside closures inside class methods. A ruleset test has been added to cover this, and it correctly does not get flagged in the ruleset test. The old `VariableAnalysis` has been marked as deprecated, until it can be removed in the next major release of VIPCS. This will stop any breakage of setups which reference `WordPressVIPMinimum.Variables.VariableAnalysis` in a custom ruleset. If called, it throws a warning, and then passes control to the new VariableAnalysis sniff. The deprecation notice is excluded if the sniff is not explicitly included, and the duplicate violation messages are also silenced. The previously used `VariableAnalaysisHelper.php` has been removed completely, as no-one should have been referencing that directly. Fixes #449. --- WordPress-VIP-Go/ruleset-test.inc | 20 +- WordPress-VIP-Go/ruleset-test.php | 1 + WordPress-VIP-Go/ruleset.xml | 4 +- .../Variables/VariableAnalysisHelper.php | 73 - .../Variables/VariableAnalysisSniff.php | 1260 +---------------- .../Variables/VariableAnalysisUnitTest.inc | 12 +- .../Variables/VariableAnalysisUnitTest.php | 4 +- WordPressVIPMinimum/ruleset-test.inc | 25 +- WordPressVIPMinimum/ruleset-test.php | 7 +- WordPressVIPMinimum/ruleset.xml | 33 +- composer.json | 1 + 11 files changed, 111 insertions(+), 1329 deletions(-) delete mode 100644 WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisHelper.php diff --git a/WordPress-VIP-Go/ruleset-test.inc b/WordPress-VIP-Go/ruleset-test.inc index 8e3be3f1..af1e610c 100644 --- a/WordPress-VIP-Go/ruleset-test.inc +++ b/WordPress-VIP-Go/ruleset-test.inc @@ -1,5 +1,5 @@ 1 ) ); // Error. -$this->extract(); // Ok. +$obj->extract(); // Ok. // WordPress.PHP.StrictComparisons.LooseComparison true == $true; // Warning. @@ -188,7 +188,7 @@ $wpdb = 'test'; // Error. $GLOBALS['domain']['subkey'] = 'something else'; // Error. // WordPress.WP.EnqueuedResources.NonEnqueuedScript -echo wp_kses( ' @@ -207,12 +207,12 @@ require_once "my_file.php"; // Warning. require '../../my_file.php'; // Warning. include("http://www.google.com/bad_file.php"); // Warning. -// WordPressVIPMinimum.Variables.VariableAnalysis.UndefinedVariable +// VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable function foo_bar_bar() { $b . 'test'; // Warning. } -// WordPressVIPMinimum.Variables.VariableAnalysis.UnusedVariable +// VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable function foo_bar_foo() { $a = 'Hello'; // Warning } @@ -339,7 +339,7 @@ require_once __DIR__ . "/my_file.svg"; // Error. // WordPressVIPMinimum.Functions.CheckReturnValue $my_theme_options = get_option( 'my_theme', false ); if ( array_key_exists( 'key', $my_theme_options ) ) { } // Error. -echo 'My term link'; // Error. +echo 'My term link'; // Error. // WordPressVIPMinimum.Functions.DynamicCalls $my_notokay_func = 'extract'; @@ -349,7 +349,7 @@ $my_notokay_func(); // Error. wp_cache_get_multi(); // Error. opcache_reset(); // Error. opcache_invalidate( 'test_script.php' ); // Error. -opcache_compile_file( $test_script ); // Error. +opcache_compile_file( $var ); // Error. opcache_​is_​script_​cached( 'test_script.php' ); // Error. opcache_​get_​status(); // Error. opcache_​get_​configuration(); // Error. @@ -425,7 +425,7 @@ wpcom_vip_get_term_by(); // Warning. wpcom_vip_get_category_by_slug(); // Warning. // WordPressVIPMinimum.Functions.StripTagsSniff -strip_tags( 'Test', $html ); // Warning. +strip_tags( 'Test', $text ); // Warning. // WordPressVIPMinimum.Hooks.AlwaysReturnInFilter function bad_example_function_thing() { // Error. @@ -489,12 +489,12 @@ $query_args = [ ]; // WordPressVIPMinimum.Performance.RemoteRequestTimeout -wp_remote_post( $this->endpoint, array( +wp_remote_post( $obj->endpoint, array( 'method' => 'POST', 'timeout' => 45, // Error. 'httpversion' => '1.1', 'blocking' => false, - 'body' => wp_json_encode( $this->logs, JSON_UNESCAPED_SLASHES ), + 'body' => wp_json_encode( $obj->logs, JSON_UNESCAPED_SLASHES ), ) ); diff --git a/WordPress-VIP-Go/ruleset-test.php b/WordPress-VIP-Go/ruleset-test.php index b653b83d..1bf4ec7c 100644 --- a/WordPress-VIP-Go/ruleset-test.php +++ b/WordPress-VIP-Go/ruleset-test.php @@ -222,6 +222,7 @@ 417 => 1, 418 => 1, 419 => 1, + 420 => 2, 421 => 1, 423 => 1, 424 => 1, diff --git a/WordPress-VIP-Go/ruleset.xml b/WordPress-VIP-Go/ruleset.xml index 57c751a8..240994bf 100644 --- a/WordPress-VIP-Go/ruleset.xml +++ b/WordPress-VIP-Go/ruleset.xml @@ -244,10 +244,10 @@ warning 3 - + 3 - + 1 diff --git a/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisHelper.php b/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisHelper.php deleted file mode 100644 index f9d9f003..00000000 --- a/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisHelper.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @copyright 2011-2012 Sam Graham - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @link http://pear.php.net/package/PHP_CodeSniffer - */ - -namespace WordPressVIPMinimum\Sniffs\Variables; - -/** - * Holds details of a scope. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Sam Graham - * @copyright 2011-2012 Sam Graham - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class ScopeInfo { - public $owner; - public $opener; - public $closer; - public $variables = array(); - - public function __construct( $currScope ) { - $this->owner = $currScope; - // TODO: extract opener/closer - } -} - -/** - * Holds details of a variable within a scope. - * - * @category PHP - * @package PHP_CodeSniffer - * @author Sam Graham - * @copyright 2011 Sam Graham - * @link http://pear.php.net/package/PHP_CodeSniffer - */ -class VariableInfo { - public $name; - /** - * What scope the variable has: local, param, static, global, bound - */ - public $scopeType; - public $typeHint; - public $passByReference = false; - public $firstDeclared; - public $firstInitialized; - public $firstRead; - public $ignoreUnused = false; - - public static $scopeTypeDescriptions = array( - 'local' => 'variable', - 'param' => 'function parameter', - 'static' => 'static variable', - 'global' => 'global variable', - 'bound' => 'bound variable', - ); - - public function __construct( $varName ) { - $this->name = $varName; - } -} -// @codingStandardsIgnoreEnd diff --git a/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php b/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php index 209ea985..2627fb59 100644 --- a/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php +++ b/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php @@ -1,5 +1,4 @@ * @copyright 2011 Sam Graham * @link http://pear.php.net/package/PHP_CodeSniffer + * + * @deprecated 2.2.0 Use the `VariableAnalysis.CodeAnalysis.VariableAnalysis` sniff instead. + * This `WordPressVIPMinimum.Variables.VariableAnalysis sniff will be removed in VIPCS 3.0.0. */ -class VariableAnalysisSniff extends Sniff { +class VariableAnalysisSniff extends \VariableAnalysis\Sniffs\CodeAnalysis\VariableAnalysisSniff { /** - * The PHP_CodeSniffer file where the token was found. + * Keep track of whether the warnings have been thrown to prevent + * the messages being thrown for every token triggering the sniff. * - * Needs consolidating with the previous property. + * @since 2.2.0 * - * @var File - */ - protected $currentFile; - - /** - * A list of scopes encountered so far and the variables within them. - */ - private $_scopes = array(); - - /** - * A regexp for matching variable names in double-quoted strings. - */ - private $_double_quoted_variable_regexp = '|(? array(5), - 'addFunction' => array(3), - 'addTask' => array(3), - 'addTaskBackground' => array(3), - 'addTaskHigh' => array(3), - 'addTaskHighBackground' => array(3), - 'addTaskLow' => array(3), - 'addTaskLowBackground' => array(3), - 'addTaskStatus' => array(2), - 'apc_dec' => array(3), - 'apc_fetch' => array(2), - 'apc_inc' => array(3), - 'areConfusable' => array(3), - 'array_multisort' => array(1), - 'array_pop' => array(1), - 'array_push' => array(1), - 'array_replace' => array(1), - 'array_replace_recursive' => array(1, 2, 3, '...' ), - 'array_shift' => array(1), - 'array_splice' => array(1), - 'array_unshift' => array(1), - 'array_walk' => array(1), - 'array_walk_recursive' => array(1), - 'arsort' => array(1), - 'asort' => array(1), - 'bindColumn' => array(2), - 'bindParam' => array(2), - 'bind_param' => array(2, 3, '...' ), - 'bind_result' => array(1, 2, '...' ), - 'call_user_method' => array(2), - 'call_user_method_array' => array(2), - 'curl_multi_exec' => array(2), - 'curl_multi_info_read' => array(2), - 'current' => array(1), - 'dbplus_curr' => array(2), - 'dbplus_first' => array(2), - 'dbplus_info' => array(3), - 'dbplus_last' => array(2), - 'dbplus_next' => array(2), - 'dbplus_prev' => array(2), - 'dbplus_tremove' => array(3), - 'dns_get_record' => array(3, 4), - 'domxml_open_file' => array(3), - 'domxml_open_mem' => array(3), - 'each' => array(1), - 'enchant_dict_quick_check' => array(3), - 'end' => array(1), - 'ereg' => array(3), - 'eregi' => array(3), - 'exec' => array(2, 3), - 'exif_thumbnail' => array(1, 2, 3), - 'expect_expectl' => array(3), - 'extract' => array(1), - 'filter' => array(3), - 'flock' => array(2,3), - 'fscanf' => array(2, 3, '...' ), - 'fsockopen' => array(3, 4), - 'ftp_alloc' => array(3), - 'get' => array(2, 3), - 'getByKey' => array(4), - 'getMulti' => array(2), - 'getMultiByKey' => array(3), - 'getimagesize' => array(2), - 'getmxrr' => array(2, 3), - 'gnupg_decryptverify' => array(3), - 'gnupg_verify' => array(4), - 'grapheme_extract' => array(5), - 'headers_sent' => array(1, 2), - 'http_build_url' => array(4), - 'http_get' => array(3), - 'http_head' => array(3), - 'http_negotiate_charset' => array(2), - 'http_negotiate_content_type' => array(2), - 'http_negotiate_language' => array(2), - 'http_post_data' => array(4), - 'http_post_fields' => array(5), - 'http_put_data' => array(4), - 'http_put_file' => array(4), - 'http_put_stream' => array(4), - 'http_request' => array(5), - 'isSuspicious' => array(2), - 'is_callable' => array(3), - 'key' => array(1), - 'krsort' => array(1), - 'ksort' => array(1), - 'ldap_get_option' => array(3), - 'ldap_parse_reference' => array(3), - 'ldap_parse_result' => array(3, 4, 5, 6), - 'localtime' => array(2), - 'm_completeauthorizations' => array(2), - 'maxdb_stmt_bind_param' => array(3, 4, '...' ), - 'maxdb_stmt_bind_result' => array(2, 3, '...' ), - 'mb_convert_variables' => array(3, 4, '...' ), - 'mb_parse_str' => array(2), - 'mqseries_back' => array(2, 3), - 'mqseries_begin' => array(3, 4), - 'mqseries_close' => array(4, 5), - 'mqseries_cmit' => array(2, 3), - 'mqseries_conn' => array(2, 3, 4), - 'mqseries_connx' => array(2, 3, 4, 5), - 'mqseries_disc' => array(2, 3), - 'mqseries_get' => array(3, 4, 5, 6, 7, 8, 9), - 'mqseries_inq' => array(6, 8, 9, 10), - 'mqseries_open' => array(2, 4, 5, 6), - 'mqseries_put' => array(3, 4, 6, 7), - 'mqseries_put1' => array(2, 3, 4, 6, 7), - 'mqseries_set' => array(9, 10), - 'msg_receive' => array(3, 5, 8), - 'msg_send' => array(6), - 'mssql_bind' => array(3), - 'natcasesort' => array(1), - 'natsort' => array(1), - 'ncurses_color_content' => array(2, 3, 4), - 'ncurses_getmaxyx' => array(2, 3), - 'ncurses_getmouse' => array(1), - 'ncurses_getyx' => array(2, 3), - 'ncurses_instr' => array(1), - 'ncurses_mouse_trafo' => array(1, 2), - 'ncurses_mousemask' => array(2), - 'ncurses_pair_content' => array(2, 3), - 'ncurses_wmouse_trafo' => array(2, 3), - 'newt_button_bar' => array(1), - 'newt_form_run' => array(2), - 'newt_get_screen_size' => array(1, 2), - 'newt_grid_get_size' => array(2, 3), - 'newt_reflow_text' => array(5, 6), - 'newt_win_entries' => array(7), - 'newt_win_menu' => array(8), - 'next' => array(1), - 'oci_bind_array_by_name' => array(3), - 'oci_bind_by_name' => array(3), - 'oci_define_by_name' => array(3), - 'oci_fetch_all' => array(2), - 'ocifetchinto' => array(2), - 'odbc_fetch_into' => array(2), - 'openssl_csr_export' => array(2), - 'openssl_csr_new' => array(2), - 'openssl_open' => array(2), - 'openssl_pkcs12_export' => array(2), - 'openssl_pkcs12_read' => array(2), - 'openssl_pkey_export' => array(2), - 'openssl_private_decrypt' => array(2), - 'openssl_private_encrypt' => array(2), - 'openssl_public_decrypt' => array(2), - 'openssl_public_encrypt' => array(2), - 'openssl_random_pseudo_bytes' => array(2), - 'openssl_seal' => array(2, 3), - 'openssl_sign' => array(2), - 'openssl_x509_export' => array(2), - 'ovrimos_fetch_into' => array(2), - 'parse' => array(2,3), - 'parseCurrency' => array(2, 3), - 'parse_str' => array(2), - 'parsekit_compile_file' => array(2), - 'parsekit_compile_string' => array(2), - 'passthru' => array(2), - 'pcntl_sigprocmask' => array(3), - 'pcntl_sigtimedwait' => array(2), - 'pcntl_sigwaitinfo' => array(2), - 'pcntl_wait' => array(1), - 'pcntl_waitpid' => array(2), - 'pfsockopen' => array(3, 4), - 'php_check_syntax' => array(2), - 'poll' => array(1, 2, 3), - 'preg_filter' => array(5), - 'preg_match' => array(3), - 'preg_match_all' => array(3), - 'preg_replace' => array(5), - 'preg_replace_callback' => array(5), - 'prev' => array(1), - 'proc_open' => array(3), - 'query' => array(3), - 'queryExec' => array(2), - 'reset' => array(1), - 'rsort' => array(1), - 'settype' => array(1), - 'shuffle' => array(1), - 'similar_text' => array(3), - 'socket_create_pair' => array(4), - 'socket_getpeername' => array(2, 3), - 'socket_getsockname' => array(2, 3), - 'socket_recv' => array(2), - 'socket_recvfrom' => array(2, 5, 6), - 'socket_select' => array(1, 2, 3), - 'sort' => array(1), - 'sortWithSortKeys' => array(1), - 'sqlite_exec' => array(3), - 'sqlite_factory' => array(3), - 'sqlite_open' => array(3), - 'sqlite_popen' => array(3), - 'sqlite_query' => array(4), - 'sqlite_unbuffered_query' => array(4), - 'sscanf' => array(3, '...' ), - 'str_ireplace' => array(4), - 'str_replace' => array(4), - 'stream_open' => array(4), - 'stream_select' => array(1, 2, 3), - 'stream_socket_accept' => array(3), - 'stream_socket_client' => array(2, 3), - 'stream_socket_recvfrom' => array(4), - 'stream_socket_server' => array(2, 3), - 'system' => array(2), - 'uasort' => array(1), - 'uksort' => array(1), - 'unbufferedQuery' => array(3), - 'usort' => array(1), - 'wincache_ucache_dec' => array(3), - 'wincache_ucache_get' => array(2), - 'wincache_ucache_inc' => array(3), - 'xdiff_string_merge3' => array(4), - 'xdiff_string_patch' => array(4), - 'xml_parse_into_struct' => array(3, 4), - 'xml_set_object' => array(2), - 'xmlrpc_decode_request' => array(2), - 'xmlrpc_set_type' => array(1), - 'xslt_set_object' => array(2), - 'yaml_parse' => array(3), - 'yaml_parse_file' => array(3), - 'yaml_parse_url' => array(3), - 'yaz_ccl_parse' => array(3), - 'yaz_hits' => array(2), - 'yaz_scan_result' => array(2), - 'yaz_wait' => array(1), - ); - - /** - * Allows an install to extend the list of known pass-by-reference functions - * by defining generic.codeanalysis.variableanalysis.sitePassByRefFunctions. - */ - public $sitePassByRefFunctions; - - /** - * Allows exceptions in a catch block to be unused without provoking unused-var warning. - * Set generic.codeanalysis.variableanalysis.allowUnusedCaughtExceptions to a true value. - */ - public $allowUnusedCaughtExceptions = false; - - /** - * Allow function parameters to be unused without provoking unused-var warning. - * Set generic.codeanalysis.variableanalysis.allowUnusedFunctionParameters to a true value. - */ - public $allowUnusedFunctionParameters = true; - - /** - * A list of names of placeholder variables that you want to ignore from - * unused variable warnings, ie things like $junk. - */ - public $validUnusedVariableNames; + private $thrown = [ + 'DeprecatedSniff' => false, + 'FoundPropertyForDeprecatedSniff' => false, + ]; /** * Returns an array of tokens this test wants to listen for. * - * @return array + * @return int[] */ public function register() { - // Magic to modify $_passByRefFunctions with any site-specific settings. - if ( !empty( $this->sitePassByRefFunctions) ) { - foreach (preg_split( '/\s+/', trim( $this->sitePassByRefFunctions) ) as $line ) { - list ( $function, $args) = explode( ':', $line ); - $this->_passByRefFunctions[$function] = explode( ',', $args); - } - } - if ( !empty( $this->validUnusedVariableNames) ) { - $this->validUnusedVariableNames = - preg_split( '/\s+/', trim( $this->validUnusedVariableNames) ); - } - return array( + return [ T_VARIABLE, T_DOUBLE_QUOTED_STRING, T_HEREDOC, T_CLOSE_CURLY_BRACKET, T_STRING, - ); - } - - /** - * Processes this test, when one of its tokens is encountered. - * - * @param int $stackPtr The position of the current token in the stack passed in $tokens. - * - * @return void - */ - public function process_token( $stackPtr ) { - $token = $this->tokens[$stackPtr]; - - //if ( $token['content'] == '$param' ) { - //echo "Found token on line {$token['line']}.\n" . print_r( $token, true ); - //} - - if ( $this->currentFile !== $this->phpcsFile ) { - $this->currentFile = $this->phpcsFile; - } - - if ( $token['code'] === T_VARIABLE ) { - $this->processVariable( $stackPtr ); - return; - } - if ( ( $token['code'] === T_DOUBLE_QUOTED_STRING) || - ( $token['code'] === T_HEREDOC) ) { - $this->processVariableInString( $stackPtr ); - return; - } - if ( ( $token['code'] === T_STRING) && ( $token['content'] === 'compact' ) ) { - $this->processCompact( $stackPtr ); - return; - } - if ( ( $token['code'] === T_CLOSE_CURLY_BRACKET) && - isset( $token['scope_condition'] ) ) { - $this->processScopeClose( $token['scope_condition'] ); - return; - } - } - - public function normalizeVarName( $varName ) { - $varName = preg_replace( '/[{}$]/', '', $varName ); - return $varName; - } - - public function scopeKey( $currScope ) { - if ( $currScope === false ) { - $currScope = 'file'; - } - return ( $this->currentFile ? $this->currentFile->getFilename() : 'unknown file' ) . - ':' . $currScope; - } - - // Warning: this is an autovivifying get - public function getScopeInfo( $currScope, $autoCreate = true ) { - require_once __DIR__ . '/VariableAnalysisHelper.php'; - $scopeKey = $this->scopeKey( $currScope ); - if ( !isset( $this->_scopes[$scopeKey] ) ) { - if ( !$autoCreate ) { - return null; - } - $this->_scopes[$scopeKey] = new ScopeInfo( $currScope ); - } - return $this->_scopes[$scopeKey]; - } - - public function getVariableInfo( $varName, $currScope, $autoCreate = true ) { - require_once __DIR__ . '/VariableAnalysisHelper.php'; - $scopeInfo = $this->getScopeInfo( $currScope, $autoCreate ); - if ( !isset( $scopeInfo->variables[$varName] ) ) { - if ( !$autoCreate ) { - return null; - } - $scopeInfo->variables[$varName] = new VariableInfo( $varName ); - if ( $this->validUnusedVariableNames && - in_array( $varName, $this->validUnusedVariableNames, true ) ) { - $scopeInfo->variables[$varName]->ignoreUnused = true; - } - } - return $scopeInfo->variables[$varName]; - } - - public function markVariableAssignment( $varName, $stackPtr, $currScope ) { - $varInfo = $this->getVariableInfo( $varName, $currScope ); - if ( !isset( $varInfo->scopeType ) ) { - $varInfo->scopeType = 'local'; - } - if ( isset( $varInfo->firstInitialized) && ( $varInfo->firstInitialized <= $stackPtr ) ) { - return; - } - $varInfo->firstInitialized = $stackPtr; - } - - public function markVariableDeclaration( $varName, $scopeType, $typeHint, $stackPtr, $currScope, $permitMatchingRedeclaration = false ) { - $varInfo = $this->getVariableInfo( $varName, $currScope ); - if ( isset( $varInfo->scopeType ) ) { - if ( ( $permitMatchingRedeclaration === false ) || - ( $varInfo->scopeType !== $scopeType ) ) { - // Issue redeclaration/reuse warning - // Note: we check off scopeType not firstDeclared, this is so that - // we catch declarations that come after implicit declarations like - // use of a variable as a local. - $message = 'Redeclaration of %s %s as %s.'; - $data = [ - VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], - "\${$varName}", - VariableInfo::$scopeTypeDescriptions[$scopeType], - ]; - $this->currentFile->addWarning( $message, $stackPtr, 'VariableRedeclaration', $data ); - } - } - $varInfo->scopeType = $scopeType; - if ( isset( $typeHint) ) { - $varInfo->typeHint = $typeHint; - } - if ( isset( $varInfo->firstDeclared) && ( $varInfo->firstDeclared <= $stackPtr ) ) { - return; - } - $varInfo->firstDeclared = $stackPtr; - } - - public function markVariableRead( $varName, $stackPtr, $currScope ) { - $varInfo = $this->getVariableInfo( $varName, $currScope ); - if ( isset( $varInfo->firstRead) && ( $varInfo->firstRead <= $stackPtr ) ) { - return; - } - $varInfo->firstRead = $stackPtr; - } - - public function isVariableInitialized( $varName, $stackPtr, $currScope ) { - $varInfo = $this->getVariableInfo( $varName, $currScope ); - - return isset( $varInfo->firstInitialized ) && $varInfo->firstInitialized <= $stackPtr; - } - - public function isVariableUndefined( $varName, $stackPtr, $currScope ) { - $varInfo = $this->getVariableInfo( $varName, $currScope, false ); - if ( isset( $varInfo->firstDeclared) && $varInfo->firstDeclared <= $stackPtr ) { - // TODO: do we want to check scopeType here? - return false; - } - if ( isset( $varInfo->firstInitialized) && $varInfo->firstInitialized <= $stackPtr ) { - return false; - } - //VIP: do not report on undefined variables on file scope - it produces a ton of warnings for custom template files - if ( 0 === $currScope ) { - return false; - } - return true; - } - - public function markVariableReadAndWarnIfUndefined( $varName, $stackPtr, $currScope ) { - - $this->markVariableRead( $varName, $stackPtr, $currScope ); - - if ( $this->isVariableUndefined( $varName, $stackPtr, $currScope ) === true ) { - // We haven't been defined by this point. - $message = 'Variable %s is undefined.'; - $data = [ "\${$varName}" ]; - $this->phpcsFile->addWarning( $message, $stackPtr, 'UndefinedVariable', $data ); - } - return true; - } - - public function findFunctionPrototype( $stackPtr ) { - if ( ( $openPtr = $this->findContainingBrackets( $stackPtr ) ) === false ) { - return false; - } - // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, - // so we look backwards from the opening bracket for the first thing that - // isn't a function name, reference sigil or whitespace and check if - // it's a function keyword. - $functionPtr = $this->phpcsFile->findPrevious(array( T_STRING, T_WHITESPACE, T_BITWISE_AND ), - $openPtr - 1, null, true, null, true ); - if ( ( $functionPtr !== false ) && - ( $this->tokens[$functionPtr]['code'] === T_FUNCTION ) ) { - return $functionPtr; - } - return false; - } - - public function findVariableScope( $stackPtr ) { - $token = $this->tokens[$stackPtr]; - - $in_class = false; - if ( !empty( $token['conditions'] ) ) { - foreach (array_reverse( $token['conditions'], true ) as $scopePtr => $scopeCode ) { - if ( ( $scopeCode === T_FUNCTION ) || ( $scopeCode === T_CLOSURE ) ) { - return $scopePtr; - } - if ( ( $scopeCode === T_CLASS) || ( $scopeCode === T_INTERFACE ) ) { - $in_class = true; - } - } - } - - if ( ( $scopePtr = $this->findFunctionPrototype( $stackPtr ) ) !== false ) { - return $scopePtr; - } - - if ( $in_class) { - // Member var of a class, we don't care. - return false; - } - - // File scope, hmm, lets use first token of file? - return 0; - } - - public function isNextThingAnAssign( $stackPtr ) { - - // Is the next non-whitespace an assignment? - $nextPtr = $this->phpcsFile->findNext( T_WHITESPACE, $stackPtr + 1, null, true, null, true ); - if ( ( $nextPtr !== false ) && $this->tokens[ $nextPtr ]['code'] === T_EQUAL ) { - return $nextPtr; - } - return false; - } - - public function findWhereAssignExecuted( $stackPtr ) { - - // Write should be recorded at the next statement to ensure we treat - // the assign as happening after the RHS execution. - // eg: $var = $var + 1; -> RHS could still be undef. - // However, if we're within a bracketed expression, we take place at - // the closing bracket, if that's first. - // eg: echo ( ( $var = 12) && ( $var == 12) ); - $semicolonPtr = $this->phpcsFile->findNext( T_SEMICOLON, $stackPtr + 1, null, false, null, true ); - $closePtr = false; - if ( ( ( $openPtr = $this->findContainingBrackets( $stackPtr ) ) !== false ) && isset( $this->tokens[ $openPtr ]['parenthesis_closer'] ) ) { - $closePtr = $this->tokens[$openPtr]['parenthesis_closer']; - } - - if ( $semicolonPtr === false ) { - if ( $closePtr === false ) { - // TODO: panic - return $stackPtr; - } - return $closePtr; - } - - if ( $closePtr < $semicolonPtr ) { - return $closePtr; - } - - return $semicolonPtr; - } - - public function findContainingBrackets( $stackPtr ) { - - if ( isset( $this->tokens[$stackPtr]['nested_parenthesis'] ) ) { - $openPtrs = array_keys( $this->tokens[$stackPtr]['nested_parenthesis'] ); - return end( $openPtrs); - } - return false; - } - - - public function findFunctionCall( $stackPtr ) { - - $openPtr = $this->findContainingBrackets( $stackPtr ); - if ( $openPtr ) { - // First non-whitespace thing and see if it's a T_STRING function name - $functionPtr = $this->phpcsFile->findPrevious( T_WHITESPACE, - $openPtr - 1, null, true, null, true ); - if ( $this->tokens[$functionPtr]['code'] === T_STRING) { - return $functionPtr; - } - } - return false; - } - - public function findFunctionCallArguments( $stackPtr ) { - - // Slight hack: also allow this to find args for array constructor. - // TODO: probably should refactor into three functions: arg-finding and bracket-finding - if ( $this->tokens[ $stackPtr ]['code'] !== T_STRING && $this->tokens[ $stackPtr ]['code'] !== T_ARRAY && ( $stackPtr = $this->findFunctionCall( $stackPtr ) ) === false ) { - return false; - } - - // $stackPtr is the function name, find our brackets after it - $openPtr = $this->phpcsFile->findNext( T_WHITESPACE, - $stackPtr + 1, null, true, null, true ); - if ( ( $openPtr === false ) || ( $this->tokens[$openPtr]['code'] !== T_OPEN_PARENTHESIS ) ) { - return false; - } - - if ( !isset( $this->tokens[$openPtr]['parenthesis_closer'] ) ) { - return false; - } - $closePtr = $this->tokens[$openPtr]['parenthesis_closer']; - - $argPtrs = array(); - $lastPtr = $openPtr; - $lastArgComma = $openPtr; - while ( ( $nextPtr = $this->phpcsFile->findNext( T_COMMA, $lastPtr + 1, $closePtr ) ) !== false ) { - if ( $this->findContainingBrackets( $nextPtr ) === $openPtr ) { - // Comma is at our level of brackets, it's an argument delimiter. - $argPtrs[] = range( $lastArgComma + 1, $nextPtr - 1 ); - $lastArgComma = $nextPtr; - } - $lastPtr = $nextPtr; - } - $argPtrs[] = range( $lastArgComma + 1, $closePtr - 1 ); - - return $argPtrs; - } - - protected function checkForFunctionPrototype( $stackPtr, $varName, $currScope ) { - - // Are we a function or closure parameter? - // It would be nice to get the list of function parameters from watching for - // T_FUNCTION, but AbstractVariableSniff and AbstractScopeSniff define everything - // we need to do that as private or final, so we have to do it this hackish way. - if ( ( $openPtr = $this->findContainingBrackets( $stackPtr ) ) === false ) { - return false; - } - - // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, - // so we look backwards from the opening bracket for the first thing that - // isn't a function name, reference sigil or whitespace and check if - // it's a function keyword. - $functionPtr = $this->phpcsFile->findPrevious(array( T_STRING, T_WHITESPACE, T_BITWISE_AND ), - $openPtr - 1, null, true, null, true ); - if ( ( $functionPtr !== false ) && - ( ( $this->tokens[$functionPtr]['code'] === T_FUNCTION) || - ( $this->tokens[$functionPtr]['code'] === T_CLOSURE ) )) { - // TODO: typeHint - $this->markVariableDeclaration( $varName, 'param', null, $stackPtr, $functionPtr ); - // Are we pass-by-reference? - $referencePtr = $this->phpcsFile->findPrevious( T_WHITESPACE, - $stackPtr - 1, null, true, null, true ); - if ( ( $referencePtr !== false ) && ( $this->tokens[$referencePtr]['code'] === T_BITWISE_AND ) ) { - $varInfo = $this->getVariableInfo( $varName, $functionPtr ); - $varInfo->passByReference = true; - } - // Are we optional with a default? - if ( $this->isNextThingAnAssign( $stackPtr ) !== false ) { - $this->markVariableAssignment( $varName, $stackPtr, $functionPtr ); - } - return true; - } - - // Is it a use keyword? Use is both a read and a define, fun! - if ( ( $functionPtr !== false ) && ( $this->tokens[$functionPtr]['code'] === T_USE ) ) { - $this->markVariableRead( $varName, $stackPtr, $currScope ); - if ( $this->isVariableUndefined( $varName, $stackPtr, $currScope ) === true ) { - // We haven't been defined by this point. - $message = 'Variable `%s` is undefined.'; - $data = [ "\${$varName}" ]; - $this->phpcsFile->addWarning( $message, $stackPtr, 'UndefinedVariable', $data ); - return true; - } - // $functionPtr is at the use, we need the function keyword for start of scope. - $functionPtr = $this->phpcsFile->findPrevious( T_CLOSURE, - $functionPtr - 1, $currScope + 1, false, null, true ); - if ( $functionPtr !== false ) { - // TODO: typeHints in use? - $this->markVariableDeclaration( $varName, 'bound', null, $stackPtr, $functionPtr ); - $this->markVariableAssignment( $varName, $stackPtr, $functionPtr ); - return true; - } - } - return false; - } - - protected function checkForCatchBlock( $stackPtr, $varName, $currScope ) { - - // Are we a catch block parameter? - if ( ( $openPtr = $this->findContainingBrackets( $stackPtr ) ) === false ) { - return false; - } - - // Function names are T_STRING, and return-by-reference is T_BITWISE_AND, - // so we look backwards from the opening bracket for the first thing that - // isn't a function name, reference sigil or whitespace and check if - // it's a function keyword. - $catchPtr = $this->phpcsFile->findPrevious( T_WHITESPACE, - $openPtr - 1, null, true, null, true ); - if ( ( $catchPtr !== false ) && - ( $this->tokens[$catchPtr]['code'] === T_CATCH) ) { - // Scope of the exception var is actually the function, not just the catch block. - // TODO: typeHint - $this->markVariableDeclaration( $varName, 'local', null, $stackPtr, $currScope, true ); - $this->markVariableAssignment( $varName, $stackPtr, $currScope ); - if ( $this->allowUnusedCaughtExceptions) { - $varInfo = $this->getVariableInfo( $varName, $currScope ); - $varInfo->ignoreUnused = true; - } - return true; - } - return false; - } - - protected function checkForThisWithinClass( $stackPtr, $varName ) { - $token = $this->tokens[$stackPtr]; - - // Are we $this within a class? - if ( ( $varName !== 'this' ) || empty( $token['conditions'] ) ) { - return false; - } - - foreach (array_reverse( $token['conditions'], true ) as $scopePtr => $scopeCode ) { - // $this within a closure is invalid - // Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes. - if ( $this->tokens[$scopePtr]['code'] === T_CLOSURE ) { - return false; - } - if ( $scopeCode === T_CLASS || $scopeCode === T_TRAIT ) { - return true; - } - } - - return false; - } - - protected function checkForSuperGlobal( $varName ) { - // Are we a superglobal variable? - if ( in_array( $varName, array( - 'GLOBALS', - '_SERVER', - '_GET', - '_POST', - '_FILES', - '_COOKIE', - '_SESSION', - '_REQUEST', - '_ENV', - 'argv', - 'argc', - ) ) ) { - return true; - } - - return false; - } - - protected function checkForStaticMember( $stackPtr, $varName ) { - $token = $this->tokens[$stackPtr]; - - // Are we a static member? - $doubleColonPtr = $stackPtr - 1; - if ( $this->tokens[$doubleColonPtr]['code'] !== T_DOUBLE_COLON ) { - return false; - } - $classNamePtr = $stackPtr - 2; - if ( ( $this->tokens[$classNamePtr]['code'] !== T_STRING ) && - ( $this->tokens[$classNamePtr]['code'] !== T_SELF ) && - ( $this->tokens[$classNamePtr]['code'] !== T_STATIC ) ) { - return false; - } - - // Are we refering to self:: outside a class? - // TODO: not sure this is our business or should be some other sniff. - if ( ( $this->tokens[$classNamePtr]['code'] === T_SELF ) || - ( $this->tokens[$classNamePtr]['code'] === T_STATIC ) ) { - if ( $this->tokens[$classNamePtr]['code'] === T_SELF ) { - $err_prefix = 'Self'; - $err_desc = 'self::'; - } else { - $err_prefix = 'Static'; - $err_desc = 'static::'; - } - if ( !empty( $token['conditions'] ) ) { - foreach (array_reverse( $token['conditions'], true ) as $scopePtr => $scopeCode ) { - // self within a closure is invalid - // Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes. - if ( $this->tokens[$scopePtr]['code'] === T_CLOSURE ) { - $message = "Use of `{$err_desc}%s` inside closure."; - $data = [ "\${$varName}" ]; - $this->phpcsFile->addError( $message, $stackPtr,$err_prefix . 'InsideClosure', $data ); - return true; - } - if ( $scopeCode === T_CLASS ) { - return true; - } - } - } - - $message = "Use of `{$err_desc}%s` outside class definition."; - $data = [ "\${$varName}" ]; - $this->phpcsFile->addError( $message, $stackPtr,$err_prefix . 'OutsideClass', $data ); - return true; - } - - return true; - } - - protected function checkForAssignment( $stackPtr, $varName, $currScope ) { - // Is the next non-whitespace an assignment? - if ( ( $assignPtr = $this->isNextThingAnAssign( $stackPtr ) ) === false ) { - return false; - } - - // Plain ol' assignment. Simple-ish. - if ( ( $writtenPtr = $this->findWhereAssignExecuted( $assignPtr ) ) === false ) { - $writtenPtr = $stackPtr; // I dunno - } - $this->markVariableAssignment( $varName, $writtenPtr, $currScope ); - return true; - } - - protected function checkForListAssignment( $stackPtr, $varName, $currScope ) { - - // OK, are we within a list (...) construct? - if ( ( $openPtr = $this->findContainingBrackets( $stackPtr ) ) === false ) { - return false; - } - - $prevPtr = $this->phpcsFile->findPrevious( T_WHITESPACE, $openPtr - 1, null, true, null, true ); - if ( ( $prevPtr === false ) || ( $this->tokens[$prevPtr]['code'] !== T_LIST) ) { - return false; - } - - // OK, we're a list (...) construct... are we being assigned to? - $closePtr = $this->tokens[$openPtr]['parenthesis_closer']; - if ( ( $assignPtr = $this->isNextThingAnAssign( $closePtr ) ) === false ) { - return false; - } - - // Yes, we're being assigned. - $writtenPtr = $this->findWhereAssignExecuted( $assignPtr ); - $this->markVariableAssignment( $varName, $writtenPtr, $currScope ); - return true; - } - - protected function checkForGlobalDeclaration( $stackPtr, $varName, $currScope ) { - - // Are we a global declaration? - // Search backwards for first token that isn't whitespace, comma or variable. - $globalPtr = $this->phpcsFile->findPrevious( - array( T_WHITESPACE, T_VARIABLE, T_COMMA ), - $stackPtr - 1, null, true, null, true ); - if ( ( $globalPtr === false ) || ( $this->tokens[$globalPtr]['code'] !== T_GLOBAL ) ) { - return false; - } - - // It's a global declaration. - $this->markVariableDeclaration( $varName, 'global', null, $stackPtr, $currScope ); - return true; - } - - protected function checkForStaticDeclaration( $stackPtr, $varName, $currScope ) { - - // Are we a static declaration? - // Static declarations are a bit more complicated than globals, since they - // can contain assignments. The assignment is compile-time however so can - // only be constant values, which makes life manageable. - // - // Just to complicate matters further, late static binding constants - // take the form static::CONSTANT and are invalid within static variable - // assignments, but we don't want to accidentally match their use of the - // static keyword. - // - // Valid values are: - // number T_MINUS T_LNUMBER T_DNUMBER - // string T_CONSTANT_ENCAPSED_STRING - // heredoc T_START_HEREDOC T_HEREDOC T_END_HEREDOC - // nowdoc T_START_NOWDOC T_NOWDOC T_END_NOWDOC - // define T_STRING - // class constant T_STRING T_DOUBLE_COLON T_STRING - // Search backwards for first token that isn't whitespace, comma, variable, - // equals, or on the list of assignable constant values above. - $staticPtr = $this->phpcsFile->findPrevious( - array( - T_WHITESPACE, T_VARIABLE, T_COMMA, T_EQUAL, - T_MINUS, T_LNUMBER, T_DNUMBER, - T_CONSTANT_ENCAPSED_STRING, - T_STRING, - T_DOUBLE_COLON, - T_START_HEREDOC, T_HEREDOC, T_END_HEREDOC, - T_START_NOWDOC, T_NOWDOC, T_END_NOWDOC, - ), - $stackPtr - 1, null, true, null, true ); - if ( ( $staticPtr === false ) || ( $this->tokens[$staticPtr]['code'] !== T_STATIC) ) { - //if ( $varName == 'static4' ) { - // echo "Failing token:\n" . print_r( $tokens[$staticPtr], true ); - //} - return false; - } - - // Is it a late static binding static::? - // If so, this isn't the static keyword we're looking for, but since - // static:: isn't allowed in a compile-time constant, we also know - // we can't be part of a static declaration anyway, so there's no - // need to look any further. - $lateStaticBindingPtr = $this->phpcsFile->findNext( T_WHITESPACE, $staticPtr + 1, null, true, null, true ); - if ( ( $lateStaticBindingPtr !== false ) && ( $this->tokens[$lateStaticBindingPtr]['code'] === T_DOUBLE_COLON ) ) { - return false; - } - - // It's a static declaration. - $this->markVariableDeclaration( $varName, 'static', null, $stackPtr, $currScope ); - if ( $this->isNextThingAnAssign( $stackPtr ) !== false ) { - $this->markVariableAssignment( $varName, $stackPtr, $currScope ); - } - return true; - } - - protected function checkForForeachLoopVar( $stackPtr, $varName, $currScope ) { - // Are we a foreach loop var? - if ( ( $openPtr = $this->findContainingBrackets( $stackPtr ) ) === false ) { - return false; - } - - // Is there an 'as' token between us and the opening bracket? - if ( $this->phpcsFile->findPrevious( T_AS, $stackPtr - 1, $openPtr ) === false ) { - return false; - } - - $this->markVariableAssignment( $varName, $stackPtr, $currScope ); - return true; - } - - protected function checkForPassByReferenceFunctionCall( $stackPtr, $varName, $currScope ) { - - // Are we pass-by-reference to known pass-by-reference function? - if ( ( $functionPtr = $this->findFunctionCall( $stackPtr ) ) === false ) { - return false; - } - - // Is our function a known pass-by-reference function? - $functionName = $this->tokens[$functionPtr]['content']; - if ( !isset( $this->_passByRefFunctions[$functionName] ) ) { - return false; - } - - $refArgs = $this->_passByRefFunctions[$functionName]; - - if ( ( $argPtrs = $this->findFunctionCallArguments( $stackPtr ) ) === false ) { - return false; - } - - // We're within a function call arguments list, find which arg we are. - $argPos = false; - foreach ( $argPtrs as $idx => $ptrs) { - if ( in_array( $stackPtr, $ptrs, true ) ) { - $argPos = $idx + 1; - break; - } - } - if ( $argPos === false ) { - return false; - } - if ( ! in_array( $argPos, $refArgs, true ) ) { - // Our arg wasn't mentioned explicitly, are we after an ellipsis catch-all? - if ( ( $elipsis = array_search( '...', $refArgs, true ) ) === false ) { - return false; - } - if ( $argPos < $refArgs[$elipsis - 1] ) { - return false; - } - } - - // Our argument position matches that of a pass-by-ref argument, - // check that we're the only part of the argument expression. - foreach ( $argPtrs[$argPos - 1] as $ptr ) { - if ( $ptr === $stackPtr ) { - continue; - } - if ( $this->tokens[$ptr]['code'] !== T_WHITESPACE ) { - return false; - } - } - - // Just us, we can mark it as a write. - $this->markVariableAssignment( $varName, $stackPtr, $currScope ); - // It's a read as well for purposes of used-variables. - $this->markVariableRead( $varName, $stackPtr, $currScope ); - return true; - } - - protected function checkForSymbolicObjectProperty( $stackPtr, $varName, $currScope ) { - - // Are we a symbolic object property/function dereference? - // Search backwards for first token that isn't whitespace, is it a "->" operator? - $objectOperatorPtr = $this->phpcsFile->findPrevious( - T_WHITESPACE, - $stackPtr - 1, null, true, null, true ); - if ( ( $objectOperatorPtr === false ) || ( $this->tokens[$objectOperatorPtr]['code'] !== T_OBJECT_OPERATOR ) ) { - return false; - } - - $this->markVariableReadAndWarnIfUndefined( $varName, $stackPtr, $currScope ); - return true; + ]; } /** - * Called to process class member vars. + * Don't use. * - * @param File $phpcsFile The PHP_CodeSniffer file where the token was found. - * @param int $stackPtr The position where the token was found. + * @since 2.2.0 Added to allow for throwing the deprecation notices. + * @deprecated 2.2.0 * - * @return void - */ - protected function processMemberVar( $stackPtr ) { - // TODO: don't care for now - } - - /** - * Called to process normal member vars. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. * - * @param File $phpcsFile The PHP_CodeSniffer file where the token was found. - * @param int $stackPtr The position where the token was found. - * - * @return void + * @return int|void Integer stack pointer to skip forward or void to continue + * normal file processing. */ - protected function processVariable( $stackPtr ) { - $token = $this->tokens[$stackPtr]; - - $varName = $this->normalizeVarName( $token['content'] ); - if ( ( $currScope = $this->findVariableScope( $stackPtr ) ) === false ) { - return; - } - - //static $dump_token = false; - //if ( $varName == 'property' ) { - // $dump_token = true; - //} - //if ( $dump_token) { - // echo "Found variable {$varName} on line {$token['line']} in scope {$currScope}.\n" . print_r( $token, true ); - // echo "Prev:\n" . print_r( $tokens[$stackPtr - 1], true ); - //} + public function process( File $phpcsFile, $stackPtr ) { - // Determine if variable is being assigned or read. - - // Read methods that preempt assignment: - // Are we a $object->$property type symbolic reference? - - // Possible assignment methods: - // Is a mandatory function/closure parameter - // Is an optional function/closure parameter with non-null value - // Is closure use declaration of a variable defined within containing scope - // catch (...) block start - // $this within a class (but not within a closure ). - // $GLOBALS, $_REQUEST, etc superglobals. - // $var part of class::$var static member - // Assignment via = - // Assignment via list (...) = - // Declares as a global - // Declares as a static - // Assignment via foreach (... as ...) { } - // Pass-by-reference to known pass-by-reference function - - // Are we a $object->$property type symbolic reference? - if ( $this->checkForSymbolicObjectProperty( $stackPtr, $varName, $currScope ) ) { - return; + if ( false === $this->thrown['DeprecatedSniff'] ) { + $this->thrown['DeprecatedSniff'] = $phpcsFile->addWarning( + 'The "WordPressVIPMinimum.Variables.VariableAnalysis" sniff has been deprecated. Use the "VariableAnalysis.CodeAnalysis.VariableAnalysis" sniff instead. Please update your custom ruleset.', + 0, + 'DeprecatedSniff' + ); } - - // Are we a function or closure parameter? - if ( $this->checkForFunctionPrototype( $stackPtr, $varName, $currScope ) ) { - return; + if ( ! empty( $this->exclude ) && false === $this->thrown['FoundPropertyForDeprecatedSniff'] ) { + $this->thrown['FoundPropertyForDeprecatedSniff'] = $phpcsFile->addWarning( + 'The "WordPressVIPMinimum.Variables.VariableAnalysis" sniff has been deprecated. Use the "CodeAnalysis.VariableAnalysis" sniff instead. "exclude" property setting found. Please update your custom ruleset.', + 0, + 'FoundPropertyForDeprecatedSniff' + ); } - // Are we a catch parameter? - if ( $this->checkForCatchBlock( $stackPtr, $varName, $currScope ) ) { - return; - } - - // Are we $this within a class? - if ( $this->checkForThisWithinClass( $stackPtr, $varName ) ) { - return; - } - - // Are we a $GLOBALS, $_REQUEST, etc superglobal? - if ( $this->checkForSuperGlobal( $varName ) ) { - return; - } - - // $var part of class::$var static member - if ( $this->checkForStaticMember( $stackPtr, $varName ) ) { - return; - } - - // Is the next non-whitespace an assignment? - if ( $this->checkForAssignment( $stackPtr, $varName, $currScope ) ) { - return; - } - - // OK, are we within a list (...) = construct? - if ( $this->checkForListAssignment( $stackPtr, $varName, $currScope ) ) { - return; - } - - // Are we a global declaration? - if ( $this->checkForGlobalDeclaration( $stackPtr, $varName, $currScope ) ) { - return; - } - - // Are we a static declaration? - if ( $this->checkForStaticDeclaration( $stackPtr, $varName, $currScope ) ) { - return; - } - - // Are we a foreach loop var? - if ( $this->checkForForeachLoopVar( $stackPtr, $varName, $currScope ) ) { - return; - } - - // Are we pass-by-reference to known pass-by-reference function? - if ( $this->checkForPassByReferenceFunctionCall( $stackPtr, $varName, $currScope ) ) { - return; - } - - // OK, we don't appear to be a write to the var, assume we're a read. - $this->markVariableReadAndWarnIfUndefined( $varName, $stackPtr, $currScope ); - } - - /** - * Called to process variables found in double quoted strings. - * - * Note that there may be more than one variable in the string, which will - * result only in one call for the string. - * - * @param File $phpcsFile The PHP_CodeSniffer file where the token was found. - * @param int $stackPtr The position where the double quoted string was found. - * - * @return void - */ - protected function processVariableInString( $stackPtr ) { - $token = $this->tokens[$stackPtr]; - - if ( !preg_match_all( $this->_double_quoted_variable_regexp, $token['content'], $matches) ) { - return; - } - - $currScope = $this->findVariableScope( $stackPtr ); - foreach ( $matches[1] as $varName ) { - $varName = $this->normalizeVarName( $varName ); - // Are we $this within a class? - if ( $this->checkForThisWithinClass( $stackPtr, $varName ) ) { - continue; - } - if ( $this->checkForSuperGlobal( $varName ) ) { - continue; - } - $this->markVariableReadAndWarnIfUndefined( $varName, $stackPtr, $currScope ); - } - } - - protected function processCompactArguments( $stackPtr, $arguments, $currScope ) { - - foreach ( $arguments as $argumentPtrs ) { - $argumentPtrs = array_values( array_filter( $argumentPtrs, array( $this, 'filter_non_whitespace_tokens' ) ) ); - if (empty( $argumentPtrs) ) { - continue; - } - if ( !isset( $this->tokens[$argumentPtrs[0]] ) ) { - continue; - } - $argument_first_token = $this->tokens[$argumentPtrs[0]]; - if ( $argument_first_token['code'] === T_ARRAY ) { - // It's an array argument, recurse. - if ( ( $array_arguments = $this->findFunctionCallArguments( $argumentPtrs[0] ) ) !== false ) { - $this->processCompactArguments( $stackPtr, $array_arguments, $currScope ); - } - continue; - } - if (count( $argumentPtrs) > 1) { - // Complex argument, we can't handle it, ignore. - continue; - } - if ( $argument_first_token['code'] === T_CONSTANT_ENCAPSED_STRING ) { - // Single-quoted string literal, ie compact( 'whatever' ). - // Substr is to strip the enclosing single-quotes. - $varName = substr( $argument_first_token['content'], 1, -1); - $this->markVariableReadAndWarnIfUndefined( $varName, $argumentPtrs[0], $currScope ); - continue; - } - if ( $argument_first_token['code'] === T_DOUBLE_QUOTED_STRING) { - // Double-quoted string literal. - if (preg_match( $this->_double_quoted_variable_regexp, $argument_first_token['content'] ) ) { - // Bail if the string needs variable expansion, that's runtime stuff. - continue; - } - // Substr is to strip the enclosing double-quotes. - $varName = substr( $argument_first_token['content'], 1, -1); - $this->markVariableReadAndWarnIfUndefined( $varName, $argumentPtrs[0], $currScope ); - } - } - } - - /** - * Called to process variables named in a call to compact(). - * - * @param File $phpcsFile The PHP_CodeSniffer file where the token was found. - * @param int $stackPtr The position where the call to compact() was found. - * - * @return void - */ - protected function processCompact( $stackPtr ) { - $currScope = $this->findVariableScope( $stackPtr ); - - if ( ( $arguments = $this->findFunctionCallArguments( $stackPtr ) ) !== false ) { - $this->processCompactArguments( $stackPtr, $arguments, $currScope ); - } - } - - /** - * Called to process the end of a scope. - * - * Note that although triggered by the closing curly brace of the scope, $stackPtr is - * the scope conditional, not the closing curly brace. - * - * @param File $phpcsFile The PHP_CodeSniffer file where the token was found.. - * @param int $stackPtr The position of the scope conditional. - * - * @return void - */ - protected function processScopeClose ( $stackPtr ) { - $scopeInfo = $this->getScopeInfo( $stackPtr, false ); - if ( null === $scopeInfo ) { - return; - } - foreach ( $scopeInfo->variables as $varInfo ) { - if ( $varInfo->ignoreUnused || isset( $varInfo->firstRead ) ) { - continue; - } - if ( $this->allowUnusedFunctionParameters && $varInfo->scopeType === 'param' ) { - continue; - } - if ( $varInfo->passByReference && isset( $varInfo->firstInitialized ) ) { - // If we're pass-by-reference then it's a common pattern to - // use the variable to return data to the caller, so any - // assignment also counts as "variable use" for the purposes - // of "unused variable" warnings. - continue; - } - - $message = 'Unused %s `%s`.'; - $data = [ - VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType], - "\${$varInfo->name}", - ]; - - if ( isset( $varInfo->firstDeclared ) ) { - $this->phpcsFile->addWarning( $message, $varInfo->firstDeclared, 'UnusedVariable', $data ); - } - if ( isset( $varInfo->firstInitialized ) ) { - $this->phpcsFile->addWarning( $message, $varInfo->firstInitialized, 'UnusedVariable', $data ); - } - } - } - - public function filter_non_whitespace_tokens( $argumentPtr ) { - return $this->tokens[$argumentPtr]['code'] !== T_WHITESPACE; + parent::process( $phpcsFile, $stackPtr ); } } -// @codingStandardsIgnoreEnd diff --git a/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.inc b/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.inc index 01231f69..2c8d0347 100644 --- a/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.inc @@ -2,7 +2,7 @@ function foo() { $a = 'Hello'; - $c = compact( $a, $b ); + $c = compact( $a, $b ); // Warning x2. } trait bar { @@ -17,3 +17,13 @@ function test() { do_something_silly(); } catch ( Exception $e ) {} // OK. } + +class MyClass { + function my_function() { + return function() { + $this->my_callback(); // OK - new VariableAnalysis doesn't flag $this as undefined in closure. + }; + } + + function my_callback() {} + } diff --git a/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php b/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php index 8ddcf625..44fd0aba 100644 --- a/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php +++ b/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php @@ -32,8 +32,8 @@ public function getErrorList() { */ public function getWarningList() { return [ - 5 => 2, - 18 => 2, + 1 => 1, + 5 => 2, ]; } diff --git a/WordPressVIPMinimum/ruleset-test.inc b/WordPressVIPMinimum/ruleset-test.inc index 632d0aa4..56df28dc 100644 --- a/WordPressVIPMinimum/ruleset-test.inc +++ b/WordPressVIPMinimum/ruleset-test.inc @@ -2,7 +2,7 @@ My term link'; // Error. +echo 'My term link'; // Error. // WordPressVIPMinimum.Functions.DynamicCalls $my_notokay_func = 'extract'; @@ -311,7 +311,7 @@ $my_notokay_func(); // Error. wp_cache_get_multi(); // Error. opcache_reset(); // Error. opcache_invalidate( 'test_script.php' ); // Error. -opcache_compile_file( $test_script ); // Error. +opcache_compile_file( $var ); // Error. opcache_​is_​script_​cached( 'test_script.php' ); // Error. opcache_​get_​status(); // Error. opcache_​get_​configuration(); // Error. @@ -409,7 +409,7 @@ wpcom_vip_get_category_by_slug(); // Warning. // WordPressVIPMinimum.Functions.StripTagsSniff strip_tags( 'Testing' ); // Warning. -strip_tags( 'Test', $html ); // Warning. +strip_tags( 'Test', $text ); // Warning. // WordPressVIPMinimum.Hooks.AlwaysReturnInFilter function bad_example_function_thing() { // Error. @@ -501,7 +501,7 @@ update_option( 'taxonomy_rating_' . $category_id ); // Warning. // WordPressVIPMinimum.Performance.WPQueryParams $query_args = array( - 'post__not_in' => $posts_not_in, // Warning. + 'post__not_in' => $posts_not_in, // Warning. 'suppress_filters' => true, // Error. ); @@ -597,11 +597,14 @@ $_SERVER['HTTP_X_FORWARDED_FOR']; // Error. $_SERVER["REMOTE_ADDR"]; // Error. // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized +class MyClass { + function my_function() { + return function() { + $this->my_callback(); // OK - new VariableAnalysis doesn't flag $this as undefined in closure. + }; + } -// WordPressVIPMinimum.Variables.VariableAnalysis -function foo() { - $a = 'Hello'; - $c = compact( $a, $b ); // Warning x 2. + function my_callback() {} } // Generic.VersionControl.GitMergeConflict diff --git a/WordPressVIPMinimum/ruleset-test.php b/WordPressVIPMinimum/ruleset-test.php index b3376134..2e8c7b99 100644 --- a/WordPressVIPMinimum/ruleset-test.php +++ b/WordPressVIPMinimum/ruleset-test.php @@ -206,9 +206,9 @@ 595 => 1, 596 => 1, 597 => 1, - 609 => 1, - 611 => 1, - 615 => 1, + 612 => 1, + 614 => 1, + 618 => 1, ], 'warnings' => [ 32 => 1, @@ -303,7 +303,6 @@ 559 => 1, 565 => 1, 589 => 1, - 604 => 2, ], 'messages' => [ 130 => [ diff --git a/WordPressVIPMinimum/ruleset.xml b/WordPressVIPMinimum/ruleset.xml index 7e0d0d68..ea062d2e 100644 --- a/WordPressVIPMinimum/ruleset.xml +++ b/WordPressVIPMinimum/ruleset.xml @@ -158,10 +158,35 @@ `%1$s()` performs a no-LIMIT query by default, make sure to set a reasonable `posts_per_page`. `%1$s()` will do a -1 query by default, a maximum of 100 should be used. - - - - + + + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 diff --git a/composer.json b/composer.json index 27133da1..291e5eee 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,7 @@ ], "require": { "php": ">=5.4", + "sirbrillig/phpcs-variable-analysis": "^2.8.3", "squizlabs/php_codesniffer": "^3.5.5", "wp-coding-standards/wpcs": "^2.3" }, From ebddcfc3f227f3fdad5d576829570a3dcf363fee Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 03:18:47 +0200 Subject: [PATCH 04/35] Travis: change from "trusty" to "xenial" As the "trusty" environment is no longer officially supported by Travis, they decided in their wisdom to silently stop updating the PHP "nightly" image, which makes it next to useless as the last image apparently is from January.... This updates the Travis config to: * Use the `xenial` distro, which at this time is the default. * Sets the distro for low PHP versions explicitly to `trusty`. --- .travis.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 97020ee1..65f73b2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: php os: linux -dist: trusty +dist: xenial env: # `master` is now 3.x. @@ -13,8 +13,6 @@ cache: - $HOME/.cache/composer/files php: - - 5.4 - - 5.5 - 5.6 - 7.0 - 7.1 @@ -69,6 +67,20 @@ jobs: # Run PHPCS against VIPCS. - ./bin/phpcs + # Builds which need a different distro. + - stage: test + - php: 5.5 + dist: trusty + env: PHPCS_BRANCH="dev-master" + - php: 5.5 + dist: trusty + env: PHPCS_BRANCH="3.5.5" + - php: 5.4 + dist: trusty + env: PHPCS_BRANCH="dev-master" + - php: 5.4 + dist: trusty + env: PHPCS_BRANCH="3.5.5" before_install: # Speed up build time by disabling Xdebug. From a44e76b8e2687b48f732322d8b4bcc9a8e882c63 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 21:07:33 +0200 Subject: [PATCH 05/35] Contributing: move file to `.github` directory --- CONTRIBUTING.md => .github/CONTRIBUTING.md | 0 README.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (100%) diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md diff --git a/README.md b/README.md index ee2d7938..01001cd0 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Alternatively, you should register the standard to PHPCS by appending the VIPCS ## Contribution -Please see [CONTRIBUTION.md](CONTRIBUTING.md). +Please see [CONTRIBUTION.md](.github/CONTRIBUTING.md). ## License From 57e4780a10882babb50ca68e0326904166f0cb4a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 21:31:22 +0200 Subject: [PATCH 06/35] Contributing: improve the text As GH was so kind as to point me to the "contributing guidelines which have been changed since you last contributed" I quickly scanned through the file and most notably, came across a link to the WPCS wiki page, while this link should have gone to the VIPCS wiki. As I was editing the file now anyway, I've made some other changes along the way. * Ask people to search the issue list before opening an issue. * Made a little table to make it easier for people to report upstream issues to the correct repository. * Updated the "custom properties" link to point to the VIPCS wiki. * Updated the PHPUnit installation link. * Updated the `phpunit.xml` example to be in line with the current `phpunit.xml.dist` file. * Updated the expected unit test output. --- .github/CONTRIBUTING.md | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3a3200f1..6d3bff7b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -7,11 +7,25 @@ Hi, thank you for your interest in contributing to the VIP Coding Standards! We Before reporting a bug, you should check what sniff an error is coming from. Running `phpcs` with the `-s` flag will show the name of the sniff with each error. +Please search the repository before opening an issue to verify that the issue hasn't been reported already. + Bug reports containing a minimal code sample which can be used to reproduce the issue are highly appreciated as those are most easily actionable. ### Upstream Issues -Since VIPCS employs many sniffs that are part of PHPCS, and makes use of WordPress Coding Standards sniffs, sometimes an issue will be caused by a bug upstream and not in VIPCS itself. If the error message in question doesn't come from a sniff whose name starts with `WordPressVIPMinimum`, the issue is probably a bug in PHPCS itself, and should be [reported there](https://github.com/squizlabs/PHP_CodeSniffer/issues). +Since VIPCS employs many sniffs that are part of PHPCS, and makes use of WordPress Coding Standards sniffs, sometimes an issue will be caused by a bug upstream and not in VIPCS itself. If the error message in question doesn't come from a sniff whose name starts with `WordPressVIPMinimum`, the issue is probably an upstream bug. + +To determine where best to report the bug, use the first part of the sniff name: + +Sniffname starts with | Report to +--- | --- +`Generic` | [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/issues/) +`PSR2` | [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/issues/) +`Squiz` | [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/issues/) +`VariableAnalysis` | [VariableAnalysis](https://github.com/sirbrillig/phpcs-variable-analysis/issues/) +`WordPress` | [WordPressCS](https://github.com/WordPress/WordPress-Coding-Standards/issues/) +`WordPressVIPMinimum` | [VIPCS](https://github.com/Automattic/VIP-Coding-Standards/issues/) (this repo) +`Generic`, `PSR2` or `Squiz` | [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/issues/) ---- @@ -42,7 +56,7 @@ The sniffs and test files - not test _case_ files! - for VIPCS should be written When writing sniffs, always remember that any `public` sniff property can be overruled via a custom ruleset by the end-user. Only make a property `public` if that is the intended behaviour. -When you introduce new `public` sniff properties, or your sniff extends a class from which you inherit a `public` property, please don't forget to update the [public properties wiki page](https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Customizable-sniff-properties) with the relevant details once your PR has been merged into the `develop` branch. +When you introduce new `public` sniff properties, or your sniff extends a class from which you inherit a `public` property, please don't forget to update the [public properties wiki page](https://github.com/Automattic/VIP-Coding-Standards/wiki/Custom-properties-for-VIPCS-Sniffs) with the relevant details once your PR has been merged into the `develop` branch. ## Unit Testing @@ -61,7 +75,7 @@ N.B.: If you installed VIPCS using Composer, make sure you used `--prefer-source If you already have PHPUnit installed on your system: Congrats, you're all set. If not, you can navigate to the directory where the `PHP_CodeSniffer` repo is checked out and do `composer install` to install the `dev` dependencies. -Alternatively, you can [install PHPUnit](https://phpunit.de/manual/5.7/en/installation.html) as a PHAR file. +Alternatively, you can [install PHPUnit](https://phpunit.readthedocs.io/en/7.5/installation.html) as a PHAR file. ### Before running the unit tests @@ -71,11 +85,13 @@ For the unit tests to work, you need to make sure PHPUnit can find your `PHP_Cod The easiest way to do this is to add a `phpunit.xml` file to the root of your VIPCS installation and set a `PHPCS_DIR` environment variable from within this file. Make sure to adjust the path to reflect your local setup. ```xml - + @@ -86,7 +102,7 @@ The easiest way to do this is to add a `phpunit.xml` file to the root of your VI ### Running the unit tests * Make sure you have registered the directory in which you installed VIPCS with PHPCS using; - + ```sh phpcs --config-set installed_paths path/to/VIPCS ``` @@ -99,13 +115,13 @@ The easiest way to do this is to add a `phpunit.xml` file to the root of your VI Expected output: ``` -PHPUnit 7.5.12 by Sebastian Bergmann and contributors. +PHPUnit 7.5.20 by Sebastian Bergmann and contributors. -........................................... 43 / 43 (100%) +.......................................... 42 / 42 (100%) -44 sniff test files generated 119 unique error codes; 0 were fixable (0%) +43 sniff test files generated 117 unique error codes; 0 were fixable (0%) -Time: 380 ms, Memory: 30.00MB +Time: 246 ms, Memory: 32.00 MB ``` ### Unit Testing conventions From 74a0ce3f035354dd779d24d071bb5eff98a1d500 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 22:17:53 +0200 Subject: [PATCH 07/35] CS ruleset: minor tweaks 1. According to the `composer.json` file, the minimum supported PHP version is PHP 5.4, so PHPCompatibility should be set to check for that, not for PHP 5.6 and up. 2. Excluding a complete sniff instead of including it twice and excluding the single errorcode. This is more efficient as it prevents the sniff from running completely instead of letting the sniff run and silencing the error at the moment it is being thrown. --- .phpcs.xml.dist | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index db53aea3..61d8926f 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -16,6 +16,7 @@ + @@ -34,13 +35,8 @@ - - - - - - + From 9d1c62d5be839c98d79efbc93e96b97cd5da048b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 23:02:04 +0200 Subject: [PATCH 08/35] RulesetTest: fix compatibility with Windows This is probably just needed for me, but when running the ruleset tests locally on Windows, they wouldn't run and would show a `'$PHPCS_BIN' is not recognized as an internal or external command, operable program or batch file.` error. By not relying on (linux) CLI variable expansion, but expanding the variable to its real path value and using the literal value within the script, the tests can be run on Windows too. --- tests/RulesetTest.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/RulesetTest.php b/tests/RulesetTest.php index fcf16992..0272ca5b 100644 --- a/tests/RulesetTest.php +++ b/tests/RulesetTest.php @@ -67,6 +67,13 @@ class RulesetTest { */ private $ruleset; + /** + * Path to the PHPCS executable. + * + * @var string + */ + private $phpcs_bin = 'phpcs'; + /** * String returned by PHP_CodeSniffer report for an Error. */ @@ -82,17 +89,20 @@ public function __construct( $ruleset, $expected = [] ) { $this->ruleset = $ruleset; $this->expected = $expected; - // Travis support. - if ( false === getenv( 'PHPCS_BIN' ) ) { + // Travis and Windows support. + $phpcs_bin = getenv( 'PHPCS_BIN' ); + if ( false === $phpcs_bin ) { // phpcs:ignore putenv( 'PHPCS_BIN=phpcs' ); + } else { + $this->phpcs_bin = realpath( $phpcs_bin ); } $output = $this->collect_phpcs_result(); if ( ! is_object( $output ) || empty( $output ) ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - printf( 'The PHPCS command checking the ruleset haven\'t returned any issues. Bailing ...' . PHP_EOL ); + printf( 'The PHPCS command checking the ruleset hasn\'t returned any issues. Bailing ...' . PHP_EOL ); exit( 1 ); // Die early, if we don't have any output. } @@ -128,7 +138,7 @@ private function run() { * @return array Returns an associative array with keys of `totals` and `files`. */ private function collect_phpcs_result() { - $shell = sprintf( '$PHPCS_BIN --severity=1 --standard=%1$s --report=json ./%1$s/ruleset-test.inc', $this->ruleset ); + $shell = sprintf( '%1$s --severity=1 --standard=%2$s --report=json ./%2$s/ruleset-test.inc', $this->phpcs_bin, $this->ruleset ); // phpcs:ignore $output = shell_exec( $shell ); From eadda0ad8d68e3078908f3b79fa45ab803dd3a2a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 22 Jul 2020 00:36:41 +0200 Subject: [PATCH 09/35] DeclarationCompatibility: fix incorrect signature check for `Walker::walk()` ... and `Walker::paged_walk()`. The method signature of both the `Walker::walk()` method as well as the `Walker::paged_walk()` method were changed in WordPress 5.3 to make the variadic nature of the allowed arguments explicit. This changes update the sniff to verify the signature of these methods in child classes against the new method signature as it is in WordPress Core. Refs: * https://make.wordpress.org/core/2019/10/09/wp-5-3-introducing-the-spread-operator/ * https://core.trac.wordpress.org/changeset/46442 Fixes 448 --- .../Classes/DeclarationCompatibilitySniff.php | 13 +++++++++++++ .../Classes/DeclarationCompatibilityUnitTest.inc | 11 ++++++++++- .../Classes/DeclarationCompatibilityUnitTest.php | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php b/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php index ca8fd808..ed9874ce 100644 --- a/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php +++ b/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php @@ -148,12 +148,18 @@ class DeclarationCompatibilitySniff extends AbstractScopeSniff { 'walk' => [ 'elements', 'max_depth', + 'args' => [ + 'variable_length' => true, + ], ], 'paged_walk' => [ 'elements', 'max_depth', 'page_num', 'per_page', + 'args' => [ + 'variable_length' => true, + ], ], 'get_number_of_root_elements' => [ 'elements', @@ -276,6 +282,9 @@ protected function processTokenWithinScope( File $phpcsFile, $stackPtr, $currSco ) || ( true === array_key_exists( 'pass_by_reference', $param ) && $param['pass_by_reference'] !== $signatureParams[ $i ]['pass_by_reference'] + ) || ( + true === array_key_exists( 'variable_length', $param ) && + $param['variable_length'] !== $signatureParams[ $i ]['variable_length'] ) ) { $this->addError( $originalParentClassName, $methodName, $signatureParams, $parentSignature, $phpcsFile, $stackPtr ); @@ -331,6 +340,10 @@ private function generateParamList( $methodSignature ) { $paramName .= $param; } + if ( true === array_key_exists( 'variable_length', $options ) && true === $options['variable_length'] ) { + $paramName = '...' . $paramName; + } + if ( true === array_key_exists( 'pass_by_reference', $options ) && true === $options['pass_by_reference'] ) { $paramName = '&' . $paramName; } diff --git a/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.inc b/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.inc index d9955fc3..a7ecaacf 100644 --- a/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.inc @@ -127,4 +127,13 @@ class MyWalker extends Walker { function unset_children( $el, $children_elements ) { } // Bad. $children_elements should be passed by reference -} \ No newline at end of file + + function walk( $elements, $max_depth, ...$args ) { + } // Ok. + + function paged_walk( $elements, $max_depth, $page_num, $per_page ) { + } // Bad. Missing $args. + + function paged_walk( $elements, $max_depth, $page_num, $per_page, $args ) { + } // Bad. $args is not variadic. +} diff --git a/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php b/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php index c0ca7c54..6dc5310d 100644 --- a/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php +++ b/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php @@ -45,6 +45,8 @@ public function getErrorList() { 112 => 1, 119 => 1, 128 => 1, + 134 => 1, + 137 => 1, ]; } From baa18f4c22317662365cc02f7bffc5918d073b7e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 23:12:07 +0200 Subject: [PATCH 10/35] Ruleset test script: fail the build on failing ruleset tests The builds on PHP 5.4, 5.5 and 5.6 should have been failing on the ruleset test for a while now, but aren't. Example: https://travis-ci.org/github/Automattic/VIP-Coding-Standards/jobs/710513865#L311-L315 What is happening here is that when several commands are run via a script, Travis will only look at the exit code of the last script to decide whether the build should be failed or not. This means that failures from the `WordPressVIPMinimum` ruleset test were never failing the build as they were hidden by a passing ruleset test for the `WordPress-VIP-Go` ruleset. By chaining the commands together, the exit codes of both commands are taken into account when determining whether the build should be failed or not. --- bin/ruleset-tests | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/ruleset-tests b/bin/ruleset-tests index 2da29def..6f0f5aa9 100755 --- a/bin/ruleset-tests +++ b/bin/ruleset-tests @@ -17,5 +17,4 @@ PHPCS_BIN="$(pwd)/vendor/bin/phpcs" export PHPCS_BIN -php ./WordPressVIPMinimum/ruleset-test.php -php ./WordPress-VIP-Go/ruleset-test.php +php ./WordPressVIPMinimum/ruleset-test.php && php ./WordPress-VIP-Go/ruleset-test.php From 1a421d49deb149e9f0caaf5eac98286f0a550d47 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 23:26:52 +0200 Subject: [PATCH 11/35] WordPressVIPMinimum: fix the failing ruleset test Ok, this is a fun one. Line 5 of the ruleset-test is not supposed to error. It is just setting up the variables for the VariableAnalysis test. Line 7, however, is supposed to error on a PHP parse error (`Generic.PHP.Syntax`). The above is true and working for PHP 7. However on PHP 5, line 7 will not throw a parse error, while line 5 actually will - `Cannot re-assign $this`. To fix this, I've: * Replaced the `$this` variable assignment on line 5 with an assignment to `$stdClass`. * Replaced the PHP 7 parse error on line 7 with a parse error which will error on all currently known PHP versions. Fun times ;-) --- WordPressVIPMinimum/ruleset-test.inc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPressVIPMinimum/ruleset-test.inc b/WordPressVIPMinimum/ruleset-test.inc index 56df28dc..78d46ea9 100644 --- a/WordPressVIPMinimum/ruleset-test.inc +++ b/WordPressVIPMinimum/ruleset-test.inc @@ -2,9 +2,9 @@ endpoint, array( +wp_remote_post( $stdClass->endpoint, array( 'method' => 'POST', 'timeout' => 45, // Error. 'httpversion' => '1.1', 'blocking' => false, - 'body' => wp_json_encode( $this->logs, JSON_UNESCAPED_SLASHES ), + 'body' => wp_json_encode( $stdClass->logs, JSON_UNESCAPED_SLASHES ), ) ); From 4aed540d928aae6030042142b57636ebfddd0268 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jul 2020 23:39:21 +0200 Subject: [PATCH 12/35] RulesetTest: fix the test script to be able to handle 0 values Turns out the test script was not set up to be able to deal with `0` values and would throw a very informative "_Expected 0 errors, found 0 on line 7._" error in such a case. Fixed now. --- tests/RulesetTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/RulesetTest.php b/tests/RulesetTest.php index 0272ca5b..bf21dd7c 100644 --- a/tests/RulesetTest.php +++ b/tests/RulesetTest.php @@ -230,6 +230,10 @@ private function check_missing_expected_values() { } foreach ( $lines as $line_number => $expected_count_of_type_violations ) { + if ( 0 === $expected_count_of_type_violations ) { + continue; + } + if ( ! isset( $this->{$type}[ $line_number ] ) ) { $this->error_warning_message( $expected_count_of_type_violations, $type, 0, $line_number ); } elseif ( $this->{$type}[ $line_number ] !== $expected_count_of_type_violations ) { @@ -247,6 +251,10 @@ private function check_missing_expected_values() { private function check_unexpected_values() { foreach ( [ 'errors', 'warnings' ] as $type ) { foreach ( $this->$type as $line_number => $actual_count_of_type_violations ) { + if ( 0 === $actual_count_of_type_violations ) { + continue; + } + if ( ! isset( $this->expected[ $type ][ $line_number ] ) ) { $this->error_warning_message( 0, $type, $actual_count_of_type_violations, $line_number ); } elseif ( $actual_count_of_type_violations !== $this->expected[ $type ][ $line_number ] ) { From bea4a24ea5a8ec1ead81d7284199f8e0b69f857c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 22 Jul 2020 02:08:22 +0200 Subject: [PATCH 13/35] RulesetTest: don't use the system default version of PHP ... instead use the PHP version used when this script was called. `shell_exec()` opens a new process and that process does not inherit the PHP executable which was used to run the tests, but uses the system default PHP version instead, which means that the PHPCS command may run on a different PHP version than the tests. The current solution is a simple one and not exhaustive, but should suffice in most cases. If a more complex/more comprehensive solution is desired, I'd recommend using the `PhpExecutableFinder` from the `Symfony\Process` package. --- tests/RulesetTest.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/RulesetTest.php b/tests/RulesetTest.php index bf21dd7c..5f45d372 100644 --- a/tests/RulesetTest.php +++ b/tests/RulesetTest.php @@ -138,7 +138,17 @@ private function run() { * @return array Returns an associative array with keys of `totals` and `files`. */ private function collect_phpcs_result() { - $shell = sprintf( '%1$s --severity=1 --standard=%2$s --report=json ./%2$s/ruleset-test.inc', $this->phpcs_bin, $this->ruleset ); + $php = ''; + if ( \PHP_BINARY && in_array( \PHP_SAPI, [ 'cgi-fcgi', 'cli', 'cli-server', 'phpdbg' ], true ) ) { + $php = \PHP_BINARY . ' '; + } + + $shell = sprintf( + '%1$s%2$s --severity=1 --standard=%3$s --report=json ./%3$s/ruleset-test.inc', + $php, // Current PHP executable if avaiable. + $this->phpcs_bin, + $this->ruleset + ); // phpcs:ignore $output = shell_exec( $shell ); From 1634ae298791e2cbf4a228a5738c911a80af5f53 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 22 Jul 2020 02:31:37 +0200 Subject: [PATCH 14/35] Ruleset Tests: revert 485 and fix it In 485, three tests were commented out because they seemed to break the ruleset tests. At the request of Gary, I've had a look see to try and find the underlying cause. Turned out to be a combination of three things: 1. A new warning having been introduced in PHP 7.4 about using array access on non-arrays. 2. The code in the test case file being incomplete/incorrect - required parameters for function calls were missing. 3. The WPCS `EscapeOutput` not having enough defensive coding for when a faulty function call without parameters would be encountered. Obviously we can't do anything about 1. As for 3, I've opened a PR in WPCS upstream to fix this, but that fix won't be available to VIP until WPCS 3.0.0 has been released and VIPCS upgrades. See: WordPress/WordPress-Coding-Standards 1939 So, in the mean time, let's make sure the function calls in the test case file which aren't intended to trigger the `EscapeOutput` sniff, don't trigger it. And that's what's done in this PR. --- To reproduce my findings / How to investigate this in the future: * Make sure you are set up to use PHP 7.4.x (or whatever other PHP version where the issue was first seen). * Run `phpcs -ps --severity=1 --standard=WordPressVIPMinimum ./WordPressVIPMinimum/ruleset-test.inc` * Take note of the missing errors/warnings. * Scroll to the top of the full report and see the cause: ``` 1 | ERROR | An error occurred during processing; checking has been aborted. The error message was: Trying to access array offset on value of type bool | | in path/to/WordPress/Sniffs/Security/EscapeOutputSniff.php on line 198 (Internal.Exception) ``` --- WordPress-VIP-Go/ruleset-test.inc | 2 +- WordPress-VIP-Go/ruleset-test.php | 2 +- WordPressVIPMinimum/ruleset-test.inc | 4 ++-- WordPressVIPMinimum/ruleset-test.php | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress-VIP-Go/ruleset-test.inc b/WordPress-VIP-Go/ruleset-test.inc index af1e610c..749f112b 100644 --- a/WordPress-VIP-Go/ruleset-test.inc +++ b/WordPress-VIP-Go/ruleset-test.inc @@ -510,7 +510,7 @@ $query_args = array( // WordPressVIPMinimum.Security.EscapingVoidReturnFunctions.Found esc_js( _deprecated_argument() ); // Error. esc_js( _deprecated_constructor() ); // Error. -// esc_js( _deprecated_file() ); // Error. +esc_js( _deprecated_file( 'filename' ) ); // Error. esc_js( _deprecated_function() ); // Error. esc_js( _deprecated_hook() ); // Error. esc_js( _doing_it_wrong() ); // Error. diff --git a/WordPress-VIP-Go/ruleset-test.php b/WordPress-VIP-Go/ruleset-test.php index 1bf4ec7c..d15f245e 100644 --- a/WordPress-VIP-Go/ruleset-test.php +++ b/WordPress-VIP-Go/ruleset-test.php @@ -98,7 +98,7 @@ 507 => 1, 511 => 1, 512 => 1, - // 513 => 1, + 513 => 1, 514 => 1, 515 => 1, 516 => 1, diff --git a/WordPressVIPMinimum/ruleset-test.inc b/WordPressVIPMinimum/ruleset-test.inc index 78d46ea9..e679d69e 100644 --- a/WordPressVIPMinimum/ruleset-test.inc +++ b/WordPressVIPMinimum/ruleset-test.inc @@ -180,7 +180,7 @@ $output = shell_exec( 'ls -lart' ); // Error. var_dump(); // Warning. var_export(); // Warning. print_r(); // Warning. -// trigger_error(); // Warning. +trigger_error( 'message' ); // Warning. set_error_handler(); // Warning. debug_backtrace(); // Warning. debug_print_backtrace(); // Warning. @@ -508,7 +508,7 @@ $query_args = array( // WordPressVIPMinimum.Security.EscapingVoidReturnFunctions.Found esc_js( _deprecated_argument() ); // Error. esc_js( _deprecated_constructor() ); // Error. -// esc_js( _deprecated_file() ); // Error. +esc_js( _deprecated_file( 'filename' ) ); // Error. esc_js( _deprecated_function() ); // Error. esc_js( _deprecated_hook() ); // Error. esc_js( _doing_it_wrong() ); // Error. diff --git a/WordPressVIPMinimum/ruleset-test.php b/WordPressVIPMinimum/ruleset-test.php index 2e8c7b99..4c9f073e 100644 --- a/WordPressVIPMinimum/ruleset-test.php +++ b/WordPressVIPMinimum/ruleset-test.php @@ -177,7 +177,7 @@ 505 => 1, 509 => 1, 510 => 1, - // 511 => 1, + 511 => 1, 512 => 1, 513 => 1, 514 => 1, @@ -235,7 +235,7 @@ 180 => 1, 181 => 1, 182 => 1, - // 183 => 1, + 183 => 1, 184 => 1, 185 => 1, 186 => 1, From 3e030664ddc1ac38d1a1ed88b1877ea992d0404f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jul 2020 22:23:17 +0200 Subject: [PATCH 15/35] Variables/RestrictedVariables: fix namespace of unit test file --- .../Tests/Variables/RestrictedVariablesUnitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php index eaba9c0c..414349f5 100644 --- a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php +++ b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php @@ -5,7 +5,7 @@ * @package VIPCS\WordPressVIPMinimum */ -namespace WordPress\Tests\Variables; +namespace WordPressVIPMinimum\Tests\Variables; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; From 270045db6fe8a4e6f94b7b291683151b43c51003 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 22 Jul 2020 03:13:42 +0200 Subject: [PATCH 16/35] Contributing: remove duplicate info Oops... that line isn't needed anymore. --- .github/CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6d3bff7b..cae4b7ef 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -25,7 +25,6 @@ Sniffname starts with | Report to `VariableAnalysis` | [VariableAnalysis](https://github.com/sirbrillig/phpcs-variable-analysis/issues/) `WordPress` | [WordPressCS](https://github.com/WordPress/WordPress-Coding-Standards/issues/) `WordPressVIPMinimum` | [VIPCS](https://github.com/Automattic/VIP-Coding-Standards/issues/) (this repo) -`Generic`, `PSR2` or `Squiz` | [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer/issues/) ---- From bc780bb9ef37c5980140a4bf7278750388773527 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jul 2020 22:39:17 +0200 Subject: [PATCH 17/35] Variables/RestrictedVariables: fix the test Now the test is actually running under the proper namespace, it comes to light that the test for the `exclude` property is not working as it is using an outdated syntax. Fixed now. --- .../Tests/Variables/RestrictedVariablesUnitTest.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc index 61c4a5b2..8918d631 100644 --- a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc @@ -28,10 +28,10 @@ $phrase = << Date: Mon, 27 Jul 2020 20:33:05 +0200 Subject: [PATCH 18/35] Test bootstrap: various minor tweaks * Remove some code duplication by using an interim variable. * Check that the PHPCS native bootstrap file can be found. * Remove the question about using PHPCS 3.x. That's not in question anymore. * Fix the link to the contributing.md file - this was now pointing to the WPCS one. * Set the `PHPCS_IGNORE_TESTS` environment variable automatically to the correct value to prevent running tests from other standards. --- tests/bootstrap.php | 46 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 9257de94..1e18c0c2 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -13,24 +13,29 @@ * @license gpl-2.0-or-later */ -if ( ! \defined( 'PHP_CODESNIFFER_IN_TESTS' ) ) { +if ( ! defined( 'PHP_CODESNIFFER_IN_TESTS' ) ) { define( 'PHP_CODESNIFFER_IN_TESTS', true ); } $ds = DIRECTORY_SEPARATOR; // Get the PHPCS dir from an environment variable. -$phpcsDir = getenv( 'PHPCS_DIR' ); +$phpcsDir = getenv( 'PHPCS_DIR' ); +$composerPHPCSPath = dirname( __DIR__ ) . $ds . 'vendor' . $ds . 'squizlabs' . $ds . 'php_codesniffer'; // This may be a Composer install. -if ( false === $phpcsDir && is_dir( dirname( __DIR__ ) . $ds . 'vendor' . $ds . 'squizlabs' . $ds . 'php_codesniffer' ) ) { - $phpcsDir = dirname( __DIR__ ) . $ds . 'vendor' . $ds . 'squizlabs' . $ds . 'php_codesniffer'; +if ( false === $phpcsDir && is_dir( $composerPHPCSPath ) ) { + $phpcsDir = $composerPHPCSPath; } elseif ( false !== $phpcsDir ) { + // PHPCS in a custom directory. $phpcsDir = realpath( $phpcsDir ); } // Try and load the PHPCS autoloader. -if ( false !== $phpcsDir && file_exists( $phpcsDir . $ds . 'autoload.php' ) ) { +if ( false !== $phpcsDir + && file_exists( $phpcsDir . $ds . 'autoload.php' ) + && file_exists( $phpcsDir . $ds . 'tests' . $ds . 'bootstrap.php' ) +) { require_once $phpcsDir . $ds . 'autoload.php'; /* @@ -39,17 +44,42 @@ */ require_once $phpcsDir . $ds . 'tests' . $ds . 'bootstrap.php'; } else { - echo 'Uh oh... can\'t find PHPCS. Are you sure you are using PHPCS 3.x ? + echo 'Uh oh... can\'t find PHPCS. If you use Composer, please run `composer install`. Otherwise, make sure you set a `PHPCS_DIR` environment variable in your phpunit.xml file pointing to the PHPCS directory. Please read the contributors guidelines for more information: -https://is.gd/contributing2WPCS +https://github.com/Automattic/VIP-Coding-Standards/blob/develop/.github/CONTRIBUTING.md '; die( 1 ); } -unset( $ds, $phpcsDir ); +/* + * Set the PHPCS_IGNORE_TEST environment variable to ignore tests from other standards. + */ +$vipcsStandards = [ + 'WordPressVIPMinimum' => true, +]; + +$allStandards = PHP_CodeSniffer\Util\Standards::getInstalledStandards(); +$allStandards[] = 'Generic'; + +$standardsToIgnore = []; +foreach ( $allStandards as $standard ) { + if ( isset( $vipcsStandards[ $standard ] ) === true ) { + continue; + } + + $standardsToIgnore[] = $standard; +} + +$standardsToIgnoreString = implode( ',', $standardsToIgnore ); + +// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_putenv -- This is test code, not production. +putenv( "PHPCS_IGNORE_TESTS={$standardsToIgnoreString}" ); + +// Clean up. +unset( $ds, $phpcsDir, $composerPHPCSPath, $allStandards, $standardsToIgnore, $standard, $standardsToIgnoreString ); From 35068c07c09c128dde1e5622ec3b42d1989b7b8b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jul 2020 23:43:11 +0200 Subject: [PATCH 19/35] Functions/RestrictedFunctions: fix false positive on class instantiation Quick fix for false positives on class instantiation. First new unit test was already ok, second unit test would previously fail. Fixes 469 --- .../Sniffs/Functions/RestrictedFunctionsSniff.php | 1 + .../Tests/Functions/RestrictedFunctionsUnitTest.inc | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php index 164021cf..38c9d60c 100644 --- a/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php @@ -398,6 +398,7 @@ public function is_targetted_token( $stackPtr ) { \T_AS => \T_AS, // Use declaration alias. \T_DOUBLE_COLON => \T_DOUBLE_COLON, \T_OBJECT_OPERATOR => \T_OBJECT_OPERATOR, + \T_NEW => \T_NEW, ]; if ( isset( $skipped[ $this->tokens[ $prev ]['code'] ] ) ) { return false; diff --git a/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc b/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc index 9b778b40..07ec748c 100644 --- a/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc @@ -226,4 +226,7 @@ wpcom_vip_get_page_by_path(); // Ok - VIP recommended version of get_page_by_pat get_page_by_path( $page_path ); // Warning. $popular = stats_get_csv( 'postviews', [ 'days' => 2, 'limit' => 20 ] ); // Error. -$popular = custom_stats_get_csv( 'postviews', [ 'days' => 2, 'limit' => 20 ] ); // Ok. \ No newline at end of file +$popular = custom_stats_get_csv( 'postviews', [ 'days' => 2, 'limit' => 20 ] ); // Ok. + +$foo = new Link; // OK, class, not function. +$foo = new Mail(); // OK, class, not function. From 060fcf17672a14a3d58fb47ea853175bd9845f17 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 28 Jul 2020 01:01:06 +0200 Subject: [PATCH 20/35] Hooks/AlwaysReturnInFilter: add support for hook-ins using short arrays As VIPCS is currently using WPCS 2.x, we can use the WPCS `Sniff::find_array_open_close()` method to get the opener/closer for an array independently of the type of array (long/short). Once VIPCS implements PHPCSUtils, this method call should be swopped out for the PHPCSUtils `Arrays::getOpenClose()` method. Addresses #358 for the `AlwaysReturnInFilter` sniff. Includes unit tests. --- .../Hooks/AlwaysReturnInFilterSniff.php | 11 ++++-- .../Hooks/AlwaysReturnInFilterUnitTest.inc | 35 +++++++++++++++++++ .../Hooks/AlwaysReturnInFilterUnitTest.php | 1 + 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php b/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php index 1a10945d..357b7c2d 100644 --- a/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php +++ b/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php @@ -78,7 +78,9 @@ public function process_token( $stackPtr ) { if ( 'PHPCS_T_CLOSURE' === $this->tokens[ $callbackPtr ]['code'] ) { $this->processFunctionBody( $callbackPtr ); - } elseif ( 'T_ARRAY' === $this->tokens[ $callbackPtr ]['type'] ) { + } elseif ( T_ARRAY === $this->tokens[ $callbackPtr ]['code'] + || T_OPEN_SHORT_ARRAY === $this->tokens[ $callbackPtr ]['code'] + ) { $this->processArray( $callbackPtr ); } elseif ( true === in_array( $this->tokens[ $callbackPtr ]['code'], Tokens::$stringTokens, true ) ) { $this->processString( $callbackPtr ); @@ -92,9 +94,14 @@ public function process_token( $stackPtr ) { */ private function processArray( $stackPtr ) { + $open_close = $this->find_array_open_close( $stackPtr ); + if ( false === $open_close ) { + return; + } + $previous = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, - $this->tokens[ $stackPtr ]['parenthesis_closer'] - 1, + $open_close['closer'] - 1, null, true ); diff --git a/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.inc b/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.inc index 591e233d..4f9d6d00 100644 --- a/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.inc @@ -137,3 +137,38 @@ function bad_example_arg( $test ) { // Error. // Missing universal return. } add_filter( 'bad_example_filter', 'bad_example_arg' ); + +class good_example_class_short_array { // Ok. + public function __construct() { + add_filter( 'good_example_class_filter', [ $this, 'class_filter' ] ); + } + + public function class_filter( $param ) { + if ( 1 === 1 ) { + if ( 1 === 0 ) { + return 'whoops'; + } else { + return 'here!'; + } + } + return 'This is Okay'; + } +} + +class bad_example_class_short_array { // Error. + public function __construct() { + add_filter( 'bad_example_class_filter', [ $this, 'class_filter' ] ); + } + + public function class_filter( $param ) { + if ( 1 === 1 ) { + if ( 1 === 0 ) { + return 'whoops'; + } else { + return 'here!'; + } + } + // Missing universal return. + } +} + diff --git a/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php b/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php index 41339fa6..ee2cd6c8 100644 --- a/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php +++ b/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php @@ -28,6 +28,7 @@ public function getErrorList() { 95 => 1, 105 => 1, 129 => 1, + 163 => 1, ]; } From b61a257e2d58671764ae60c8ff8b49fb7d374888 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 28 Jul 2020 12:20:48 +0200 Subject: [PATCH 21/35] RestrictedFunctions: fix false negative - functions in `config_settings` would never match The functions in the `config_settings` group were using a unicode `_`, not the ascii `_`, so these would never match the PHP native `opcache_*` functions they were intended to match. As the same unicode character was used in the applicable unit tests and ruleset tests, the bug was never reported as a test failure. --- WordPress-VIP-Go/ruleset-test.inc | 6 +++--- .../Sniffs/Functions/RestrictedFunctionsSniff.php | 6 +++--- .../Tests/Functions/RestrictedFunctionsUnitTest.inc | 10 +++++----- WordPressVIPMinimum/ruleset-test.inc | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/WordPress-VIP-Go/ruleset-test.inc b/WordPress-VIP-Go/ruleset-test.inc index 749f112b..d1d1445c 100644 --- a/WordPress-VIP-Go/ruleset-test.inc +++ b/WordPress-VIP-Go/ruleset-test.inc @@ -350,9 +350,9 @@ wp_cache_get_multi(); // Error. opcache_reset(); // Error. opcache_invalidate( 'test_script.php' ); // Error. opcache_compile_file( $var ); // Error. -opcache_​is_​script_​cached( 'test_script.php' ); // Error. -opcache_​get_​status(); // Error. -opcache_​get_​configuration(); // Error. +opcache_is_script_cached( 'test_script.php' ); // Error. +opcache_get_status(); // Error. +opcache_get_configuration(); // Error. get_super_admins(); // OK. wpcom_vip_irc(); // Error. flush_rewrite_rules(); // Error. diff --git a/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php index 38c9d60c..888b17ca 100644 --- a/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php @@ -45,9 +45,9 @@ public function getGroups() { 'type' => 'error', 'message' => '`%s` is not recommended for use on the WordPress VIP platform due to potential setting changes.', 'functions' => [ - 'opcache_​is_​script_​cached', - 'opcache_​get_​status', - 'opcache_​get_​configuration', + 'opcache_is_script_cached', + 'opcache_get_status', + 'opcache_get_configuration', ], ], 'get_super_admins' => [ diff --git a/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc b/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc index 07ec748c..7c1ba946 100644 --- a/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc @@ -21,17 +21,17 @@ wp_cache_get_multi(); // Error. opcache_resets(); // Ok - similarly-named custom function to opcache_reset(). opcach_invalidate ( $test_script ); // Ok - similarly-named custom function to opcache_invalidate(). opcache_compil_file(); // Ok - similarly-named custom function to opcache_compile_file(). -okcache_is_​script_​cached( 'test_script.php' ); // Ok - similarly-named custom function to opcache_is_script_cached(). +okcache_is_script_cached( 'test_script.php' ); // Ok - similarly-named custom function to opcache_is_script_cached(). foo_opcache_get_status( $test_script ); // Ok - similarly-named custom function to opcache_get_status(). opcache_get_config( $test_script ); // Ok - similary-named custom function to opcache_get_configuration(). opcache_reset(); // Error. opcache_invalidate( 'test_script.php' ); // Error - one parameter. opcache_invalidate( $test_script, true ); // Error - two parameters. opcache_compile_file( $test_script ); // Error - one parameter. -opcache_​is_​script_​cached( 'test_script.php' ); // Error - one parameter. -opcache_​get_​status(); // Error. -opcache_​get_​status( false ); // Error. -opcache_​get_​configuration(); // Error. +opcache_is_script_cached( 'test_script.php' ); // Error - one parameter. +opcache_get_status(); // Error. +opcache_get_status( false ); // Error. +opcache_get_configuration(); // Error. get_super_admin(); // Ok - similarly-named function to get_super_admins(). get_super_admins(); // Error. diff --git a/WordPressVIPMinimum/ruleset-test.inc b/WordPressVIPMinimum/ruleset-test.inc index e679d69e..9953d432 100644 --- a/WordPressVIPMinimum/ruleset-test.inc +++ b/WordPressVIPMinimum/ruleset-test.inc @@ -312,9 +312,9 @@ wp_cache_get_multi(); // Error. opcache_reset(); // Error. opcache_invalidate( 'test_script.php' ); // Error. opcache_compile_file( $var ); // Error. -opcache_​is_​script_​cached( 'test_script.php' ); // Error. -opcache_​get_​status(); // Error. -opcache_​get_​configuration(); // Error. +opcache_is_script_cached( 'test_script.php' ); // Error. +opcache_get_status(); // Error. +opcache_get_configuration(); // Error. get_super_admins(); // Error. wpcom_vip_irc(); // Error. flush_rewrite_rules(); // Error. From 46895e99bcbf88369a9e7705fea60fde94a48d43 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 28 Jul 2020 05:00:32 +0200 Subject: [PATCH 22/35] PreGetPosts: improve the isEarlyMainQueryCheck() method [1] This adds a unit test which results in the error as reported in issue 499 and fixes the error properly. The error was caused by the presumption in the code that if an a check for `is_main_query` has a scope condition which is a `closure`, that the `closure` is the callback in the hook function call and that therefore the outer parenthesis (those of the function call) should be disgarded and the next parenthesis will be the ones for the `if` statement which will always have a scope opener and closer. Now read the above sentence again and count the number of assumptions in that statement ;-) Either way, the fix I've now added should stabilize this part of the code. Fixes 499 --- .../Sniffs/Hooks/PreGetPostsSniff.php | 21 ++++++++++++++++--- .../Tests/Hooks/PreGetPostsUnitTest.inc | 16 ++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php index 8beca64f..a2df7603 100644 --- a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php @@ -304,9 +304,24 @@ private function isEarlyMainQueryCheck( $stackPtr ) { return false; } - $nestedParenthesisEnd = array_shift( $this->tokens[ $stackPtr ]['nested_parenthesis'] ); - if ( true === in_array( 'PHPCS_T_CLOSURE', $this->tokens[ $stackPtr ]['conditions'], true ) ) { - $nestedParenthesisEnd = array_shift( $this->tokens[ $stackPtr ]['nested_parenthesis'] ); + $parentheses = $this->tokens[ $stackPtr ]['nested_parenthesis']; + do { + $nestedParenthesisEnd = array_shift( $parentheses ); + if ( null === $nestedParenthesisEnd ) { + // Nothing left in the array. No parenthesis found with a non-closure owner. + return false; + } + + if ( isset( $this->tokens[ $nestedParenthesisEnd ]['parenthesis_owner'] ) + && T_CLOSURE !== $this->tokens[ $this->tokens[ $nestedParenthesisEnd ]['parenthesis_owner'] ]['code'] + ) { + break; + } + } while ( true ); + + $owner = $this->tokens[ $nestedParenthesisEnd ]['parenthesis_owner']; + if ( isset( $this->tokens[ $owner ]['scope_opener'], $this->tokens[ $owner ]['scope_closer'] ) === false ) { + return false; } $next = $this->phpcsFile->findNext( diff --git a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc index 6ff848b1..f0ebf896 100644 --- a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc @@ -90,3 +90,19 @@ add_action( 'pre_get_posts', function( $wp_query ) { } } ); + +class undefined_index_issue_499 { + + public function __construct() { + add_action( 'pre_get_posts', array( $this, 'pre_get_posts_499' ) ); + } + + public function pre_get_posts_499( $wp_query ) { + + if ( function() { return ( $wp_query->is_main_query() === false ) }() === false ) { + return; + } + + $wp_query->set( 'cat', '-5' ); + } +} From 82d1232802600919e47af8f5a7094e7c1dde154d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 28 Jul 2020 05:00:32 +0200 Subject: [PATCH 23/35] PreGetPosts: improve the isEarlyMainQueryCheck() method [2] This adds a second unit test which is based on the actual code which originally triggered the error. The error was caused by the code in question using inline control structures (without braces) for the early main query check. After the previous fix, that code would now throw a false positive. I've fixed this now by adding an additional check for a `return` statement straight after the parenthesis closer of the `if()` statement. Fixes 499 --- .../Sniffs/Hooks/PreGetPostsSniff.php | 12 ++++++++++++ .../Tests/Hooks/PreGetPostsUnitTest.inc | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php index a2df7603..655bbdae 100644 --- a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php @@ -321,6 +321,18 @@ private function isEarlyMainQueryCheck( $stackPtr ) { $owner = $this->tokens[ $nestedParenthesisEnd ]['parenthesis_owner']; if ( isset( $this->tokens[ $owner ]['scope_opener'], $this->tokens[ $owner ]['scope_closer'] ) === false ) { + // This may be an inline control structure (no braces). + $next = $this->phpcsFile->findNext( + Tokens::$emptyTokens, + ( $nestedParenthesisEnd + 1 ), + null, + true + ); + + if ( false !== $next && T_RETURN === $this->tokens[ $next ]['code'] ) { + return true; + } + return false; } diff --git a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc index f0ebf896..09c5f06e 100644 --- a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc @@ -106,3 +106,13 @@ class undefined_index_issue_499 { $wp_query->set( 'cat', '-5' ); } } + +add_action('pre_get_posts', 'inline_control_structures', 10, 1); + +function inline_control_structures( $query ) { + if( !$query->is_main_query() && !is_front_page()) return; + if(is_single() || is_search() || is_archive()) return; + + $query->set('meta_query', 'foo'); + return $query; +} From 6b6cf1087921bb2376e626f656597f843eceeee1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 28 Jul 2020 02:48:37 +0200 Subject: [PATCH 24/35] Hooks/PreGetPosts: add support for hook-ins using short arrays As VIPCS is currently using WPCS 2.x, we can use the WPCS `Sniff::find_array_open_close()` method to get the opener/closer for an array independently of the type of array (long/short). Once VIPCS implements PHPCSUtils, this method call should be swopped out for the PHPCSUtils `Arrays::getOpenClose()` method. Addresses #358 for the `PreGetPosts` sniff. Includes unit tests. --- .../Sniffs/Hooks/PreGetPostsSniff.php | 11 +++++-- .../Tests/Hooks/PreGetPostsUnitTest.inc | 30 +++++++++++++++++++ .../Tests/Hooks/PreGetPostsUnitTest.php | 16 +++++----- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php index 655bbdae..cd2c8867 100644 --- a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php @@ -79,7 +79,9 @@ public function process_token( $stackPtr ) { if ( 'PHPCS_T_CLOSURE' === $this->tokens[ $callbackPtr ]['code'] ) { $this->processClosure( $callbackPtr ); - } elseif ( 'T_ARRAY' === $this->tokens[ $callbackPtr ]['type'] ) { + } elseif ( T_ARRAY === $this->tokens[ $callbackPtr ]['code'] + || T_OPEN_SHORT_ARRAY === $this->tokens[ $callbackPtr ]['code'] + ) { $this->processArray( $callbackPtr ); } elseif ( true === in_array( $this->tokens[ $callbackPtr ]['code'], Tokens::$stringTokens, true ) ) { $this->processString( $callbackPtr ); @@ -93,9 +95,14 @@ public function process_token( $stackPtr ) { */ private function processArray( $stackPtr ) { + $open_close = $this->find_array_open_close( $stackPtr ); + if ( false === $open_close ) { + return; + } + $previous = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, - $this->tokens[ $stackPtr ]['parenthesis_closer'] - 1, + $open_close['closer'] - 1, null, true ); diff --git a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc index 09c5f06e..5cb8c0d4 100644 --- a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.inc @@ -116,3 +116,33 @@ function inline_control_structures( $query ) { $query->set('meta_query', 'foo'); return $query; } + +class short_array_hook_in { + + public function __construct() { + add_action( 'pre_get_posts', [ $this, 'short_pre_get_posts' ] ); + } + + public function short_pre_get_posts( $wp_query ) { + + $wp_query->set( 'cat', '-5' ); + + if ( $wp_query->is_main_query() ) { + $wp_query->set( 'cat', '-5' ); + } else if ( $wp_query->is_search() ) { + $wp_query->set( 'cat', '-5' ); + } + + if ( ( ! $wp_query->is_main_query() ) ) { + return; + } + + $wp_query->set( 'cat', '-5' ); + + if ( $wp_query->is_main_query() ) { + $wp_query->set( 'cat', '-5' ); + } else if ( $wp_query->is_search() ) { + $wp_query->set( 'cat', '-5' ); + } + } +} diff --git a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php index 058f2d6b..02e45189 100644 --- a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php @@ -32,13 +32,15 @@ public function getErrorList() { */ public function getWarningList() { return [ - 8 => 1, - 11 => 1, - 29 => 1, - 32 => 1, - 52 => 1, - 57 => 1, - 87 => 1, + 8 => 1, + 11 => 1, + 29 => 1, + 32 => 1, + 52 => 1, + 57 => 1, + 87 => 1, + 128 => 1, + 133 => 1, ]; } From b54105fe59714e0af40e7758cd2bbc1ffc8b64d0 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 29 Jul 2020 13:35:07 +0200 Subject: [PATCH 25/35] RestrictedVariables: don't report on "use" in `isset()` Disregard when the existence of a restricted variable is being checked. This uses the upstream WPCS `Sniff::is_in_isset_or_empty()` method. This means that variables will not be reported as "used" when they are wrapped in a call to: * `isset()` * `empty()` * `array_key_exists()` This also means that the `if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {` test on line 13 will no longer report a warning. As `$_SERVER['REMOTE_ADDR']` was then no longer tested for and `$_SERVER['HTTP_USER_AGENT']` was being tested twice (line 14 and line 28), I've changed the occurrence on line 14 to use `$_SERVER['REMOTE_ADDR']` to make sure both are still tested. Includes additional unit test for the case as reported by the op. Fixes 568 --- WordPress-VIP-Go/ruleset-test.inc | 2 +- .../Sniffs/AbstractVariableRestrictionsSniff.php | 5 +++++ .../Tests/Variables/RestrictedVariablesUnitTest.inc | 8 ++++++-- .../Tests/Variables/RestrictedVariablesUnitTest.php | 1 - 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/WordPress-VIP-Go/ruleset-test.inc b/WordPress-VIP-Go/ruleset-test.inc index d1d1445c..4706542e 100644 --- a/WordPress-VIP-Go/ruleset-test.inc +++ b/WordPress-VIP-Go/ruleset-test.inc @@ -53,7 +53,7 @@ setcookie( 'cookie[three]', 'cookiethree' ); // Error + Message. $x = sanitize_key( $_COOKIE['bar'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Error + Message. // WordPressVIPMinimum.Variables.RestrictedVariables.cache_constraints___SERVER__HTTP_USER_AGENT__ -if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) { // Error + Message. +if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'some_value' ) { // Error + Message. } // WordPress.WP.AlternativeFunctions.file_system_read_fclose diff --git a/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php b/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php index bc5e7a46..b4a77874 100644 --- a/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php @@ -143,6 +143,11 @@ public function process_token( $stackPtr ) { } } + if ( $this->is_in_isset_or_empty( $stackPtr ) === true ) { + // Checking whether a variable exists is not the same as using it. + return; + } + foreach ( $this->groups_cache as $groupName => $group ) { if ( isset( $this->excluded_groups[ $groupName ] ) ) { diff --git a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc index 8918d631..2126a037 100644 --- a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc @@ -10,8 +10,8 @@ $wp_db->update( $wpdb->usermeta, array( 'meta_value' => 'bar!' ), array( 'user_i $query = "SELECT * FROM $wpdb->posts"; // Ok. -if ( isset( $_SERVER['REMOTE_ADDR'] ) ) { // Warning. - foo( $_SERVER['HTTP_USER_AGENT'] ); // Warning. +if ( isset( $_SERVER['REMOTE_ADDR'] ) ) { // OK. + foo( $_SERVER['REMOTE_ADDR'] ); // Warning. } $x = $_COOKIE['bar']; // Warning. @@ -35,3 +35,7 @@ $query = "SELECT * FROM $wpdb->usermeta"; // Ok, excluded. foo( $_SESSION ); // Error. foo( $_SESSION['bar'] ); // Error. + +if ( isset( $_SESSION ) ) { // OK. + $cache = false; +} diff --git a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php index 414349f5..37ef4079 100644 --- a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php +++ b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php @@ -43,7 +43,6 @@ public function getErrorList() { */ public function getWarningList() { return [ - 13 => 1, 14 => 1, 17 => 1, 28 => 1, From cbf152583c7535794083a14bc3cccdc5288f9d77 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 30 Jul 2020 04:52:06 +0200 Subject: [PATCH 26/35] PHPCS ruleset: forbid yoda conditions in VIPCS codebase In contrast to WPCS, disallow the use of Yoda conditions. --- .phpcs.xml.dist | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 61d8926f..01fc5ff9 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -17,6 +17,7 @@ + @@ -32,9 +33,12 @@ - + + + + From fe6ccecf033c4d987302980fc0ab04d22e553d35 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 30 Jul 2020 05:22:23 +0200 Subject: [PATCH 27/35] CS: change yoda conditions to non-yoda Fixes made with the auto-fixer available in the Slevomat standard via the `SlevomatCodingStandard.ControlStructures.DisallowYodaComparison` sniff and visually reviewed. --- .../AbstractVariableRestrictionsSniff.php | 10 ++-- .../Classes/DeclarationCompatibilitySniff.php | 36 ++++++------ .../Classes/RestrictedExtendClassesSniff.php | 2 +- .../Sniffs/Compatibility/ZoninatorSniff.php | 12 ++-- .../Sniffs/Constants/ConstantStringSniff.php | 8 +-- .../Constants/RestrictedConstantsSniff.php | 18 +++--- .../Sniffs/Files/IncludingFileSniff.php | 22 ++++---- .../Sniffs/Files/IncludingNonPHPFileSniff.php | 10 ++-- .../Functions/CheckReturnValueSniff.php | 36 ++++++------ .../Sniffs/Functions/DynamicCallsSniff.php | 24 ++++---- .../Functions/RestrictedFunctionsSniff.php | 12 ++-- .../Sniffs/Functions/StripTagsSniff.php | 2 +- .../Hooks/AlwaysReturnInFilterSniff.php | 36 ++++++------ .../Sniffs/Hooks/PreGetPostsSniff.php | 56 +++++++++---------- .../Sniffs/Hooks/RestrictedHooksSniff.php | 2 +- .../JS/DangerouslySetInnerHTMLSniff.php | 6 +- .../Sniffs/JS/HTMLExecutingFunctionsSniff.php | 14 ++--- .../Sniffs/JS/InnerHTMLSniff.php | 12 ++-- .../Sniffs/JS/StringConcatSniff.php | 4 +- .../Sniffs/JS/StrippingTagsSniff.php | 8 +-- WordPressVIPMinimum/Sniffs/JS/WindowSniff.php | 12 ++-- .../BatcacheWhitelistedParamsSniff.php | 6 +- .../Performance/CacheValueOverrideSniff.php | 20 +++---- .../Performance/FetchingRemoteDataSniff.php | 8 +-- .../Performance/LowExpiryCacheTimeSniff.php | 4 +- .../Sniffs/Performance/NoPagingSniff.php | 2 +- .../Sniffs/Performance/OrderByRandSniff.php | 2 +- .../Sniffs/Performance/RegexpCompareSniff.php | 6 +- .../TaxonomyMetaInOptionsSniff.php | 22 ++++---- .../Sniffs/Performance/WPQueryParamsSniff.php | 6 +- .../EscapingVoidReturnFunctionsSniff.php | 6 +- .../Security/ExitAfterRedirectSniff.php | 12 ++-- .../Sniffs/Security/MustacheSniff.php | 8 +-- .../Security/PHPFilterFunctionsSniff.php | 6 +- .../Security/ProperEscapingFunctionSniff.php | 20 +++---- .../Sniffs/Security/StaticStrreplaceSniff.php | 14 ++--- .../Sniffs/Security/TwigSniff.php | 4 +- .../Sniffs/Security/UnderscorejsSniff.php | 4 +- .../Sniffs/Security/VuejsSniff.php | 2 +- .../UserExperience/AdminBarRemovalSniff.php | 54 +++++++++--------- .../Sniffs/Variables/ServerVariablesSniff.php | 2 +- .../Variables/VariableAnalysisSniff.php | 4 +- tests/RulesetTest.php | 10 ++-- tests/bootstrap.php | 6 +- 44 files changed, 285 insertions(+), 285 deletions(-) diff --git a/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php b/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php index bc5e7a46..02fd7a58 100644 --- a/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/AbstractVariableRestrictionsSniff.php @@ -61,7 +61,7 @@ abstract class AbstractVariableRestrictionsSniff extends Sniff { */ public function register() { // Retrieve the groups only once and don't set up a listener if there are no groups. - if ( false === $this->setup_groups() ) { + if ( $this->setup_groups() === false ) { return []; } @@ -138,7 +138,7 @@ public function process_token( $stackPtr ) { if ( \in_array( $token['code'], [ \T_OBJECT_OPERATOR, \T_DOUBLE_COLON ], true ) ) { // This only works for object vars and array members. $method = $this->phpcsFile->findNext( \T_WHITESPACE, $stackPtr + 1, null, true ); $possible_parenthesis = $this->phpcsFile->findNext( \T_WHITESPACE, $method + 1, null, true ); - if ( \T_OPEN_PARENTHESIS === $this->tokens[ $possible_parenthesis ]['code'] ) { + if ( $this->tokens[ $possible_parenthesis ]['code'] === \T_OPEN_PARENTHESIS ) { return; // So .. it is a function after all ! } } @@ -185,9 +185,9 @@ public function process_token( $stackPtr ) { $patterns = array_map( [ $this, 'test_patterns' ], $patterns ); $pattern = implode( '|', $patterns ); - $delim = ( \T_OPEN_SQUARE_BRACKET !== $token['code'] && \T_HEREDOC !== $token['code'] ) ? '\b' : ''; + $delim = ( $token['code'] !== \T_OPEN_SQUARE_BRACKET && $token['code'] !== \T_HEREDOC ) ? '\b' : ''; - if ( \T_DOUBLE_QUOTED_STRING === $token['code'] || \T_HEREDOC === $token['code'] ) { + if ( $token['code'] === \T_DOUBLE_QUOTED_STRING || $token['code'] === \T_HEREDOC ) { $var = $token['content']; } @@ -198,7 +198,7 @@ public function process_token( $stackPtr ) { $this->addMessage( $group['message'], $stackPtr, - 'error' === $group['type'], + $group['type'] === 'error', $this->string_to_errorcode( $groupName . '_' . $match[1] ), [ $var ] ); diff --git a/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php b/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php index ed9874ce..6b294807 100644 --- a/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php +++ b/WordPressVIPMinimum/Sniffs/Classes/DeclarationCompatibilitySniff.php @@ -218,7 +218,7 @@ protected function processTokenWithinScope( File $phpcsFile, $stackPtr, $currSco $methodName = $phpcsFile->getDeclarationName( $stackPtr ); $parentClassName = $phpcsFile->findExtendedClassName( $currScope ); - if ( false === $parentClassName ) { + if ( $parentClassName === false ) { // This class does not extend any other class. return; } @@ -226,7 +226,7 @@ protected function processTokenWithinScope( File $phpcsFile, $stackPtr, $currSco // Meed to define the originalParentClassName since we might override the parentClassName due to signature notations grouping. $originalParentClassName = $parentClassName; - if ( false === array_key_exists( $parentClassName, $this->checkClasses ) ) { + if ( array_key_exists( $parentClassName, $this->checkClasses ) === false ) { // This class does not extend a class we are interested in. foreach ( $this->checkClassesGroups as $parent => $children ) { // But it might be one of the grouped classes. @@ -237,14 +237,14 @@ protected function processTokenWithinScope( File $phpcsFile, $stackPtr, $currSco } } } - if ( false === array_key_exists( $parentClassName, $this->checkClasses ) ) { + if ( array_key_exists( $parentClassName, $this->checkClasses ) === false ) { // This class really does not extend a class we are interested in. return; } } - if ( false === array_key_exists( $methodName, $this->checkClasses[ $parentClassName ] ) && - false === in_array( $methodName, $this->checkClasses[ $parentClassName ], true ) + if ( array_key_exists( $methodName, $this->checkClasses[ $parentClassName ] ) === false && + in_array( $methodName, $this->checkClasses[ $parentClassName ], true ) === false ) { // This method is not a one we are interested in. return; @@ -258,11 +258,11 @@ protected function processTokenWithinScope( File $phpcsFile, $stackPtr, $currSco $extra_params = array_slice( $signatureParams, count( $parentSignature ) - count( $signatureParams ) ); $all_extra_params_have_default = true; foreach ( $extra_params as $extra_param ) { - if ( false === array_key_exists( 'default', $extra_param ) || 'true' !== $extra_param['default'] ) { + if ( array_key_exists( 'default', $extra_param ) === false || $extra_param['default'] !== 'true' ) { $all_extra_params_have_default = false; } } - if ( true === $all_extra_params_have_default ) { + if ( $all_extra_params_have_default === true ) { return; // We're good. } } @@ -274,16 +274,16 @@ protected function processTokenWithinScope( File $phpcsFile, $stackPtr, $currSco $i = 0; foreach ( $parentSignature as $key => $param ) { - if ( true === is_array( $param ) ) { + if ( is_array( $param ) === true ) { if ( ( - true === array_key_exists( 'default', $param ) && - false === array_key_exists( 'default', $signatureParams[ $i ] ) + array_key_exists( 'default', $param ) === true && + array_key_exists( 'default', $signatureParams[ $i ] ) === false ) || ( - true === array_key_exists( 'pass_by_reference', $param ) && + array_key_exists( 'pass_by_reference', $param ) === true && $param['pass_by_reference'] !== $signatureParams[ $i ]['pass_by_reference'] ) || ( - true === array_key_exists( 'variable_length', $param ) && + array_key_exists( 'variable_length', $param ) === true && $param['variable_length'] !== $signatureParams[ $i ]['variable_length'] ) ) { @@ -329,26 +329,26 @@ private function generateParamList( $methodSignature ) { $paramList = []; foreach ( $methodSignature as $param => $options ) { $paramName = '$'; - if ( false === is_array( $options ) ) { + if ( is_array( $options ) === false ) { $paramList[] = '$' . $options; continue; } - if ( true === array_key_exists( 'name', $options ) ) { + if ( array_key_exists( 'name', $options ) === true ) { $paramName = $options['name']; } else { $paramName .= $param; } - if ( true === array_key_exists( 'variable_length', $options ) && true === $options['variable_length'] ) { + if ( array_key_exists( 'variable_length', $options ) === true && $options['variable_length'] === true ) { $paramName = '...' . $paramName; } - if ( true === array_key_exists( 'pass_by_reference', $options ) && true === $options['pass_by_reference'] ) { + if ( array_key_exists( 'pass_by_reference', $options ) === true && $options['pass_by_reference'] === true ) { $paramName = '&' . $paramName; } - if ( true === array_key_exists( 'default', $options ) && false === empty( $options['default'] ) ) { + if ( array_key_exists( 'default', $options ) === true && empty( $options['default'] ) === false ) { $paramName .= ' = ' . trim( $options['default'] ); } @@ -371,7 +371,7 @@ protected function loadFunctionNamesInScope( File $phpcsFile, $currScope ) { $tokens = $phpcsFile->getTokens(); for ( $i = ( $tokens[ $currScope ]['scope_opener'] + 1 ); $i < $tokens[ $currScope ]['scope_closer']; $i++ ) { - if ( T_FUNCTION !== $tokens[ $i ]['code'] ) { + if ( $tokens[ $i ]['code'] !== T_FUNCTION ) { continue; } diff --git a/WordPressVIPMinimum/Sniffs/Classes/RestrictedExtendClassesSniff.php b/WordPressVIPMinimum/Sniffs/Classes/RestrictedExtendClassesSniff.php index 92bd9f9e..b92ffbd8 100644 --- a/WordPressVIPMinimum/Sniffs/Classes/RestrictedExtendClassesSniff.php +++ b/WordPressVIPMinimum/Sniffs/Classes/RestrictedExtendClassesSniff.php @@ -47,7 +47,7 @@ public function getGroups() { public function process_matched_token( $stackPtr, $group_name, $matched_content ) { $tokens = $this->phpcsFile->getTokens(); - if ( T_EXTENDS !== $tokens[ $stackPtr ]['code'] ) { + if ( $tokens[ $stackPtr ]['code'] !== T_EXTENDS ) { // If not extending, bail. return; } diff --git a/WordPressVIPMinimum/Sniffs/Compatibility/ZoninatorSniff.php b/WordPressVIPMinimum/Sniffs/Compatibility/ZoninatorSniff.php index f7acc831..7d18a7f5 100644 --- a/WordPressVIPMinimum/Sniffs/Compatibility/ZoninatorSniff.php +++ b/WordPressVIPMinimum/Sniffs/Compatibility/ZoninatorSniff.php @@ -35,26 +35,26 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'wpcom_vip_load_plugin' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== 'wpcom_vip_load_plugin' ) { return; } $openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function call. return; } $plugin_name = $this->phpcsFile->findNext( Tokens::$emptyTokens, $openBracket + 1, null, true ); - if ( 'zoninator' !== $this->remove_wrapping_quotation_marks( $this->tokens[ $plugin_name ]['content'] ) ) { + if ( $this->remove_wrapping_quotation_marks( $this->tokens[ $plugin_name ]['content'] ) !== 'zoninator' ) { return; } $comma = $this->phpcsFile->findNext( Tokens::$emptyTokens, $plugin_name + 1, null, true ); - if ( ! $comma || 'PHPCS_T_COMMA' !== $this->tokens[ $comma ]['code'] ) { + if ( ! $comma || $this->tokens[ $comma ]['code'] !== 'PHPCS_T_COMMA' ) { // We are loading the default version. return; } @@ -63,7 +63,7 @@ public function process_token( $stackPtr ) { $comma = $this->phpcsFile->findNext( Tokens::$emptyTokens, $folder + 1, null, true ); - if ( ! $comma || 'PHPCS_T_COMMA' !== $this->tokens[ $comma ]['code'] ) { + if ( ! $comma || $this->tokens[ $comma ]['code'] !== 'PHPCS_T_COMMA' ) { // We are loading the default version. return; } @@ -71,7 +71,7 @@ public function process_token( $stackPtr ) { $version = $this->phpcsFile->findNext( Tokens::$emptyTokens, $comma + 1, null, true ); $version = $this->remove_wrapping_quotation_marks( $this->tokens[ $version ]['content'] ); - if ( true === version_compare( $version, '0.8', '>=' ) ) { + if ( version_compare( $version, '0.8', '>=' ) === true ) { $message = 'Zoninator of version >= v0.8 requires WordPress core REST API. Please, make sure the `wpcom_vip_load_wp_rest_api()` is being called on all sites loading this file.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'RequiresRESTAPI' ); } diff --git a/WordPressVIPMinimum/Sniffs/Constants/ConstantStringSniff.php b/WordPressVIPMinimum/Sniffs/Constants/ConstantStringSniff.php index dfb2cef2..24a13635 100644 --- a/WordPressVIPMinimum/Sniffs/Constants/ConstantStringSniff.php +++ b/WordPressVIPMinimum/Sniffs/Constants/ConstantStringSniff.php @@ -38,26 +38,26 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( false === in_array( $this->tokens[ $stackPtr ]['content'], [ 'define', 'defined' ], true ) ) { + if ( in_array( $this->tokens[ $stackPtr ]['content'], [ 'define', 'defined' ], true ) === false ) { return; } // Find the next non-empty token. $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function call. return; } - if ( false === isset( $this->tokens[ $nextToken ]['parenthesis_closer'] ) ) { + if ( isset( $this->tokens[ $nextToken ]['parenthesis_closer'] ) === false ) { // Not a function call. return; } $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true ); - if ( T_CONSTANT_ENCAPSED_STRING !== $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] !== T_CONSTANT_ENCAPSED_STRING ) { $message = 'Constant name, as a string, should be used along with `%s()`.'; $data = [ $this->tokens[ $stackPtr ]['content'] ]; $this->phpcsFile->addError( $message, $nextToken, 'NotCheckingConstantName', $data ); diff --git a/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php b/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php index a812b2ad..92d1f7dc 100644 --- a/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php @@ -58,18 +58,18 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( T_STRING === $this->tokens[ $stackPtr ]['code'] ) { + if ( $this->tokens[ $stackPtr ]['code'] === T_STRING ) { $constantName = $this->tokens[ $stackPtr ]['content']; } else { $constantName = trim( $this->tokens[ $stackPtr ]['content'], "\"'" ); } - if ( false === in_array( $constantName, $this->restrictedConstantNames, true ) && false === in_array( $constantName, $this->restrictedConstantDeclaration, true ) ) { + if ( in_array( $constantName, $this->restrictedConstantNames, true ) === false && in_array( $constantName, $this->restrictedConstantDeclaration, true ) === false ) { // Not the constant we are looking for. return; } - if ( T_STRING === $this->tokens[ $stackPtr ]['code'] && true === in_array( $constantName, $this->restrictedConstantNames, true ) ) { + if ( $this->tokens[ $stackPtr ]['code'] === T_STRING && in_array( $constantName, $this->restrictedConstantNames, true ) === true ) { $message = 'Code is touching the `%s` constant. Make sure it\'s used appropriately.'; $data = [ $constantName ]; $this->phpcsFile->addWarning( $message, $stackPtr, 'UsingRestrictedConstant', $data ); @@ -79,12 +79,12 @@ public function process_token( $stackPtr ) { // Find the previous non-empty token. $openBracket = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function call. return; } - if ( false === isset( $this->tokens[ $openBracket ]['parenthesis_closer'] ) ) { + if ( isset( $this->tokens[ $openBracket ]['parenthesis_closer'] ) === false ) { // Not a function call. return; } @@ -93,17 +93,17 @@ public function process_token( $stackPtr ) { $search = Tokens::$emptyTokens; $search[] = T_BITWISE_AND; $previous = $this->phpcsFile->findPrevious( $search, $openBracket - 1, null, true ); - if ( T_FUNCTION === $this->tokens[ $previous ]['code'] ) { + if ( $this->tokens[ $previous ]['code'] === T_FUNCTION ) { // It's a function definition, not a function call. return; } - if ( true === in_array( $this->tokens[ $previous ]['code'], Tokens::$functionNameTokens, true ) ) { + if ( in_array( $this->tokens[ $previous ]['code'], Tokens::$functionNameTokens, true ) === true ) { $data = [ $constantName ]; - if ( 'define' === $this->tokens[ $previous ]['content'] ) { + if ( $this->tokens[ $previous ]['content'] === 'define' ) { $message = 'The definition of `%s` constant is prohibited. Please use a different name.'; $this->phpcsFile->addError( $message, $previous, 'DefiningRestrictedConstant', $data ); - } elseif ( true === in_array( $constantName, $this->restrictedConstantNames, true ) ) { + } elseif ( in_array( $constantName, $this->restrictedConstantNames, true ) === true ) { $message = 'Code is touching the `%s` constant. Make sure it\'s used appropriately.'; $this->phpcsFile->addWarning( $message, $previous, 'UsingRestrictedConstant', $data ); } diff --git a/WordPressVIPMinimum/Sniffs/Files/IncludingFileSniff.php b/WordPressVIPMinimum/Sniffs/Files/IncludingFileSniff.php index 0f383800..0451dafb 100644 --- a/WordPressVIPMinimum/Sniffs/Files/IncludingFileSniff.php +++ b/WordPressVIPMinimum/Sniffs/Files/IncludingFileSniff.php @@ -94,35 +94,35 @@ public function register() { public function process_token( $stackPtr ) { $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); - if ( T_OPEN_PARENTHESIS === $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] === T_OPEN_PARENTHESIS ) { // The construct is using parenthesis, grab the next non empty token. $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true ); } - if ( T_DIR === $this->tokens[ $nextToken ]['code'] || '__DIR__' === $this->tokens[ $nextToken ]['content'] ) { + if ( $this->tokens[ $nextToken ]['code'] === T_DIR || $this->tokens[ $nextToken ]['content'] === '__DIR__' ) { // The construct is using __DIR__ which is fine. return; } - if ( T_VARIABLE === $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] === T_VARIABLE ) { $message = 'File inclusion using variable (`%s`). Probably needs manual inspection.'; $data = [ $this->tokens[ $nextToken ]['content'] ]; $this->phpcsFile->addWarning( $message, $nextToken, 'UsingVariable', $data ); return; } - if ( T_STRING === $this->tokens[ $nextToken ]['code'] ) { - if ( true === in_array( $this->tokens[ $nextToken ]['content'], $this->getPathFunctions, true ) ) { + if ( $this->tokens[ $nextToken ]['code'] === T_STRING ) { + if ( in_array( $this->tokens[ $nextToken ]['content'], $this->getPathFunctions, true ) === true ) { // The construct is using one of the function for getting correct path which is fine. return; } - if ( true === in_array( $this->tokens[ $nextToken ]['content'], $this->allowedConstants, true ) ) { + if ( in_array( $this->tokens[ $nextToken ]['content'], $this->allowedConstants, true ) === true ) { // The construct is using one of the allowed constants which is fine. return; } - if ( true === array_key_exists( $this->tokens[ $nextToken ]['content'], $this->restrictedConstants ) ) { + if ( array_key_exists( $this->tokens[ $nextToken ]['content'], $this->restrictedConstants ) === true ) { // The construct is using one of the restricted constants. $message = '`%s` constant might not be defined or available. Use `%s()` instead.'; $data = [ $this->tokens[ $nextToken ]['content'], $this->restrictedConstants[ $this->tokens[ $nextToken ]['content'] ] ]; @@ -131,7 +131,7 @@ public function process_token( $stackPtr ) { } $nextNextToken = $this->phpcsFile->findNext( array_merge( Tokens::$emptyTokens, [ T_COMMENT ] ), $nextToken + 1, null, true, null, true ); - if ( 1 === preg_match( '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $this->tokens[ $nextToken ]['content'] ) && T_OPEN_PARENTHESIS !== $this->tokens[ $nextNextToken ]['code'] ) { + if ( preg_match( '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $this->tokens[ $nextToken ]['content'] ) === 1 && $this->tokens[ $nextNextToken ]['code'] !== T_OPEN_PARENTHESIS ) { // The construct is using custom constant, which needs manual inspection. $message = 'File inclusion using custom constant (`%s`). Probably needs manual inspection.'; $data = [ $this->tokens[ $nextToken ]['content'] ]; @@ -139,14 +139,14 @@ public function process_token( $stackPtr ) { return; } - if ( 0 === strpos( $this->tokens[ $nextToken ]['content'], '$' ) ) { + if ( strpos( $this->tokens[ $nextToken ]['content'], '$' ) === 0 ) { $message = 'File inclusion using variable (`%s`). Probably needs manual inspection.'; $data = [ $this->tokens[ $nextToken ]['content'] ]; $this->phpcsFile->addWarning( $message, $nextToken, 'UsingVariable', $data ); return; } - if ( true === in_array( $this->tokens[ $nextToken ]['content'], $this->slashingFunctions, true ) ) { + if ( in_array( $this->tokens[ $nextToken ]['content'], $this->slashingFunctions, true ) === true ) { // The construct is using one of the slashing functions, it's probably correct. return; } @@ -163,7 +163,7 @@ public function process_token( $stackPtr ) { return; } - if ( T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $nextToken ]['code'] && filter_var( str_replace( [ '"', "'" ], '', $this->tokens[ $nextToken ]['content'] ), FILTER_VALIDATE_URL ) ) { + if ( $this->tokens[ $nextToken ]['code'] === T_CONSTANT_ENCAPSED_STRING && filter_var( str_replace( [ '"', "'" ], '', $this->tokens[ $nextToken ]['content'] ), FILTER_VALIDATE_URL ) ) { $message = 'Include path must be local file source, external URLs are prohibited on WordPress VIP.'; $this->phpcsFile->addError( $message, $nextToken, 'ExternalURL' ); return; diff --git a/WordPressVIPMinimum/Sniffs/Files/IncludingNonPHPFileSniff.php b/WordPressVIPMinimum/Sniffs/Files/IncludingNonPHPFileSniff.php index 77863272..ba1735c1 100644 --- a/WordPressVIPMinimum/Sniffs/Files/IncludingNonPHPFileSniff.php +++ b/WordPressVIPMinimum/Sniffs/Files/IncludingNonPHPFileSniff.php @@ -40,10 +40,10 @@ public function register() { */ public function process_token( $stackPtr ) { $curStackPtr = $stackPtr; - while ( false !== $this->phpcsFile->findNext( Tokens::$stringTokens, $curStackPtr + 1, null, false, null, true ) ) { + while ( $this->phpcsFile->findNext( Tokens::$stringTokens, $curStackPtr + 1, null, false, null, true ) !== false ) { $curStackPtr = $this->phpcsFile->findNext( Tokens::$stringTokens, $curStackPtr + 1, null, false, null, true ); - if ( T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $curStackPtr ]['code'] ) { + if ( $this->tokens[ $curStackPtr ]['code'] === T_CONSTANT_ENCAPSED_STRING ) { $stringWithoutEnclosingQuotationMarks = trim( $this->tokens[ $curStackPtr ]['content'], "\"'" ); } else { $stringWithoutEnclosingQuotationMarks = $this->tokens[ $curStackPtr ]['content']; @@ -51,12 +51,12 @@ public function process_token( $stackPtr ) { $isFileName = preg_match( '/.*(\.[a-z]{2,})$/i', $stringWithoutEnclosingQuotationMarks, $regexMatches ); - if ( false === $isFileName || 0 === $isFileName ) { + if ( $isFileName === false || $isFileName === 0 ) { continue; } $extension = $regexMatches[1]; - if ( true === in_array( $extension, [ '.php', '.inc' ], true ) ) { + if ( in_array( $extension, [ '.php', '.inc' ], true ) === true ) { return; } @@ -64,7 +64,7 @@ public function process_token( $stackPtr ) { $data = [ $this->tokens[ $stackPtr ]['content'] ]; $code = 'IncludingNonPHPFile'; - if ( true === in_array( $extension, [ '.svg', '.css' ], true ) ) { + if ( in_array( $extension, [ '.svg', '.css' ], true ) === true ) { // Be more specific for SVG and CSS files. $message = 'Local SVG and CSS files should be loaded via `file_get_contents` rather than via `%s`.'; $code = 'IncludingSVGCSSFile'; diff --git a/WordPressVIPMinimum/Sniffs/Functions/CheckReturnValueSniff.php b/WordPressVIPMinimum/Sniffs/Functions/CheckReturnValueSniff.php index af8fd7cb..a95c2acf 100644 --- a/WordPressVIPMinimum/Sniffs/Functions/CheckReturnValueSniff.php +++ b/WordPressVIPMinimum/Sniffs/Functions/CheckReturnValueSniff.php @@ -86,14 +86,14 @@ public function process_token( $stackPtr ) { */ private function isFunctionCall( $stackPtr ) { - if ( false === in_array( $this->tokens[ $stackPtr ]['code'], Tokens::$functionNameTokens, true ) ) { + if ( in_array( $this->tokens[ $stackPtr ]['code'], Tokens::$functionNameTokens, true ) === false ) { return false; } // Find the next non-empty token. $openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function call. return false; } @@ -104,7 +104,7 @@ private function isFunctionCall( $stackPtr ) { $previous = $this->phpcsFile->findPrevious( $search, $stackPtr - 1, null, true ); // It's a function definition, not a function call, so return false. - return ! ( T_FUNCTION === $this->tokens[ $previous ]['code'] ); + return ! ( $this->tokens[ $previous ]['code'] === T_FUNCTION ); } /** @@ -121,14 +121,14 @@ private function isVariableAssignment( $stackPtr ) { $search[] = T_BITWISE_AND; $previous = $this->phpcsFile->findPrevious( $search, $stackPtr - 1, null, true ); - if ( T_EQUAL !== $this->tokens[ $previous ]['code'] ) { + if ( $this->tokens[ $previous ]['code'] !== T_EQUAL ) { // It's not a variable assignment. return false; } $previous = $this->phpcsFile->findPrevious( $search, $previous - 1, null, true ); - if ( T_VARIABLE !== $this->tokens[ $previous ]['code'] ) { + if ( $this->tokens[ $previous ]['code'] !== T_VARIABLE ) { // It's not a variable assignment. return false; } @@ -145,12 +145,12 @@ public function findDirectFunctionCalls( $stackPtr ) { $functionName = $this->tokens[ $stackPtr ]['content']; - if ( false === array_key_exists( $functionName, $this->catch ) ) { + if ( array_key_exists( $functionName, $this->catch ) === false ) { // Not a function we are looking for. return; } - if ( false === $this->isFunctionCall( $stackPtr ) ) { + if ( $this->isFunctionCall( $stackPtr ) === false ) { // Not a function call. return; } @@ -164,7 +164,7 @@ public function findDirectFunctionCalls( $stackPtr ) { $startNext = $openBracket + 1; $next = $this->phpcsFile->findNext( Tokens::$functionNameTokens, $startNext, $closeBracket, false, null, true ); while ( $next ) { - if ( true === in_array( $this->tokens[ $next ]['content'], $this->catch[ $functionName ], true ) ) { + if ( in_array( $this->tokens[ $next ]['content'], $this->catch[ $functionName ], true ) === true ) { $message = "`%s`'s return type must be checked before calling `%s` using that value."; $data = [ $this->tokens[ $next ]['content'], $functionName ]; $this->phpcsFile->addError( $message, $next, 'DirectFunctionCall', $data ); @@ -192,25 +192,25 @@ public function findNonCheckedVariables( $stackPtr ) { $callees = []; foreach ( $this->catch as $callee => $checkReturnArray ) { - if ( true === in_array( $functionName, $checkReturnArray, true ) ) { + if ( in_array( $functionName, $checkReturnArray, true ) === true ) { $isFunctionWeLookFor = true; $callees[] = $callee; } } - if ( false === $isFunctionWeLookFor ) { + if ( $isFunctionWeLookFor === false ) { // Not a function we are looking for. return; } - if ( false === $this->isFunctionCall( $stackPtr ) ) { + if ( $this->isFunctionCall( $stackPtr ) === false ) { // Not a function call. return; } $variablePos = $this->isVariableAssignment( $stackPtr ); - if ( false === $variablePos ) { + if ( $variablePos === false ) { // Not a variable assignment. return; } @@ -224,7 +224,7 @@ public function findNonCheckedVariables( $stackPtr ) { // Find the closing bracket. $closeBracket = $this->tokens[ $openBracket ]['parenthesis_closer']; - if ( true === in_array( $functionName, [ 'get_post_meta', 'get_term_meta' ], true ) ) { + if ( in_array( $functionName, [ 'get_post_meta', 'get_term_meta' ], true ) === true ) { // Since the get_post_meta and get_term_meta always returns an array if $single is set to `true` we need to check for the value of it's third param before proceeding. $params = []; $paramNo = 1; @@ -232,11 +232,11 @@ public function findNonCheckedVariables( $stackPtr ) { for ( $i = $openBracket + 1; $i <= $closeBracket; $i++ ) { - if ( T_OPEN_PARENTHESIS === $this->tokens[ $i ]['code'] ) { + if ( $this->tokens[ $i ]['code'] === T_OPEN_PARENTHESIS ) { $i = $this->tokens[ $i ]['parenthesis_closer']; } - if ( T_COMMA === $this->tokens[ $i ]['code'] ) { + if ( $this->tokens[ $i ]['code'] === T_COMMA ) { $params[ $paramNo++ ] = trim( array_reduce( array_slice( $this->tokens, $prevCommaPos, $i - $prevCommaPos ), [ $this, 'reduce_array' ] ) ); $prevCommaPos = $i + 1; } @@ -247,7 +247,7 @@ public function findNonCheckedVariables( $stackPtr ) { } } - if ( false === array_key_exists( 3, $params ) || 'false' === $params[3] ) { + if ( array_key_exists( 3, $params ) === false || $params[3] === 'false' ) { // Third param of get_post_meta is not set (default to false) or is set to false. // Means the function returns an array. We are good then. return; @@ -269,7 +269,7 @@ public function findNonCheckedVariables( $stackPtr ) { foreach ( $callees as $callee ) { $notFunctionsCallee = array_key_exists( $callee, $this->notFunctions ) ? (array) $this->notFunctions[ $callee ] : []; // Check whether the found token is one of the function calls (or foreach call) we are interested in. - if ( true === in_array( $this->tokens[ $nextFunctionCallWithVariable ]['code'], array_merge( Tokens::$functionNameTokens, $notFunctionsCallee ), true ) + if ( in_array( $this->tokens[ $nextFunctionCallWithVariable ]['code'], array_merge( Tokens::$functionNameTokens, $notFunctionsCallee ), true ) === true && $this->tokens[ $nextFunctionCallWithVariable ]['content'] === $callee ) { $this->addNonCheckedVariableError( $nextFunctionCallWithVariable, $variableName, $callee ); @@ -278,7 +278,7 @@ public function findNonCheckedVariables( $stackPtr ) { $search = array_merge( Tokens::$emptyTokens, [ T_EQUAL ] ); $next = $this->phpcsFile->findNext( $search, $nextVariableOccurrence + 1, null, true ); - if ( true === in_array( $this->tokens[ $next ]['code'], Tokens::$functionNameTokens, true ) + if ( in_array( $this->tokens[ $next ]['code'], Tokens::$functionNameTokens, true ) === true && $this->tokens[ $next ]['content'] === $callee ) { $this->addNonCheckedVariableError( $next, $variableName, $callee ); diff --git a/WordPressVIPMinimum/Sniffs/Functions/DynamicCallsSniff.php b/WordPressVIPMinimum/Sniffs/Functions/DynamicCallsSniff.php index e1f6a22e..660bd0e1 100644 --- a/WordPressVIPMinimum/Sniffs/Functions/DynamicCallsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Functions/DynamicCallsSniff.php @@ -100,8 +100,8 @@ private function collect_variables() { */ if ( - 'T_VARIABLE' !== - $this->tokens[ $this->stackPtr ]['type'] + $this->tokens[ $this->stackPtr ]['type'] !== + 'T_VARIABLE' ) { return; } @@ -123,15 +123,15 @@ private function collect_variables() { true ); - if ( false === $t_item_key ) { + if ( $t_item_key === false ) { return; } - if ( 'T_EQUAL' !== $this->tokens[ $t_item_key ]['type'] ) { + if ( $this->tokens[ $t_item_key ]['type'] !== 'T_EQUAL' ) { return; } - if ( 1 !== $this->tokens[ $t_item_key ]['length'] ) { + if ( $this->tokens[ $t_item_key ]['length'] !== 1 ) { return; } @@ -147,7 +147,7 @@ private function collect_variables() { true ); - if ( false === $t_item_key ) { + if ( $t_item_key === false ) { return; } @@ -186,8 +186,8 @@ private function find_dynamic_calls() { */ if ( - 'T_VARIABLE' !== - $this->tokens[ $this->stackPtr ]['type'] + $this->tokens[ $this->stackPtr ]['type'] !== + 'T_VARIABLE' ) { return; } @@ -215,13 +215,13 @@ private function find_dynamic_calls() { do { $i++; } while ( - 'T_WHITESPACE' === - $this->tokens[ $this->stackPtr + $i ]['type'] + $this->tokens[ $this->stackPtr + $i ]['type'] === + 'T_WHITESPACE' ); if ( - 'T_OPEN_PARENTHESIS' !== - $this->tokens[ $this->stackPtr + $i ]['type'] + $this->tokens[ $this->stackPtr + $i ]['type'] !== + 'T_OPEN_PARENTHESIS' ) { return; } diff --git a/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php index 888b17ca..74995407 100644 --- a/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php @@ -373,22 +373,22 @@ public function getGroups() { */ public function is_targetted_token( $stackPtr ) { // Exclude function definitions, class methods, and namespaced calls. - if ( \T_STRING === $this->tokens[ $stackPtr ]['code'] && isset( $this->tokens[ $stackPtr - 1 ] ) ) { + if ( $this->tokens[ $stackPtr ]['code'] === \T_STRING && isset( $this->tokens[ $stackPtr - 1 ] ) ) { // Check if this is really a function. $next = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( false !== $next && T_OPEN_PARENTHESIS !== $this->tokens[ $next ]['code'] ) { + if ( $next !== false && $this->tokens[ $next ]['code'] !== T_OPEN_PARENTHESIS ) { return false; } $prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true ); - if ( false !== $prev ) { + if ( $prev !== false ) { // Start difference to parent class method. // Check to see if function is a method on a specific object variable. if ( ! empty( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'] ) ) { $prevPrev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 2, null, true ); - return \T_OBJECT_OPERATOR === $this->tokens[ $prev ]['code'] && isset( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'][ $this->tokens[ $prevPrev ]['content'] ] ); + return $this->tokens[ $prev ]['code'] === \T_OBJECT_OPERATOR && isset( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'][ $this->tokens[ $prevPrev ]['content'] ] ); } // End difference to parent class method. // Skip sniffing if calling a same-named method, or on function definitions. @@ -404,9 +404,9 @@ public function is_targetted_token( $stackPtr ) { return false; } // Skip namespaced functions, ie: \foo\bar() not \bar(). - if ( \T_NS_SEPARATOR === $this->tokens[ $prev ]['code'] ) { + if ( $this->tokens[ $prev ]['code'] === \T_NS_SEPARATOR ) { $pprev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $prev - 1, null, true ); - if ( false !== $pprev && \T_STRING === $this->tokens[ $pprev ]['code'] ) { + if ( $pprev !== false && $this->tokens[ $pprev ]['code'] === \T_STRING ) { return false; } } diff --git a/WordPressVIPMinimum/Sniffs/Functions/StripTagsSniff.php b/WordPressVIPMinimum/Sniffs/Functions/StripTagsSniff.php index 40b4094e..5434427d 100644 --- a/WordPressVIPMinimum/Sniffs/Functions/StripTagsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Functions/StripTagsSniff.php @@ -48,7 +48,7 @@ class StripTagsSniff extends AbstractFunctionParameterSniff { * normal file processing. */ public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { - if ( 1 === count( $parameters ) ) { + if ( count( $parameters ) === 1 ) { $message = '`strip_tags()` does not strip CSS and JS in between the script and style tags. Use `wp_strip_all_tags()` to strip all tags.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'StripTagsOneParameter' ); } elseif ( isset( $parameters[2] ) ) { diff --git a/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php b/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php index 357b7c2d..f5ea5734 100644 --- a/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php +++ b/WordPressVIPMinimum/Sniffs/Hooks/AlwaysReturnInFilterSniff.php @@ -44,7 +44,7 @@ public function process_token( $stackPtr ) { $functionName = $this->tokens[ $stackPtr ]['content']; - if ( 'add_filter' !== $functionName ) { + if ( $functionName !== 'add_filter' ) { return; } @@ -76,13 +76,13 @@ public function process_token( $stackPtr ) { return; } - if ( 'PHPCS_T_CLOSURE' === $this->tokens[ $callbackPtr ]['code'] ) { + if ( $this->tokens[ $callbackPtr ]['code'] === 'PHPCS_T_CLOSURE' ) { $this->processFunctionBody( $callbackPtr ); - } elseif ( T_ARRAY === $this->tokens[ $callbackPtr ]['code'] - || T_OPEN_SHORT_ARRAY === $this->tokens[ $callbackPtr ]['code'] + } elseif ( $this->tokens[ $callbackPtr ]['code'] === T_ARRAY + || $this->tokens[ $callbackPtr ]['code'] === T_OPEN_SHORT_ARRAY ) { $this->processArray( $callbackPtr ); - } elseif ( true === in_array( $this->tokens[ $callbackPtr ]['code'], Tokens::$stringTokens, true ) ) { + } elseif ( in_array( $this->tokens[ $callbackPtr ]['code'], Tokens::$stringTokens, true ) === true ) { $this->processString( $callbackPtr ); } } @@ -95,7 +95,7 @@ public function process_token( $stackPtr ) { private function processArray( $stackPtr ) { $open_close = $this->find_array_open_close( $stackPtr ); - if ( false === $open_close ) { + if ( $open_close === false ) { return; } @@ -106,7 +106,7 @@ private function processArray( $stackPtr ) { true ); - if ( true === in_array( T_CLASS, $this->tokens[ $stackPtr ]['conditions'], true ) ) { + if ( in_array( T_CLASS, $this->tokens[ $stackPtr ]['conditions'], true ) === true ) { $classPtr = array_search( T_CLASS, $this->tokens[ $stackPtr ]['conditions'], true ); if ( $classPtr ) { $classToken = $this->tokens[ $classPtr ]; @@ -157,10 +157,10 @@ private function processFunction( $stackPtr, $start = 0, $end = null ) { $functionName = $this->tokens[ $stackPtr ]['content']; $offset = $start; - while ( false !== $this->phpcsFile->findNext( [ T_FUNCTION ], $offset, $end ) ) { + while ( $this->phpcsFile->findNext( [ T_FUNCTION ], $offset, $end ) !== false ) { $functionStackPtr = $this->phpcsFile->findNext( [ T_FUNCTION ], $offset, $end ); $functionNamePtr = $this->phpcsFile->findNext( Tokens::$emptyTokens, $functionStackPtr + 1, null, true, null, true ); - if ( T_STRING === $this->tokens[ $functionNamePtr ]['code'] && $this->tokens[ $functionNamePtr ]['content'] === $functionName ) { + if ( $this->tokens[ $functionNamePtr ]['code'] === T_STRING && $this->tokens[ $functionNamePtr ]['content'] === $functionName ) { $this->processFunctionBody( $functionStackPtr ); return; } @@ -185,7 +185,7 @@ private function processFunctionBody( $stackPtr ) { ); // If arg is being passed by reference, we can skip. - if ( T_BITWISE_AND === $this->tokens[ $argPtr ]['code'] ) { + if ( $this->tokens[ $argPtr ]['code'] === T_BITWISE_AND ) { return; } @@ -221,7 +221,7 @@ private function processFunctionBody( $stackPtr ) { ); } - if ( 0 <= $insideIfConditionalReturn && 0 === $outsideConditionalReturn ) { + if ( $insideIfConditionalReturn >= 0 && $outsideConditionalReturn === 0 ) { $message = 'Please, make sure that a callback to `%s` filter is always returning some value.'; $data = [ $filterName ]; $this->phpcsFile->addError( $message, $functionBodyScopeStart, 'MissingReturnStatement', $data ); @@ -240,24 +240,24 @@ private function isInsideIfConditonal( $stackPtr ) { // This check helps us in situations a class or a function is wrapped // inside a conditional as a whole. Eg.: inside `class_exists`. - if ( T_FUNCTION === end( $this->tokens[ $stackPtr ]['conditions'] ) ) { + if ( end( $this->tokens[ $stackPtr ]['conditions'] ) === T_FUNCTION ) { return false; } // Similar case may be a conditional closure. - if ( 'PHPCS_T_CLOSURE' === end( $this->tokens[ $stackPtr ]['conditions'] ) ) { + if ( end( $this->tokens[ $stackPtr ]['conditions'] ) === 'PHPCS_T_CLOSURE' ) { return false; } // Loop over the array of conditions and look for an IF. reset( $this->tokens[ $stackPtr ]['conditions'] ); - if ( true === array_key_exists( 'conditions', $this->tokens[ $stackPtr ] ) - && true === is_array( $this->tokens[ $stackPtr ]['conditions'] ) - && false === empty( $this->tokens[ $stackPtr ]['conditions'] ) + if ( array_key_exists( 'conditions', $this->tokens[ $stackPtr ] ) === true + && is_array( $this->tokens[ $stackPtr ]['conditions'] ) === true + && empty( $this->tokens[ $stackPtr ]['conditions'] ) === false ) { foreach ( $this->tokens[ $stackPtr ]['conditions'] as $tokenPtr => $tokenCode ) { - if ( T_IF === $this->tokens[ $stackPtr ]['conditions'][ $tokenPtr ] ) { + if ( $this->tokens[ $stackPtr ]['conditions'][ $tokenPtr ] === T_IF ) { return true; } } @@ -281,6 +281,6 @@ private function isReturningVoid( $stackPtr ) { true ); - return T_SEMICOLON === $this->tokens[ $nextToReturnTokenPtr ]['code']; + return $this->tokens[ $nextToReturnTokenPtr ]['code'] === T_SEMICOLON; } } diff --git a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php index cd2c8867..eb1dce4e 100644 --- a/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Hooks/PreGetPostsSniff.php @@ -39,7 +39,7 @@ public function process_token( $stackPtr ) { $functionName = $this->tokens[ $stackPtr ]['content']; - if ( 'add_action' !== $functionName ) { + if ( $functionName !== 'add_action' ) { // We are interested in add_action calls only. return; } @@ -58,7 +58,7 @@ public function process_token( $stackPtr ) { return; } - if ( 'pre_get_posts' !== substr( $this->tokens[ $actionNamePtr ]['content'], 1, -1 ) ) { + if ( substr( $this->tokens[ $actionNamePtr ]['content'], 1, -1 ) !== 'pre_get_posts' ) { // This is not setting a callback for pre_get_posts action. return; } @@ -77,13 +77,13 @@ public function process_token( $stackPtr ) { return; } - if ( 'PHPCS_T_CLOSURE' === $this->tokens[ $callbackPtr ]['code'] ) { + if ( $this->tokens[ $callbackPtr ]['code'] === 'PHPCS_T_CLOSURE' ) { $this->processClosure( $callbackPtr ); - } elseif ( T_ARRAY === $this->tokens[ $callbackPtr ]['code'] - || T_OPEN_SHORT_ARRAY === $this->tokens[ $callbackPtr ]['code'] + } elseif ( $this->tokens[ $callbackPtr ]['code'] === T_ARRAY + || $this->tokens[ $callbackPtr ]['code'] === T_OPEN_SHORT_ARRAY ) { $this->processArray( $callbackPtr ); - } elseif ( true === in_array( $this->tokens[ $callbackPtr ]['code'], Tokens::$stringTokens, true ) ) { + } elseif ( in_array( $this->tokens[ $callbackPtr ]['code'], Tokens::$stringTokens, true ) === true ) { $this->processString( $callbackPtr ); } } @@ -96,7 +96,7 @@ public function process_token( $stackPtr ) { private function processArray( $stackPtr ) { $open_close = $this->find_array_open_close( $stackPtr ); - if ( false === $open_close ) { + if ( $open_close === false ) { return; } @@ -251,9 +251,9 @@ private function addPreGetPostsWarning( $stackPtr ) { */ private function isParentConditionalCheckingMainQuery( $stackPtr ) { - if ( false === array_key_exists( 'conditions', $this->tokens[ $stackPtr ] ) - || false === is_array( $this->tokens[ $stackPtr ]['conditions'] ) - || true === empty( $this->tokens[ $stackPtr ]['conditions'] ) + if ( array_key_exists( 'conditions', $this->tokens[ $stackPtr ] ) === false + || is_array( $this->tokens[ $stackPtr ]['conditions'] ) === false + || empty( $this->tokens[ $stackPtr ]['conditions'] ) === true ) { return false; } @@ -261,7 +261,7 @@ private function isParentConditionalCheckingMainQuery( $stackPtr ) { $conditionStackPtrs = array_keys( $this->tokens[ $stackPtr ]['conditions'] ); $lastConditionStackPtr = array_pop( $conditionStackPtrs ); - while ( T_IF === $this->tokens[ $stackPtr ]['conditions'][ $lastConditionStackPtr ] ) { + while ( $this->tokens[ $stackPtr ]['conditions'][ $lastConditionStackPtr ] === T_IF ) { $next = $this->phpcsFile->findNext( [ T_VARIABLE ], @@ -272,7 +272,7 @@ private function isParentConditionalCheckingMainQuery( $stackPtr ) { true ); while ( $next ) { - if ( true === $this->isWPQueryMethodCall( $next, 'is_main_query' ) ) { + if ( $this->isWPQueryMethodCall( $next, 'is_main_query' ) === true ) { return true; } $next = $this->phpcsFile->findNext( @@ -305,8 +305,8 @@ private function isEarlyMainQueryCheck( $stackPtr ) { return false; } - if ( false === array_key_exists( 'nested_parenthesis', $this->tokens[ $stackPtr ] ) - || true === empty( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) + if ( array_key_exists( 'nested_parenthesis', $this->tokens[ $stackPtr ] ) === false + || empty( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) === true ) { return false; } @@ -314,13 +314,13 @@ private function isEarlyMainQueryCheck( $stackPtr ) { $parentheses = $this->tokens[ $stackPtr ]['nested_parenthesis']; do { $nestedParenthesisEnd = array_shift( $parentheses ); - if ( null === $nestedParenthesisEnd ) { + if ( $nestedParenthesisEnd === null ) { // Nothing left in the array. No parenthesis found with a non-closure owner. return false; } if ( isset( $this->tokens[ $nestedParenthesisEnd ]['parenthesis_owner'] ) - && T_CLOSURE !== $this->tokens[ $this->tokens[ $nestedParenthesisEnd ]['parenthesis_owner'] ]['code'] + && $this->tokens[ $this->tokens[ $nestedParenthesisEnd ]['parenthesis_owner'] ]['code'] !== T_CLOSURE ) { break; } @@ -336,7 +336,7 @@ private function isEarlyMainQueryCheck( $stackPtr ) { true ); - if ( false !== $next && T_RETURN === $this->tokens[ $next ]['code'] ) { + if ( $next !== false && $this->tokens[ $next ]['code'] === T_RETURN ) { return true; } @@ -377,11 +377,11 @@ private function isWPQueryMethodCall( $stackPtr, $method = null ) { true ); - if ( ! $next || 'T_OBJECT_OPERATOR' !== $this->tokens[ $next ]['type'] ) { + if ( ! $next || $this->tokens[ $next ]['type'] !== 'T_OBJECT_OPERATOR' ) { return false; } - if ( null === $method ) { + if ( $method === null ) { return true; } @@ -394,7 +394,7 @@ private function isWPQueryMethodCall( $stackPtr, $method = null ) { true ); - return $next && true === in_array( $this->tokens[ $next ]['code'], Tokens::$functionNameTokens, true ) && $method === $this->tokens[ $next ]['content']; + return $next && in_array( $this->tokens[ $next ]['code'], Tokens::$functionNameTokens, true ) === true && $method === $this->tokens[ $next ]['content']; } /** @@ -406,9 +406,9 @@ private function isWPQueryMethodCall( $stackPtr, $method = null ) { */ private function isPartOfIfConditional( $stackPtr ) { - if ( true === array_key_exists( 'nested_parenthesis', $this->tokens[ $stackPtr ] ) - && true === is_array( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) - && false === empty( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) + if ( array_key_exists( 'nested_parenthesis', $this->tokens[ $stackPtr ] ) === true + && is_array( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) === true + && empty( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) === false ) { $previousLocalIf = $this->phpcsFile->findPrevious( [ T_IF ], @@ -418,7 +418,7 @@ private function isPartOfIfConditional( $stackPtr ) { null, true ); - if ( false !== $previousLocalIf + if ( $previousLocalIf !== false && $this->tokens[ $previousLocalIf ]['parenthesis_opener'] < $stackPtr && $this->tokens[ $previousLocalIf ]['parenthesis_closer'] > $stackPtr ) { @@ -437,13 +437,13 @@ private function isPartOfIfConditional( $stackPtr ) { */ private function isInsideIfConditonal( $stackPtr ) { - if ( true === array_key_exists( 'conditions', $this->tokens[ $stackPtr ] ) - && true === is_array( $this->tokens[ $stackPtr ]['conditions'] ) - && false === empty( $this->tokens[ $stackPtr ]['conditions'] ) + if ( array_key_exists( 'conditions', $this->tokens[ $stackPtr ] ) === true + && is_array( $this->tokens[ $stackPtr ]['conditions'] ) === true + && empty( $this->tokens[ $stackPtr ]['conditions'] ) === false ) { $conditionStackPtrs = array_keys( $this->tokens[ $stackPtr ]['conditions'] ); $lastConditionStackPtr = array_pop( $conditionStackPtrs ); - return T_IF === $this->tokens[ $stackPtr ]['conditions'][ $lastConditionStackPtr ]; + return $this->tokens[ $stackPtr ]['conditions'][ $lastConditionStackPtr ] === T_IF; } return false; } diff --git a/WordPressVIPMinimum/Sniffs/Hooks/RestrictedHooksSniff.php b/WordPressVIPMinimum/Sniffs/Hooks/RestrictedHooksSniff.php index ff340ebb..5b44c2df 100644 --- a/WordPressVIPMinimum/Sniffs/Hooks/RestrictedHooksSniff.php +++ b/WordPressVIPMinimum/Sniffs/Hooks/RestrictedHooksSniff.php @@ -114,7 +114,7 @@ private function normalize_hook_name_from_parameter( $parameter ) { if ( $concat_ptr ) { $hook_name = ''; for ( $i = $parameter['start'] + 1; $i < $parameter['end']; $i++ ) { - if ( T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $i ]['code'] ) { + if ( $this->tokens[ $i ]['code'] === T_CONSTANT_ENCAPSED_STRING ) { $hook_name .= str_replace( [ "'", '"' ], '', $this->tokens[ $i ]['content'] ); } } diff --git a/WordPressVIPMinimum/Sniffs/JS/DangerouslySetInnerHTMLSniff.php b/WordPressVIPMinimum/Sniffs/JS/DangerouslySetInnerHTMLSniff.php index c0d82efc..9355756e 100644 --- a/WordPressVIPMinimum/Sniffs/JS/DangerouslySetInnerHTMLSniff.php +++ b/WordPressVIPMinimum/Sniffs/JS/DangerouslySetInnerHTMLSniff.php @@ -46,21 +46,21 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'dangerouslySetInnerHTML' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== 'dangerouslySetInnerHTML' ) { // Looking for dangerouslySetInnerHTML only. return; } $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); - if ( T_EQUAL !== $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] !== T_EQUAL ) { // Not an assignment. return; } $nextNextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true ); - if ( T_OBJECT !== $this->tokens[ $nextNextToken ]['code'] ) { + if ( $this->tokens[ $nextNextToken ]['code'] !== T_OBJECT ) { // Not react syntax. return; } diff --git a/WordPressVIPMinimum/Sniffs/JS/HTMLExecutingFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/JS/HTMLExecutingFunctionsSniff.php index dc76da4a..66126d28 100644 --- a/WordPressVIPMinimum/Sniffs/JS/HTMLExecutingFunctionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/JS/HTMLExecutingFunctionsSniff.php @@ -76,10 +76,10 @@ public function process_token( $stackPtr ) { return; } - if ( 'content' === $this->HTMLExecutingFunctions[ $this->tokens[ $stackPtr ]['content'] ] ) { + if ( $this->HTMLExecutingFunctions[ $this->tokens[ $stackPtr ]['content'] ] === 'content' ) { $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function. return; } @@ -88,7 +88,7 @@ public function process_token( $stackPtr ) { while ( $nextToken < $parenthesis_closer ) { $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true ); - if ( T_STRING === $this->tokens[ $nextToken ]['code'] ) { // Contains a variable, function call or something else dynamic. + if ( $this->tokens[ $nextToken ]['code'] === T_STRING ) { // Contains a variable, function call or something else dynamic. $message = 'Any HTML passed to `%s` gets executed. Make sure it\'s properly escaped.'; $data = [ $this->tokens[ $stackPtr ]['content'] ]; $this->phpcsFile->addWarning( $message, $stackPtr, $this->tokens[ $stackPtr ]['content'], $data ); @@ -96,16 +96,16 @@ public function process_token( $stackPtr ) { return; } } - } elseif ( 'target' === $this->HTMLExecutingFunctions[ $this->tokens[ $stackPtr ]['content'] ] ) { + } elseif ( $this->HTMLExecutingFunctions[ $this->tokens[ $stackPtr ]['content'] ] === 'target' ) { $prevToken = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true, null, true ); - if ( T_OBJECT_OPERATOR !== $this->tokens[ $prevToken ]['code'] ) { + if ( $this->tokens[ $prevToken ]['code'] !== T_OBJECT_OPERATOR ) { return; } $prevPrevToken = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $prevToken - 1, null, true, null, true ); - if ( T_CLOSE_PARENTHESIS !== $this->tokens[ $prevPrevToken ]['code'] ) { + if ( $this->tokens[ $prevPrevToken ]['code'] !== T_CLOSE_PARENTHESIS ) { // Not a function call, but may be a variable containing an element reference, so just // flag all remaining instances of these target HTML executing functions. $message = 'Any HTML used with `%s` gets executed. Make sure it\'s properly escaped.'; @@ -120,7 +120,7 @@ public function process_token( $stackPtr ) { while ( $prevPrevToken > $parenthesis_opener ) { $prevPrevToken = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $prevPrevToken - 1, null, true, null, true ); - if ( T_STRING === $this->tokens[ $prevPrevToken ]['code'] ) { // Contains a variable, function call or something else dynamic. + if ( $this->tokens[ $prevPrevToken ]['code'] === T_STRING ) { // Contains a variable, function call or something else dynamic. $message = 'Any HTML used with `%s` gets executed. Make sure it\'s properly escaped.'; $data = [ $this->tokens[ $stackPtr ]['content'] ]; $this->phpcsFile->addWarning( $message, $stackPtr, $this->tokens[ $stackPtr ]['content'], $data ); diff --git a/WordPressVIPMinimum/Sniffs/JS/InnerHTMLSniff.php b/WordPressVIPMinimum/Sniffs/JS/InnerHTMLSniff.php index c197c6fe..aac49116 100644 --- a/WordPressVIPMinimum/Sniffs/JS/InnerHTMLSniff.php +++ b/WordPressVIPMinimum/Sniffs/JS/InnerHTMLSniff.php @@ -46,20 +46,20 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'innerHTML' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== 'innerHTML' ) { // Looking for .innerHTML only. return; } $prevToken = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true, null, true ); - if ( T_OBJECT_OPERATOR !== $this->tokens[ $prevToken ]['code'] ) { + if ( $this->tokens[ $prevToken ]['code'] !== T_OBJECT_OPERATOR ) { return; } $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); - if ( T_EQUAL !== $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] !== T_EQUAL ) { // Not an assignment. return; } @@ -67,9 +67,9 @@ public function process_token( $stackPtr ) { $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true ); $foundVariable = false; - while ( false !== $nextToken && T_SEMICOLON !== $this->tokens[ $nextToken ]['code'] ) { + while ( $nextToken !== false && $this->tokens[ $nextToken ]['code'] !== T_SEMICOLON ) { - if ( T_STRING === $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] === T_STRING ) { $foundVariable = true; break; } @@ -77,7 +77,7 @@ public function process_token( $stackPtr ) { $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true ); } - if ( true === $foundVariable ) { + if ( $foundVariable === true ) { $message = 'Any HTML passed to `%s` gets executed. Consider using `.textContent` or make sure that used variables are properly escaped.'; $data = [ $this->tokens[ $stackPtr ]['content'] ]; $this->phpcsFile->addWarning( $message, $stackPtr, 'Found', $data ); diff --git a/WordPressVIPMinimum/Sniffs/JS/StringConcatSniff.php b/WordPressVIPMinimum/Sniffs/JS/StringConcatSniff.php index ac58d654..d0ace2ee 100644 --- a/WordPressVIPMinimum/Sniffs/JS/StringConcatSniff.php +++ b/WordPressVIPMinimum/Sniffs/JS/StringConcatSniff.php @@ -49,14 +49,14 @@ public function process_token( $stackPtr ) { $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); - if ( T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $nextToken ]['code'] && false !== strpos( $this->tokens[ $nextToken ]['content'], '<' ) && 1 === preg_match( '/\<\/[a-zA-Z]+/', $this->tokens[ $nextToken ]['content'] ) ) { + if ( $this->tokens[ $nextToken ]['code'] === T_CONSTANT_ENCAPSED_STRING && strpos( $this->tokens[ $nextToken ]['content'], '<' ) !== false && preg_match( '/\<\/[a-zA-Z]+/', $this->tokens[ $nextToken ]['content'] ) === 1 ) { $data = [ '+' . $this->tokens[ $nextToken ]['content'] ]; $this->addFoundError( $stackPtr, $data ); } $prevToken = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true, null, true ); - if ( T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $prevToken ]['code'] && false !== strpos( $this->tokens[ $prevToken ]['content'], '<' ) && 1 === preg_match( '/\<[a-zA-Z]+/', $this->tokens[ $prevToken ]['content'] ) ) { + if ( $this->tokens[ $prevToken ]['code'] === T_CONSTANT_ENCAPSED_STRING && strpos( $this->tokens[ $prevToken ]['content'], '<' ) !== false && preg_match( '/\<[a-zA-Z]+/', $this->tokens[ $prevToken ]['content'] ) === 1 ) { $data = [ $this->tokens[ $nextToken ]['content'] . '+' ]; $this->addFoundError( $stackPtr, $data ); } diff --git a/WordPressVIPMinimum/Sniffs/JS/StrippingTagsSniff.php b/WordPressVIPMinimum/Sniffs/JS/StrippingTagsSniff.php index e4ead8c5..b140d8f6 100644 --- a/WordPressVIPMinimum/Sniffs/JS/StrippingTagsSniff.php +++ b/WordPressVIPMinimum/Sniffs/JS/StrippingTagsSniff.php @@ -48,27 +48,27 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'html' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== 'html' ) { // Looking for html() only. return; } $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $nextToken ]['code'] ) { + if ( $this->tokens[ $nextToken ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function. return; } $afterFunctionCall = $this->phpcsFile->findNext( Tokens::$emptyTokens, $this->tokens[ $nextToken ]['parenthesis_closer'] + 1, null, true, null, true ); - if ( T_OBJECT_OPERATOR !== $this->tokens[ $afterFunctionCall ]['code'] ) { + if ( $this->tokens[ $afterFunctionCall ]['code'] !== T_OBJECT_OPERATOR ) { return; } $nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $afterFunctionCall + 1, null, true, null, true ); - if ( T_STRING === $this->tokens[ $nextToken ]['code'] && 'text' === $this->tokens[ $nextToken ]['content'] ) { + if ( $this->tokens[ $nextToken ]['code'] === T_STRING && $this->tokens[ $nextToken ]['content'] === 'text' ) { $message = 'Vulnerable tag stripping approach detected.'; $this->phpcsFile->addError( $message, $stackPtr, 'VulnerableTagStripping' ); } diff --git a/WordPressVIPMinimum/Sniffs/JS/WindowSniff.php b/WordPressVIPMinimum/Sniffs/JS/WindowSniff.php index 847df92f..602d342c 100644 --- a/WordPressVIPMinimum/Sniffs/JS/WindowSniff.php +++ b/WordPressVIPMinimum/Sniffs/JS/WindowSniff.php @@ -69,20 +69,20 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'window' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== 'window' ) { // Doesn't begin with 'window', bail. return; } $nextTokenPtr = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true ); $nextToken = $this->tokens[ $nextTokenPtr ]['code']; - if ( T_OBJECT_OPERATOR !== $nextToken && T_OPEN_SQUARE_BRACKET !== $nextToken ) { + if ( $nextToken !== T_OBJECT_OPERATOR && $nextToken !== T_OPEN_SQUARE_BRACKET ) { // No . or [' next, bail. return; } $nextNextTokenPtr = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextTokenPtr + 1, null, true, null, true ); - if ( false === $nextNextTokenPtr ) { + if ( $nextNextTokenPtr === false ) { // Something went wrong, bail. return; } @@ -97,9 +97,9 @@ public function process_token( $stackPtr ) { $nextNextNextToken = $this->tokens[ $nextNextNextTokenPtr ]['code']; $nextNextNextNextToken = false; - if ( T_OBJECT_OPERATOR === $nextNextNextToken || T_OPEN_SQUARE_BRACKET === $nextNextNextToken ) { + if ( $nextNextNextToken === T_OBJECT_OPERATOR || $nextNextNextToken === T_OPEN_SQUARE_BRACKET ) { $nextNextNextNextTokenPtr = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextNextNextTokenPtr + 1, null, true, null, true ); - if ( false === $nextNextNextNextTokenPtr ) { + if ( $nextNextNextNextTokenPtr === false ) { // Something went wrong, bail. return; } @@ -117,7 +117,7 @@ public function process_token( $stackPtr ) { $prevTokenPtr = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true, null, true ); - if ( T_EQUAL === $this->tokens[ $prevTokenPtr ]['code'] ) { + if ( $this->tokens[ $prevTokenPtr ]['code'] === T_EQUAL ) { // Variable assignment. $message = 'Data from JS global "%s" may contain user-supplied values and should be checked.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'VarAssignment', $data ); diff --git a/WordPressVIPMinimum/Sniffs/Performance/BatcacheWhitelistedParamsSniff.php b/WordPressVIPMinimum/Sniffs/Performance/BatcacheWhitelistedParamsSniff.php index 1bc093f6..1b42498b 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/BatcacheWhitelistedParamsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/BatcacheWhitelistedParamsSniff.php @@ -88,13 +88,13 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( '$_GET' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== '$_GET' ) { return; } $key = $this->phpcsFile->findNext( array_merge( Tokens::$emptyTokens, [ T_OPEN_SQUARE_BRACKET ] ), $stackPtr + 1, null, true ); - if ( T_CONSTANT_ENCAPSED_STRING !== $this->tokens[ $key ]['code'] ) { + if ( $this->tokens[ $key ]['code'] !== T_CONSTANT_ENCAPSED_STRING ) { return; } @@ -102,7 +102,7 @@ public function process_token( $stackPtr ) { $variable_name = substr( $variable_name, 1, -1 ); - if ( true === in_array( $variable_name, $this->whitelistes_batcache_params, true ) ) { + if ( in_array( $variable_name, $this->whitelistes_batcache_params, true ) === true ) { $message = 'Batcache whitelisted GET param, `%s`, found. Batcache whitelisted parameters get stripped and are not available in PHP.'; $data = [ $variable_name ]; $this->phpcsFile->addWarning( $message, $stackPtr, 'StrippedGetParam', $data ); diff --git a/WordPressVIPMinimum/Sniffs/Performance/CacheValueOverrideSniff.php b/WordPressVIPMinimum/Sniffs/Performance/CacheValueOverrideSniff.php index 3434f5a0..96696437 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/CacheValueOverrideSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/CacheValueOverrideSniff.php @@ -44,19 +44,19 @@ public function process_token( $stackPtr ) { $functionName = $this->tokens[ $stackPtr ]['content']; - if ( 'wp_cache_get' !== $functionName ) { + if ( $functionName !== 'wp_cache_get' ) { // Not a function we are looking for. return; } - if ( false === $this->isFunctionCall( $stackPtr ) ) { + if ( $this->isFunctionCall( $stackPtr ) === false ) { // Not a function call. return; } $variablePos = $this->isVariableAssignment( $stackPtr ); - if ( false === $variablePos ) { + if ( $variablePos === false ) { // Not a variable assignment. return; } @@ -74,14 +74,14 @@ public function process_token( $stackPtr ) { $rightAfterNextVariableOccurence = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextVariableOccurrence + 1, null, true, null, true ); - if ( T_EQUAL !== $this->tokens[ $rightAfterNextVariableOccurence ]['code'] ) { + if ( $this->tokens[ $rightAfterNextVariableOccurence ]['code'] !== T_EQUAL ) { // Not a value override. return; } $valueAfterEqualSign = $this->phpcsFile->findNext( Tokens::$emptyTokens, $rightAfterNextVariableOccurence + 1, null, true, null, true ); - if ( T_FALSE === $this->tokens[ $valueAfterEqualSign ]['code'] ) { + if ( $this->tokens[ $valueAfterEqualSign ]['code'] === T_FALSE ) { $message = 'Obtained cached value in `%s` is being overridden. Disabling caching?'; $data = [ $variableName ]; $this->phpcsFile->addError( $message, $nextVariableOccurrence, 'CacheValueOverride', $data ); @@ -97,14 +97,14 @@ public function process_token( $stackPtr ) { */ private function isFunctionCall( $stackPtr ) { - if ( false === in_array( $this->tokens[ $stackPtr ]['code'], Tokens::$functionNameTokens, true ) ) { + if ( in_array( $this->tokens[ $stackPtr ]['code'], Tokens::$functionNameTokens, true ) === false ) { return false; } // Find the next non-empty token. $openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function call. return false; } @@ -115,7 +115,7 @@ private function isFunctionCall( $stackPtr ) { $previous = $this->phpcsFile->findPrevious( $search, $stackPtr - 1, null, true ); // It's a function definition, not a function call, so return false. - return ! ( T_FUNCTION === $this->tokens[ $previous ]['code'] ); + return ! ( $this->tokens[ $previous ]['code'] === T_FUNCTION ); } /** @@ -132,14 +132,14 @@ private function isVariableAssignment( $stackPtr ) { $search[] = T_BITWISE_AND; $previous = $this->phpcsFile->findPrevious( $search, $stackPtr - 1, null, true ); - if ( T_EQUAL !== $this->tokens[ $previous ]['code'] ) { + if ( $this->tokens[ $previous ]['code'] !== T_EQUAL ) { // It's not a variable assignment. return false; } $previous = $this->phpcsFile->findPrevious( $search, $previous - 1, null, true ); - if ( T_VARIABLE !== $this->tokens[ $previous ]['code'] ) { + if ( $this->tokens[ $previous ]['code'] !== T_VARIABLE ) { // It's not a variable assignment. return false; } diff --git a/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php b/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php index 4e0cacaf..62d1d090 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/FetchingRemoteDataSniff.php @@ -37,22 +37,22 @@ public function register() { public function process_token( $stackPtr ) { $functionName = $this->tokens[ $stackPtr ]['content']; - if ( 'file_get_contents' !== $functionName ) { + if ( $functionName !== 'file_get_contents' ) { return; } $data = [ $this->tokens[ $stackPtr ]['content'] ]; $fileNameStackPtr = $this->phpcsFile->findNext( Tokens::$stringTokens, $stackPtr + 1, null, false, null, true ); - if ( false === $fileNameStackPtr ) { + if ( $fileNameStackPtr === false ) { $message = '`%s()` is highly discouraged for remote requests, please use `wpcom_vip_file_get_contents()` or `vip_safe_wp_remote_get()` instead. If it\'s for a local file please use WP_Filesystem instead.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'FileGetContentsUnknown', $data ); } $fileName = $this->tokens[ $fileNameStackPtr ]['content']; - $isRemoteFile = ( false !== strpos( $fileName, '://' ) ); - if ( true === $isRemoteFile ) { + $isRemoteFile = ( strpos( $fileName, '://' ) !== false ); + if ( $isRemoteFile === true ) { $message = '`%s()` is highly discouraged for remote requests, please use `wpcom_vip_file_get_contents()` or `vip_safe_wp_remote_get()` instead.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'FileGetContentsRemoteFile', $data ); } diff --git a/WordPressVIPMinimum/Sniffs/Performance/LowExpiryCacheTimeSniff.php b/WordPressVIPMinimum/Sniffs/Performance/LowExpiryCacheTimeSniff.php index 20ae980f..34ea78e6 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/LowExpiryCacheTimeSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/LowExpiryCacheTimeSniff.php @@ -64,14 +64,14 @@ class LowExpiryCacheTimeSniff extends AbstractFunctionParameterSniff { * normal file processing. */ public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { - if ( false === isset( $parameters[4] ) ) { + if ( isset( $parameters[4] ) === false ) { // If no cache expiry time, bail (i.e. we don't want to flag for something like feeds where it is cached indefinitely until a hook runs). return; } $time = $parameters[4]['raw']; - if ( false === is_numeric( $time ) ) { + if ( is_numeric( $time ) === false ) { // If using time constants, we need to convert to a number. $time = str_replace( array_keys( $this->wp_time_constants ), $this->wp_time_constants, $time ); diff --git a/WordPressVIPMinimum/Sniffs/Performance/NoPagingSniff.php b/WordPressVIPMinimum/Sniffs/Performance/NoPagingSniff.php index fbeffa51..124b3aeb 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/NoPagingSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/NoPagingSniff.php @@ -51,7 +51,7 @@ public function getGroups() { public function callback( $key, $val, $line, $group ) { $key = strtolower( $key ); - if ( 'nopaging' === $key && ( 'true' === $val || 1 === $val ) ) { + if ( $key === 'nopaging' && ( $val === 'true' || $val === 1 ) ) { return 'Disabling pagination is prohibited in VIP context, do not set `%s` to `%s` ever.'; } diff --git a/WordPressVIPMinimum/Sniffs/Performance/OrderByRandSniff.php b/WordPressVIPMinimum/Sniffs/Performance/OrderByRandSniff.php index b743e74d..47d3c604 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/OrderByRandSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/OrderByRandSniff.php @@ -49,7 +49,7 @@ public function getGroups() { * @return mixed FALSE if no match, TRUE if matches, STRING if matches with custom error message passed to ->process(). */ public function callback( $key, $val, $line, $group ) { - if ( 'rand' === strtolower( $val ) ) { + if ( strtolower( $val ) === 'rand' ) { return 'Detected forbidden query_var "%s" of "%s". Use vip_get_random_posts() instead.'; } diff --git a/WordPressVIPMinimum/Sniffs/Performance/RegexpCompareSniff.php b/WordPressVIPMinimum/Sniffs/Performance/RegexpCompareSniff.php index 7a34ab5c..9e828677 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/RegexpCompareSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/RegexpCompareSniff.php @@ -56,9 +56,9 @@ public function getGroups() { * with custom error message passed to ->process(). */ public function callback( $key, $val, $line, $group ) { - if ( 0 === strpos( $val, 'NOT REGEXP' ) - || 0 === strpos( $val, 'REGEXP' ) - || true === in_array( $val, [ 'REGEXP', 'NOT REGEXP' ], true ) + if ( strpos( $val, 'NOT REGEXP' ) === 0 + || strpos( $val, 'REGEXP' ) === 0 + || in_array( $val, [ 'REGEXP', 'NOT REGEXP' ], true ) === true ) { return 'Detected regular expression comparison. `%s` is set to `%s`.'; } diff --git a/WordPressVIPMinimum/Sniffs/Performance/TaxonomyMetaInOptionsSniff.php b/WordPressVIPMinimum/Sniffs/Performance/TaxonomyMetaInOptionsSniff.php index 7586d642..071dc641 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/TaxonomyMetaInOptionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/TaxonomyMetaInOptionsSniff.php @@ -63,56 +63,56 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( false === in_array( $this->tokens[ $stackPtr ]['content'], $this->option_functions, true ) ) { + if ( in_array( $this->tokens[ $stackPtr ]['content'], $this->option_functions, true ) === false ) { return; } $openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { return; } $param_ptr = $this->phpcsFile->findNext( Tokens::$emptyTokens, $openBracket + 1, null, true ); - if ( T_DOUBLE_QUOTED_STRING === $this->tokens[ $param_ptr ]['code'] ) { + if ( $this->tokens[ $param_ptr ]['code'] === T_DOUBLE_QUOTED_STRING ) { foreach ( $this->taxonomy_term_patterns as $taxonomy_term_pattern ) { - if ( false !== strpos( $this->tokens[ $param_ptr ]['content'], $taxonomy_term_pattern ) ) { + if ( strpos( $this->tokens[ $param_ptr ]['content'], $taxonomy_term_pattern ) !== false ) { $this->addPossibleTermMetaInOptionsWarning( $stackPtr ); return; } } - } elseif ( T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $param_ptr ]['code'] ) { + } elseif ( $this->tokens[ $param_ptr ]['code'] === T_CONSTANT_ENCAPSED_STRING ) { $string_concat = $this->phpcsFile->findNext( Tokens::$emptyTokens, $param_ptr + 1, null, true ); - if ( T_STRING_CONCAT !== $this->tokens[ $string_concat ]['code'] ) { + if ( $this->tokens[ $string_concat ]['code'] !== T_STRING_CONCAT ) { return; } $variable_name = $this->phpcsFile->findNext( Tokens::$emptyTokens, $string_concat + 1, null, true ); - if ( T_VARIABLE !== $this->tokens[ $variable_name ]['code'] ) { + if ( $this->tokens[ $variable_name ]['code'] !== T_VARIABLE ) { return; } foreach ( $this->taxonomy_term_patterns as $taxonomy_term_pattern ) { - if ( false !== strpos( $this->tokens[ $variable_name ]['content'], $taxonomy_term_pattern ) ) { + if ( strpos( $this->tokens[ $variable_name ]['content'], $taxonomy_term_pattern ) !== false ) { $this->addPossibleTermMetaInOptionsWarning( $stackPtr ); return; } } $object_operator = $this->phpcsFile->findNext( Tokens::$emptyTokens, $variable_name + 1, null, true ); - if ( T_OBJECT_OPERATOR !== $this->tokens[ $object_operator ]['code'] ) { + if ( $this->tokens[ $object_operator ]['code'] !== T_OBJECT_OPERATOR ) { return; } $object_property = $this->phpcsFile->findNext( Tokens::$emptyTokens, $object_operator + 1, null, true ); - if ( T_STRING !== $this->tokens[ $object_property ]['code'] ) { + if ( $this->tokens[ $object_property ]['code'] !== T_STRING ) { return; } foreach ( $this->taxonomy_term_patterns as $taxonomy_term_pattern ) { - if ( false !== strpos( $this->tokens[ $object_property ]['content'], $taxonomy_term_pattern ) ) { + if ( strpos( $this->tokens[ $object_property ]['content'], $taxonomy_term_pattern ) !== false ) { $this->addPossibleTermMetaInOptionsWarning( $stackPtr ); return; } diff --git a/WordPressVIPMinimum/Sniffs/Performance/WPQueryParamsSniff.php b/WordPressVIPMinimum/Sniffs/Performance/WPQueryParamsSniff.php index ea7b4865..949e3f5b 100644 --- a/WordPressVIPMinimum/Sniffs/Performance/WPQueryParamsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Performance/WPQueryParamsSniff.php @@ -38,11 +38,11 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'suppress_filters' === trim( $this->tokens[ $stackPtr ]['content'], '\'' ) ) { + if ( trim( $this->tokens[ $stackPtr ]['content'], '\'' ) === 'suppress_filters' ) { $next_token = $this->phpcsFile->findNext( array_merge( Tokens::$emptyTokens, [ T_EQUAL, T_CLOSE_SQUARE_BRACKET, T_DOUBLE_ARROW ] ), $stackPtr + 1, null, true ); - if ( T_TRUE === $this->tokens[ $next_token ]['code'] ) { + if ( $this->tokens[ $next_token ]['code'] === T_TRUE ) { // WordPress.com: https://lobby.vip.wordpress.com/wordpress-com-documentation/uncached-functions/. // VIP Go: https://wpvip.com/documentation/vip-go/uncached-functions/. $message = 'Setting `suppress_filters` to `true` is prohibited.'; @@ -50,7 +50,7 @@ public function process_token( $stackPtr ) { } } - if ( 'post__not_in' === trim( $this->tokens[ $stackPtr ]['content'], '\'' ) ) { + if ( trim( $this->tokens[ $stackPtr ]['content'], '\'' ) === 'post__not_in' ) { $message = 'Using `post__not_in` should be done with caution, see https://wpvip.com/documentation/performance-improvements-by-removing-usage-of-post__not_in/ for more information.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'PostNotIn' ); } diff --git a/WordPressVIPMinimum/Sniffs/Security/EscapingVoidReturnFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/Security/EscapingVoidReturnFunctionsSniff.php index c1f57d12..5c7f4e72 100644 --- a/WordPressVIPMinimum/Sniffs/Security/EscapingVoidReturnFunctionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/EscapingVoidReturnFunctionsSniff.php @@ -40,21 +40,21 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 0 !== strpos( $this->tokens[ $stackPtr ]['content'], 'esc_' ) && 0 !== strpos( $this->tokens[ $stackPtr ]['content'], 'wp_kses' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], 'esc_' ) !== 0 && strpos( $this->tokens[ $stackPtr ]['content'], 'wp_kses' ) !== 0 ) { // Not what we are looking for. return; } $next_token = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $next_token ]['code'] ) { + if ( $this->tokens[ $next_token ]['code'] !== T_OPEN_PARENTHESIS ) { // Not a function call. return; } $next_token = $this->phpcsFile->findNext( Tokens::$emptyTokens, $next_token + 1, null, true ); - if ( T_STRING !== $this->tokens[ $next_token ]['code'] ) { + if ( $this->tokens[ $next_token ]['code'] !== T_STRING ) { // Not what we are looking for. return; } diff --git a/WordPressVIPMinimum/Sniffs/Security/ExitAfterRedirectSniff.php b/WordPressVIPMinimum/Sniffs/Security/ExitAfterRedirectSniff.php index c015d108..5d76976a 100644 --- a/WordPressVIPMinimum/Sniffs/Security/ExitAfterRedirectSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/ExitAfterRedirectSniff.php @@ -36,13 +36,13 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'wp_redirect' !== $this->tokens[ $stackPtr ]['content'] && 'wp_safe_redirect' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== 'wp_redirect' && $this->tokens[ $stackPtr ]['content'] !== 'wp_safe_redirect' ) { return; } $openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { return; } @@ -51,17 +51,17 @@ public function process_token( $stackPtr ) { $message = '`%s()` should almost always be followed by a call to `exit;`.'; $data = [ $this->tokens[ $stackPtr ]['content'] ]; - if ( T_OPEN_CURLY_BRACKET === $this->tokens[ $next_token ]['code'] ) { + if ( $this->tokens[ $next_token ]['code'] === T_OPEN_CURLY_BRACKET ) { $is_exit_in_scope = false; for ( $i = $this->tokens[ $next_token ]['scope_opener']; $i <= $this->tokens[ $next_token ]['scope_closer']; $i++ ) { - if ( T_EXIT === $this->tokens[ $i ]['code'] ) { + if ( $this->tokens[ $i ]['code'] === T_EXIT ) { $is_exit_in_scope = true; } } - if ( false === $is_exit_in_scope ) { + if ( $is_exit_in_scope === false ) { $this->phpcsFile->addError( $message, $stackPtr, 'NoExitInConditional', $data ); } - } elseif ( T_EXIT !== $this->tokens[ $next_token ]['code'] ) { + } elseif ( $this->tokens[ $next_token ]['code'] !== T_EXIT ) { $this->phpcsFile->addError( $message, $stackPtr, 'NoExit', $data ); } } diff --git a/WordPressVIPMinimum/Sniffs/Security/MustacheSniff.php b/WordPressVIPMinimum/Sniffs/Security/MustacheSniff.php index d9c08adf..c6465c2d 100644 --- a/WordPressVIPMinimum/Sniffs/Security/MustacheSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/MustacheSniff.php @@ -47,19 +47,19 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( false !== strpos( $this->tokens[ $stackPtr ]['content'], '{{{' ) || false !== strpos( $this->tokens[ $stackPtr ]['content'], '}}}' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], '{{{' ) !== false || strpos( $this->tokens[ $stackPtr ]['content'], '}}}' ) !== false ) { // Mustache unescaped output notation. $message = 'Found Mustache unescaped output notation: "{{{}}}".'; $this->phpcsFile->addWarning( $message, $stackPtr, 'OutputNotation' ); } - if ( false !== strpos( $this->tokens[ $stackPtr ]['content'], '{{&' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], '{{&' ) !== false ) { // Mustache unescaped variable notation. $message = 'Found Mustache unescape variable notation: "{{&".'; $this->phpcsFile->addWarning( $message, $stackPtr, 'VariableNotation' ); } - if ( false !== strpos( $this->tokens[ $stackPtr ]['content'], '{{=' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], '{{=' ) !== false ) { // Mustache delimiter change. $new_delimiter = trim( str_replace( [ '{{=', '=}}' ], '', substr( $this->tokens[ $stackPtr ]['content'], 0, strpos( $this->tokens[ $stackPtr ]['content'], '=}}' ) + 3 ) ) ); $message = 'Found Mustache delimiter change notation. New delimiter is: %s.'; @@ -67,7 +67,7 @@ public function process_token( $stackPtr ) { $this->phpcsFile->addWarning( $message, $stackPtr, 'DelimiterChange', $data ); } - if ( false !== strpos( $this->tokens[ $stackPtr ]['content'], 'SafeString' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], 'SafeString' ) !== false ) { // Handlebars.js Handlebars.SafeString does not get escaped. $message = 'Found Handlebars.SafeString call which does not get escaped.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'SafeString' ); diff --git a/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php index abe621fe..84278541 100644 --- a/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php @@ -61,8 +61,8 @@ class PHPFilterFunctionsSniff extends AbstractFunctionParameterSniff { * normal file processing. */ public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { - if ( 'filter_input' === $matched_content ) { - if ( 2 === count( $parameters ) ) { + if ( $matched_content === 'filter_input' ) { + if ( count( $parameters ) === 2 ) { $message = 'Missing third parameter for "%s".'; $data = [ $matched_content ]; $this->phpcsFile->addWarning( $message, $stackPtr, 'MissingThirdParameter', $data ); @@ -74,7 +74,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $this->phpcsFile->addWarning( $message, $stackPtr, 'RestrictedFilter', $data ); } } else { - if ( 1 === count( $parameters ) ) { + if ( count( $parameters ) === 1 ) { $message = 'Missing second parameter for "%s".'; $data = [ $matched_content ]; $this->phpcsFile->addWarning( $message, $stackPtr, 'MissingSecondParameter', $data ); diff --git a/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php b/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php index 7209b076..3e9038dc 100644 --- a/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php @@ -47,7 +47,7 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( false === in_array( $this->tokens[ $stackPtr ]['content'], $this->escaping_functions, true ) ) { + if ( in_array( $this->tokens[ $stackPtr ]['content'], $this->escaping_functions, true ) === false ) { return; } @@ -55,24 +55,24 @@ public function process_token( $stackPtr ) { $echo_or_string_concat = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true ); - if ( T_ECHO === $this->tokens[ $echo_or_string_concat ]['code'] ) { + if ( $this->tokens[ $echo_or_string_concat ]['code'] === T_ECHO ) { // Very likely inline HTML with phpcsFile->findPrevious( Tokens::$emptyTokens, $echo_or_string_concat - 1, null, true ); - if ( T_OPEN_TAG !== $this->tokens[ $php_open ]['code'] ) { + if ( $this->tokens[ $php_open ]['code'] !== T_OPEN_TAG ) { return; } $html = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $php_open - 1, null, true ); - if ( T_INLINE_HTML !== $this->tokens[ $html ]['code'] ) { + if ( $this->tokens[ $html ]['code'] !== T_INLINE_HTML ) { return; } - } elseif ( T_STRING_CONCAT === $this->tokens[ $echo_or_string_concat ]['code'] ) { + } elseif ( $this->tokens[ $echo_or_string_concat ]['code'] === T_STRING_CONCAT ) { // Very likely string concatenation mixing strings and functions/variables. $html = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $echo_or_string_concat - 1, null, true ); - if ( T_CONSTANT_ENCAPSED_STRING !== $this->tokens[ $html ]['code'] ) { + if ( $this->tokens[ $html ]['code'] !== T_CONSTANT_ENCAPSED_STRING ) { return; } } else { @@ -82,12 +82,12 @@ public function process_token( $stackPtr ) { $data = [ $function_name ]; - if ( 'esc_url' !== $function_name && $this->is_href_or_src( $this->tokens[ $html ]['content'] ) ) { + if ( $function_name !== 'esc_url' && $this->is_href_or_src( $this->tokens[ $html ]['content'] ) ) { $message = 'Wrong escaping function. href and src attributes should be escaped by `esc_url()`, not by `%s()`.'; $this->phpcsFile->addError( $message, $stackPtr, 'hrefSrcEscUrl', $data ); return; } - if ( 'esc_html' === $function_name && $this->is_html_attr( $this->tokens[ $html ]['content'] ) ) { + if ( $function_name === 'esc_html' && $this->is_html_attr( $this->tokens[ $html ]['content'] ) ) { $message = 'Wrong escaping function. HTML attributes should be escaped by `esc_attr()`, not by `%s()`.'; $this->phpcsFile->addError( $message, $stackPtr, 'htmlAttrNotByEscHTML', $data ); return; @@ -110,7 +110,7 @@ public function is_href_or_src( $content ) { '=\'"', // The tokenizer does some fun stuff when it comes to mixing double and single quotes. '="\'', // The tokenizer does some fun stuff when it comes to mixing double and single quotes. ] as $ending ) { - if ( true === $this->endswith( $content, $attr . $ending ) ) { + if ( $this->endswith( $content, $attr . $ending ) === true ) { $is_href_or_src = true; break; } @@ -134,7 +134,7 @@ public function is_html_attr( $content ) { '=\'"', // The tokenizer does some fun stuff when it comes to mixing double and single quotes. '="\'', // The tokenizer does some fun stuff when it comes to mixing double and single quotes. ] as $ending ) { - if ( true === $this->endswith( $content, $ending ) ) { + if ( $this->endswith( $content, $ending ) === true ) { $is_html_attr = true; break; } diff --git a/WordPressVIPMinimum/Sniffs/Security/StaticStrreplaceSniff.php b/WordPressVIPMinimum/Sniffs/Security/StaticStrreplaceSniff.php index f905a291..09159a07 100644 --- a/WordPressVIPMinimum/Sniffs/Security/StaticStrreplaceSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/StaticStrreplaceSniff.php @@ -36,13 +36,13 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 'str_replace' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== 'str_replace' ) { return; } $openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { return; } @@ -50,9 +50,9 @@ public function process_token( $stackPtr ) { for ( $i = 0; $i < 3; $i++ ) { $param_ptr = $this->phpcsFile->findNext( array_merge( Tokens::$emptyTokens, [ T_COMMA ] ), $next_start_ptr, null, true ); - if ( T_ARRAY === $this->tokens[ $param_ptr ]['code'] ) { + if ( $this->tokens[ $param_ptr ]['code'] === T_ARRAY ) { $openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $param_ptr + 1, null, true ); - if ( T_OPEN_PARENTHESIS !== $this->tokens[ $openBracket ]['code'] ) { + if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) { return; } @@ -60,9 +60,9 @@ public function process_token( $stackPtr ) { $closeBracket = $this->tokens[ $openBracket ]['parenthesis_closer']; $array_item_ptr = $this->phpcsFile->findNext( array_merge( Tokens::$emptyTokens, [ T_COMMA ] ), $openBracket + 1, $closeBracket, true ); - while ( false !== $array_item_ptr ) { + while ( $array_item_ptr !== false ) { - if ( T_CONSTANT_ENCAPSED_STRING !== $this->tokens[ $array_item_ptr ]['code'] ) { + if ( $this->tokens[ $array_item_ptr ]['code'] !== T_CONSTANT_ENCAPSED_STRING ) { return; } $array_item_ptr = $this->phpcsFile->findNext( array_merge( Tokens::$emptyTokens, [ T_COMMA ] ), $array_item_ptr + 1, $closeBracket, true ); @@ -73,7 +73,7 @@ public function process_token( $stackPtr ) { } - if ( T_CONSTANT_ENCAPSED_STRING !== $this->tokens[ $param_ptr ]['code'] ) { + if ( $this->tokens[ $param_ptr ]['code'] !== T_CONSTANT_ENCAPSED_STRING ) { return; } diff --git a/WordPressVIPMinimum/Sniffs/Security/TwigSniff.php b/WordPressVIPMinimum/Sniffs/Security/TwigSniff.php index 937c5005..9c87efa7 100644 --- a/WordPressVIPMinimum/Sniffs/Security/TwigSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/TwigSniff.php @@ -46,13 +46,13 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( 1 === preg_match( '/autoescape\s+false/', $this->tokens[ $stackPtr ]['content'] ) ) { + if ( preg_match( '/autoescape\s+false/', $this->tokens[ $stackPtr ]['content'] ) === 1 ) { // Twig autoescape disabled. $message = 'Found Twig autoescape disabling notation.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'AutoescapeFalse' ); } - if ( 1 === preg_match( '/\|\s*raw/', $this->tokens[ $stackPtr ]['content'] ) ) { + if ( preg_match( '/\|\s*raw/', $this->tokens[ $stackPtr ]['content'] ) === 1 ) { // Twig default unescape filter. $message = 'Found Twig default unescape filter: "|raw".'; $this->phpcsFile->addWarning( $message, $stackPtr, 'RawFound' ); diff --git a/WordPressVIPMinimum/Sniffs/Security/UnderscorejsSniff.php b/WordPressVIPMinimum/Sniffs/Security/UnderscorejsSniff.php index c9f25b00..fb1c0af0 100644 --- a/WordPressVIPMinimum/Sniffs/Security/UnderscorejsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/UnderscorejsSniff.php @@ -47,13 +47,13 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( false !== strpos( $this->tokens[ $stackPtr ]['content'], '<%=' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], '<%=' ) !== false ) { // Underscore.js unescaped output. $message = 'Found Underscore.js unescaped output notation: "<%=".'; $this->phpcsFile->addWarning( $message, $stackPtr, 'OutputNotation' ); } - if ( false !== strpos( $this->tokens[ $stackPtr ]['content'], 'interpolate' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], 'interpolate' ) !== false ) { // Underscore.js unescaped output. $message = 'Found Underscore.js delimiter change notation.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'InterpolateFound' ); diff --git a/WordPressVIPMinimum/Sniffs/Security/VuejsSniff.php b/WordPressVIPMinimum/Sniffs/Security/VuejsSniff.php index c1c5792e..df9ac30d 100644 --- a/WordPressVIPMinimum/Sniffs/Security/VuejsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/VuejsSniff.php @@ -45,7 +45,7 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( false !== strpos( $this->tokens[ $stackPtr ]['content'], 'v-html' ) ) { + if ( strpos( $this->tokens[ $stackPtr ]['content'], 'v-html' ) !== false ) { // Vue autoescape disabled. $message = 'Found Vue.js non-escaped (raw) HTML directive.'; $this->phpcsFile->addWarning( $message, $stackPtr, 'RawHTMLDirectiveFound' ); diff --git a/WordPressVIPMinimum/Sniffs/UserExperience/AdminBarRemovalSniff.php b/WordPressVIPMinimum/Sniffs/UserExperience/AdminBarRemovalSniff.php index 833745d4..6945c2f4 100644 --- a/WordPressVIPMinimum/Sniffs/UserExperience/AdminBarRemovalSniff.php +++ b/WordPressVIPMinimum/Sniffs/UserExperience/AdminBarRemovalSniff.php @@ -160,8 +160,8 @@ public function process_token( $stackPtr ) { $file_name = $this->phpcsFile->getFilename(); $file_extension = substr( strrchr( $file_name, '.' ), 1 ); - if ( 'css' === $file_extension ) { - if ( \T_STYLE === $this->tokens[ $stackPtr ]['code'] ) { + if ( $file_extension === 'css' ) { + if ( $this->tokens[ $stackPtr ]['code'] === \T_STYLE ) { $this->process_css_style( $stackPtr ); return; } @@ -201,25 +201,25 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p switch ( $matched_content ) { case 'show_admin_bar': $error = true; - if ( true === $this->remove_only && 'true' === $parameters[1]['raw'] ) { + if ( $this->remove_only === true && $parameters[1]['raw'] === 'true' ) { $error = false; } break; case 'add_filter': $filter_name = $this->strip_quotes( $parameters[1]['raw'] ); - if ( 'show_admin_bar' !== $filter_name ) { + if ( $filter_name !== 'show_admin_bar' ) { break; } $error = true; - if ( true === $this->remove_only && isset( $parameters[2]['raw'] ) && '__return_true' === $this->strip_quotes( $parameters[2]['raw'] ) ) { + if ( $this->remove_only === true && isset( $parameters[2]['raw'] ) && $this->strip_quotes( $parameters[2]['raw'] ) === '__return_true' ) { $error = false; } break; } - if ( true === $error ) { + if ( $error === true ) { $message = 'Removal of admin bar is prohibited.'; $this->phpcsFile->addError( $message, $stackPtr, 'RemovalDetected' ); } @@ -237,20 +237,20 @@ public function process_text_for_style( $stackPtr, $file_name ) { $content = trim( $this->tokens[ $stackPtr ]['content'] ); // No need to check an empty string. - if ( '' === $content ) { + if ( $content === '' ) { return; } // Are we in a ' ) ) { + if ( $this->in_style[ $file_name ] === true ) { + if ( strpos( $content, '' ) !== false ) { // Make sure we check any content on this line before the closing style tag. $this->in_style[ $file_name ] = false; $content = trim( substr( $content, 0, strpos( $content, '' ) ) ); } - } elseif ( true === $this->has_html_open_tag( 'style', $stackPtr, $content ) ) { + } elseif ( $this->has_html_open_tag( 'style', $stackPtr, $content ) === true ) { // Ok, found a ' ) ) { + if ( strpos( $content, '' ) === false ) { // Make sure we check any content on this line after the opening style tag. $this->in_style[ $file_name ] = true; $content = trim( substr( $content, strpos( $content, 'in_target_selector[ $file_name ] ) { - if ( false !== strpos( $content, '}' ) ) { + if ( $this->in_target_selector[ $file_name ] === true ) { + if ( strpos( $content, '}' ) !== false ) { // Make sure we check any content on this line before the selector closing brace. $this->in_target_selector[ $file_name ] = false; $content = trim( substr( $content, 0, strpos( $content, '}' ) ) ); @@ -276,8 +276,8 @@ public function process_text_for_style( $stackPtr, $file_name ) { // Ok, found a new target selector. $content = ''; - if ( isset( $matches[1] ) && '' !== $matches[1] ) { - if ( false === strpos( $matches[1], '}' ) ) { + if ( isset( $matches[1] ) && $matches[1] !== '' ) { + if ( strpos( $matches[1], '}' ) === false ) { // Make sure we check any content on this line before the closing brace. $this->in_target_selector[ $file_name ] = true; $content = trim( $matches[1] ); @@ -296,19 +296,19 @@ public function process_text_for_style( $stackPtr, $file_name ) { // Now let's do the check for the CSS properties. if ( ! empty( $content ) ) { foreach ( $this->target_css_properties as $property => $requirements ) { - if ( false !== strpos( $content, $property ) ) { + if ( strpos( $content, $property ) !== false ) { $error = true; // Check the value of the CSS property. - if ( true === $this->remove_only && preg_match( '`' . preg_quote( $property, '`' ) . '\s*:\s*(.+?)\s*(?:!important)?;`', $content, $matches ) > 0 ) { + if ( $this->remove_only === true && preg_match( '`' . preg_quote( $property, '`' ) . '\s*:\s*(.+?)\s*(?:!important)?;`', $content, $matches ) > 0 ) { $value = trim( $matches[1] ); $valid = $this->validate_css_property_value( $value, $requirements['type'], $requirements['value'] ); - if ( true === $valid ) { + if ( $valid === true ) { $error = false; } } - if ( true === $error ) { + if ( $error === true ) { $this->addHidingDetectedError( $stackPtr ); } } @@ -333,10 +333,10 @@ protected function process_css_style( $stackPtr ) { // Check if the CSS selector matches. $opener = $this->phpcsFile->findPrevious( \T_OPEN_CURLY_BRACKET, $stackPtr ); - if ( false !== $opener ) { + if ( $opener !== false ) { for ( $i = ( $opener - 1 ); $i >= 0; $i-- ) { if ( isset( Tokens::$commentTokens[ $this->tokens[ $i ]['code'] ] ) - || \T_CLOSE_CURLY_BRACKET === $this->tokens[ $i ]['code'] + || $this->tokens[ $i ]['code'] === \T_CLOSE_CURLY_BRACKET ) { break; } @@ -346,20 +346,20 @@ protected function process_css_style( $stackPtr ) { unset( $i ); foreach ( $this->target_css_selectors as $target_selector ) { - if ( false !== strpos( $selector, $target_selector ) ) { + if ( strpos( $selector, $target_selector ) !== false ) { $error = true; - if ( true === $this->remove_only ) { + if ( $this->remove_only === true ) { // Check the value of the CSS property. $valuePtr = $this->phpcsFile->findNext( [ \T_COLON, \T_WHITESPACE ], $stackPtr + 1, null, true ); $value = $this->tokens[ $valuePtr ]['content']; $valid = $this->validate_css_property_value( $value, $css_property['type'], $css_property['value'] ); - if ( true === $valid ) { + if ( $valid === true ) { $error = false; } } - if ( true === $error ) { + if ( $error === true ) { $this->addHidingDetectedError( $stackPtr ); } } @@ -419,11 +419,11 @@ protected function validate_css_property_value( $value, $compare_type, $compare_ * @return bool True if the string contains an open tag, false otherwise. */ public function has_html_open_tag( $tag_name, $stackPtr = null, $content = null ) { - if ( null === $content && isset( $stackPtr ) ) { + if ( $content === null && isset( $stackPtr ) ) { $content = $this->tokens[ $stackPtr ]['content']; } - return null !== $content && false !== strpos( $content, '<' . $tag_name ); + return $content !== null && strpos( $content, '<' . $tag_name ) !== false; } } diff --git a/WordPressVIPMinimum/Sniffs/Variables/ServerVariablesSniff.php b/WordPressVIPMinimum/Sniffs/Variables/ServerVariablesSniff.php index 946a86a9..03e52e55 100644 --- a/WordPressVIPMinimum/Sniffs/Variables/ServerVariablesSniff.php +++ b/WordPressVIPMinimum/Sniffs/Variables/ServerVariablesSniff.php @@ -54,7 +54,7 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( '$_SERVER' !== $this->tokens[ $stackPtr ]['content'] ) { + if ( $this->tokens[ $stackPtr ]['content'] !== '$_SERVER' ) { // Not the variable we are looking for. return; } diff --git a/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php b/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php index 2627fb59..1296ea31 100644 --- a/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php +++ b/WordPressVIPMinimum/Sniffs/Variables/VariableAnalysisSniff.php @@ -76,14 +76,14 @@ public function register() { */ public function process( File $phpcsFile, $stackPtr ) { - if ( false === $this->thrown['DeprecatedSniff'] ) { + if ( $this->thrown['DeprecatedSniff'] === false ) { $this->thrown['DeprecatedSniff'] = $phpcsFile->addWarning( 'The "WordPressVIPMinimum.Variables.VariableAnalysis" sniff has been deprecated. Use the "VariableAnalysis.CodeAnalysis.VariableAnalysis" sniff instead. Please update your custom ruleset.', 0, 'DeprecatedSniff' ); } - if ( ! empty( $this->exclude ) && false === $this->thrown['FoundPropertyForDeprecatedSniff'] ) { + if ( ! empty( $this->exclude ) && $this->thrown['FoundPropertyForDeprecatedSniff'] === false ) { $this->thrown['FoundPropertyForDeprecatedSniff'] = $phpcsFile->addWarning( 'The "WordPressVIPMinimum.Variables.VariableAnalysis" sniff has been deprecated. Use the "CodeAnalysis.VariableAnalysis" sniff instead. "exclude" property setting found. Please update your custom ruleset.', 0, diff --git a/tests/RulesetTest.php b/tests/RulesetTest.php index 5f45d372..23ea2921 100644 --- a/tests/RulesetTest.php +++ b/tests/RulesetTest.php @@ -91,7 +91,7 @@ public function __construct( $ruleset, $expected = [] ) { // Travis and Windows support. $phpcs_bin = getenv( 'PHPCS_BIN' ); - if ( false === $phpcs_bin ) { + if ( $phpcs_bin === false ) { // phpcs:ignore putenv( 'PHPCS_BIN=phpcs' ); } else { @@ -199,7 +199,7 @@ private function process_violation( $violation ) { * @return bool True if string matches error type. */ private function violation_type_is_error( $violation ) { - return self::ERROR_TYPE === $violation->type; + return $violation->type === self::ERROR_TYPE; } /** @@ -235,12 +235,12 @@ private function add_message_for_line( $line, $message ) { */ private function check_missing_expected_values() { foreach ( $this->expected as $type => $lines ) { - if ( 'messages' === $type ) { + if ( $type === 'messages' ) { continue; } foreach ( $lines as $line_number => $expected_count_of_type_violations ) { - if ( 0 === $expected_count_of_type_violations ) { + if ( $expected_count_of_type_violations === 0 ) { continue; } @@ -261,7 +261,7 @@ private function check_missing_expected_values() { private function check_unexpected_values() { foreach ( [ 'errors', 'warnings' ] as $type ) { foreach ( $this->$type as $line_number => $actual_count_of_type_violations ) { - if ( 0 === $actual_count_of_type_violations ) { + if ( $actual_count_of_type_violations === 0 ) { continue; } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 1e18c0c2..bb063fdc 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -24,15 +24,15 @@ $composerPHPCSPath = dirname( __DIR__ ) . $ds . 'vendor' . $ds . 'squizlabs' . $ds . 'php_codesniffer'; // This may be a Composer install. -if ( false === $phpcsDir && is_dir( $composerPHPCSPath ) ) { +if ( $phpcsDir === false && is_dir( $composerPHPCSPath ) ) { $phpcsDir = $composerPHPCSPath; -} elseif ( false !== $phpcsDir ) { +} elseif ( $phpcsDir !== false ) { // PHPCS in a custom directory. $phpcsDir = realpath( $phpcsDir ); } // Try and load the PHPCS autoloader. -if ( false !== $phpcsDir +if ( $phpcsDir !== false && file_exists( $phpcsDir . $ds . 'autoload.php' ) && file_exists( $phpcsDir . $ds . 'tests' . $ds . 'bootstrap.php' ) ) { From be0fb40df0d213fc34c0c76b32746682b8497d97 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jul 2020 19:42:28 +0200 Subject: [PATCH 28/35] Tests: add code coverage configuration * PHPUnit config: add code coverage configuration. By default, when there is a code coverage configuration and Xdebug is enabled, code coverage will be generated. For now, code coverage is set up for local use with an HTML code coverage report being generated in a `build/logs/` directory. Note: generating code coverage is slow. * Git ignore the `build` directory as created by PHPUnit to store the log files. * Adjust the "normal" test script to not generate code coverage information. * Add a `bin/unit-tests-coverage` to run the unit tests with code coverage enabled. * Add a Composer script to call the `unit-tests-coverage` script. --- .gitignore | 1 + bin/unit-tests | 2 +- bin/unit-tests-coverage | 12 ++++++++++++ composer.json | 1 + phpunit.xml.dist | 29 +++++++++++++++++++++++------ 5 files changed, 38 insertions(+), 7 deletions(-) create mode 100755 bin/unit-tests-coverage diff --git a/.gitignore b/.gitignore index 915feab9..1c6a1b2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +build/ vendor/ composer.lock phpcs.xml diff --git a/bin/unit-tests b/bin/unit-tests index 07a99191..58afa1fd 100755 --- a/bin/unit-tests +++ b/bin/unit-tests @@ -10,4 +10,4 @@ # ./bin/unit-tests # -"$(pwd)/vendor/bin/phpunit" --filter WordPressVIPMinimum "$(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php" +"$(pwd)/vendor/bin/phpunit" --filter WordPressVIPMinimum "$(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php" --no-coverage diff --git a/bin/unit-tests-coverage b/bin/unit-tests-coverage new file mode 100755 index 00000000..c0fdf90d --- /dev/null +++ b/bin/unit-tests-coverage @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# +# Run the unit tests with code coverage. +# +# This ensures that the logic in the VIP sniffs is covered by unit tests. +# +# EXAMPLE TO RUN LOCALLY: +# +# ./bin/unit-tests-coverage +# + +"$(pwd)/vendor/bin/phpunit" --filter WordPressVIPMinimum "$(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php" diff --git a/composer.json b/composer.json index 291e5eee..dd892443 100644 --- a/composer.json +++ b/composer.json @@ -38,6 +38,7 @@ ], "phpcs": "bin/phpcs", "phpunit": "bin/unit-tests", + "coverage": "bin/unit-tests-coverage", "test": [ "@lint", "@ruleset", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 82131e96..aba257c8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,9 +1,26 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.2/phpunit.xsd" + backupGlobals="true" + bootstrap="./tests/bootstrap.php" + beStrictAboutTestsThatDoNotTestAnything="false" + colors="true" + > + + + ./WordPressVIPMinimum/Tests/ + + + + + + ./WordPressVIPMinimum/Sniffs/ + + + + + + + From 03697e03e2c2125dbc5d533109993bd5a5532c88 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jul 2020 22:14:27 +0200 Subject: [PATCH 29/35] Code coverage recording: add @covers tags ... to all unit test files, as well as enable strict coverage recording. --- .../Tests/Classes/DeclarationCompatibilityUnitTest.php | 2 ++ .../Tests/Classes/RestrictedExtendClassesUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Compatibility/ZoninatorUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Constants/ConstantStringUnitTest.php | 2 ++ .../Tests/Constants/RestrictedConstantsUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Files/IncludingFileUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Files/IncludingNonPHPFileUnitTest.php | 2 ++ .../Tests/Functions/CheckReturnValueUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Functions/DynamicCallsUnitTest.php | 2 ++ .../Tests/Functions/RestrictedFunctionsUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Functions/StripTagsUnitTest.php | 2 ++ .../Tests/Hooks/AlwaysReturnInFilterUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Hooks/RestrictedHooksUnitTest.php | 2 ++ .../Tests/JS/DangerouslySetInnerHTMLUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/JS/HTMLExecutingFunctionsUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/JS/InnerHTMLUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/JS/StringConcatUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/JS/StrippingTagsUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/JS/WindowUnitTest.php | 2 ++ .../Tests/Performance/BatcacheWhitelistedParamsUnitTest.php | 2 ++ .../Tests/Performance/CacheValueOverrideUnitTest.php | 2 ++ .../Tests/Performance/FetchingRemoteDataUnitTest.php | 2 ++ .../Tests/Performance/LowExpiryCacheTimeUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Performance/NoPagingUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Performance/OrderByRandUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Performance/RegexpCompareUnitTest.php | 2 ++ .../Tests/Performance/RemoteRequestTimeoutUnitTest.php | 2 ++ .../Tests/Performance/TaxonomyMetaInOptionsUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Performance/WPQueryParamsUnitTest.php | 2 ++ .../Tests/Security/EscapingVoidReturnFunctionsUnitTest.php | 2 ++ .../Tests/Security/ExitAfterRedirectUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Security/MustacheUnitTest.php | 2 ++ .../Tests/Security/PHPFilterFunctionsUnitTest.php | 2 ++ .../Tests/Security/ProperEscapingFunctionUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Security/StaticStrreplaceUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Security/TwigUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Security/UnderscorejsUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Security/VuejsUnitTest.php | 2 ++ .../Tests/UserExperience/AdminBarRemovalUnitTest.php | 2 ++ .../Tests/Variables/RestrictedVariablesUnitTest.php | 2 ++ WordPressVIPMinimum/Tests/Variables/ServerVariablesUnitTest.php | 2 ++ .../Tests/Variables/VariableAnalysisUnitTest.php | 2 ++ phpunit.xml.dist | 1 + 44 files changed, 87 insertions(+) diff --git a/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php b/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php index 6dc5310d..f27507ee 100644 --- a/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php +++ b/WordPressVIPMinimum/Tests/Classes/DeclarationCompatibilityUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the DeclarationCompatibility sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Classes\DeclarationCompatibilitySniff */ class DeclarationCompatibilityUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Classes/RestrictedExtendClassesUnitTest.php b/WordPressVIPMinimum/Tests/Classes/RestrictedExtendClassesUnitTest.php index 543fb7d5..9b28ee37 100644 --- a/WordPressVIPMinimum/Tests/Classes/RestrictedExtendClassesUnitTest.php +++ b/WordPressVIPMinimum/Tests/Classes/RestrictedExtendClassesUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the RestrictedExtendClasses sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Classes\RestrictedExtendClassesSniff */ class RestrictedExtendClassesUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Compatibility/ZoninatorUnitTest.php b/WordPressVIPMinimum/Tests/Compatibility/ZoninatorUnitTest.php index fdec45eb..f3f07049 100644 --- a/WordPressVIPMinimum/Tests/Compatibility/ZoninatorUnitTest.php +++ b/WordPressVIPMinimum/Tests/Compatibility/ZoninatorUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the CheckReturnValue sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Compatibility\ZoninatorSniff */ class ZoninatorUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Constants/ConstantStringUnitTest.php b/WordPressVIPMinimum/Tests/Constants/ConstantStringUnitTest.php index 7d3abc44..9b6b4225 100644 --- a/WordPressVIPMinimum/Tests/Constants/ConstantStringUnitTest.php +++ b/WordPressVIPMinimum/Tests/Constants/ConstantStringUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the ConstantString sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Constants\ConstantStringSniff */ class ConstantStringUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php b/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php index 7999e997..5c109483 100644 --- a/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the ConstantRestrictions sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Constants\RestrictedConstantsSniff */ class RestrictedConstantsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Files/IncludingFileUnitTest.php b/WordPressVIPMinimum/Tests/Files/IncludingFileUnitTest.php index 5957cc5d..3253a83a 100644 --- a/WordPressVIPMinimum/Tests/Files/IncludingFileUnitTest.php +++ b/WordPressVIPMinimum/Tests/Files/IncludingFileUnitTest.php @@ -12,6 +12,8 @@ * Unit test class for the IncludingFile sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Files\IncludingFileSniff */ class IncludingFileUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Files/IncludingNonPHPFileUnitTest.php b/WordPressVIPMinimum/Tests/Files/IncludingNonPHPFileUnitTest.php index 9f0f8de4..ad139cc6 100644 --- a/WordPressVIPMinimum/Tests/Files/IncludingNonPHPFileUnitTest.php +++ b/WordPressVIPMinimum/Tests/Files/IncludingNonPHPFileUnitTest.php @@ -12,6 +12,8 @@ * Unit test class for the IncludingFile sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Files\IncludingNonPHPFileSniff */ class IncludingNonPHPFileUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Functions/CheckReturnValueUnitTest.php b/WordPressVIPMinimum/Tests/Functions/CheckReturnValueUnitTest.php index 2da0d187..1508a7c5 100644 --- a/WordPressVIPMinimum/Tests/Functions/CheckReturnValueUnitTest.php +++ b/WordPressVIPMinimum/Tests/Functions/CheckReturnValueUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the CheckReturnValue sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Functions\CheckReturnValueSniff */ class CheckReturnValueUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Functions/DynamicCallsUnitTest.php b/WordPressVIPMinimum/Tests/Functions/DynamicCallsUnitTest.php index a7318449..98057179 100644 --- a/WordPressVIPMinimum/Tests/Functions/DynamicCallsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Functions/DynamicCallsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the DynamicCalls sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Functions\DynamicCallsSniff */ class DynamicCallsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.php b/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.php index 147c7cfa..493b9270 100644 --- a/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the RestrictedFunctions sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Functions\RestrictedFunctionsSniff */ class RestrictedFunctionsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Functions/StripTagsUnitTest.php b/WordPressVIPMinimum/Tests/Functions/StripTagsUnitTest.php index 462dd983..a95d5e33 100644 --- a/WordPressVIPMinimum/Tests/Functions/StripTagsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Functions/StripTagsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the StripTags sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Functions\StripTagsSniff */ class StripTagsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php b/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php index ee2cd6c8..747e0b83 100644 --- a/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php +++ b/WordPressVIPMinimum/Tests/Hooks/AlwaysReturnInFilterUnitTest.php @@ -12,6 +12,8 @@ * Unit test class for the Hooks/AlwaysReturn sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Hooks\AlwaysReturnInFilterSniff */ class AlwaysReturnInFilterUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php index 02e45189..9b733c15 100644 --- a/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Hooks/PreGetPostsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the PreGetPosts sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Hooks\PreGetPostsSniff */ class PreGetPostsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Hooks/RestrictedHooksUnitTest.php b/WordPressVIPMinimum/Tests/Hooks/RestrictedHooksUnitTest.php index d4ed28e2..de76d873 100644 --- a/WordPressVIPMinimum/Tests/Hooks/RestrictedHooksUnitTest.php +++ b/WordPressVIPMinimum/Tests/Hooks/RestrictedHooksUnitTest.php @@ -14,6 +14,8 @@ * @package VIPCS\WordPressVIPMinimum * * @since 0.4.0 + * + * @covers \WordPressVIPMinimum\Sniffs\Hooks\RestrictedHooksSniff */ class RestrictedHooksUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/JS/DangerouslySetInnerHTMLUnitTest.php b/WordPressVIPMinimum/Tests/JS/DangerouslySetInnerHTMLUnitTest.php index 6dea8c31..f0cfc1dd 100644 --- a/WordPressVIPMinimum/Tests/JS/DangerouslySetInnerHTMLUnitTest.php +++ b/WordPressVIPMinimum/Tests/JS/DangerouslySetInnerHTMLUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the HTML String concatenation in JS sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\JS\DangerouslySetInnerHTMLSniff */ class DangerouslySetInnerHTMLUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/JS/HTMLExecutingFunctionsUnitTest.php b/WordPressVIPMinimum/Tests/JS/HTMLExecutingFunctionsUnitTest.php index 794ec61f..8efb366f 100644 --- a/WordPressVIPMinimum/Tests/JS/HTMLExecutingFunctionsUnitTest.php +++ b/WordPressVIPMinimum/Tests/JS/HTMLExecutingFunctionsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the HTML executing JS functions sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\JS\HTMLExecutingFunctionsSniff */ class HTMLExecutingFunctionsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/JS/InnerHTMLUnitTest.php b/WordPressVIPMinimum/Tests/JS/InnerHTMLUnitTest.php index d51bdf9d..a696a7fe 100644 --- a/WordPressVIPMinimum/Tests/JS/InnerHTMLUnitTest.php +++ b/WordPressVIPMinimum/Tests/JS/InnerHTMLUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the HTML String concatenation in JS sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\JS\InnerHTMLSniff */ class InnerHTMLUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/JS/StringConcatUnitTest.php b/WordPressVIPMinimum/Tests/JS/StringConcatUnitTest.php index 50b87b3c..ac218635 100644 --- a/WordPressVIPMinimum/Tests/JS/StringConcatUnitTest.php +++ b/WordPressVIPMinimum/Tests/JS/StringConcatUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the HTML String concatenation in JS sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\JS\StringConcatSniff */ class StringConcatUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/JS/StrippingTagsUnitTest.php b/WordPressVIPMinimum/Tests/JS/StrippingTagsUnitTest.php index 12494d63..9a27f293 100644 --- a/WordPressVIPMinimum/Tests/JS/StrippingTagsUnitTest.php +++ b/WordPressVIPMinimum/Tests/JS/StrippingTagsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for incorrect HTML tags stripping approach in JS sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\JS\StrippingTagsSniff */ class StrippingTagsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/JS/WindowUnitTest.php b/WordPressVIPMinimum/Tests/JS/WindowUnitTest.php index c93bdae7..3ba5cf36 100644 --- a/WordPressVIPMinimum/Tests/JS/WindowUnitTest.php +++ b/WordPressVIPMinimum/Tests/JS/WindowUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the HTML String concatenation in JS sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\JS\WindowSniff */ class WindowUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/BatcacheWhitelistedParamsUnitTest.php b/WordPressVIPMinimum/Tests/Performance/BatcacheWhitelistedParamsUnitTest.php index 9867a2c0..f1b0897c 100644 --- a/WordPressVIPMinimum/Tests/Performance/BatcacheWhitelistedParamsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/BatcacheWhitelistedParamsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the BatcacheWhitelistedParams sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\BatcacheWhitelistedParamsSniff */ class BatcacheWhitelistedParamsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/CacheValueOverrideUnitTest.php b/WordPressVIPMinimum/Tests/Performance/CacheValueOverrideUnitTest.php index 91ba18ed..62c0aa1a 100644 --- a/WordPressVIPMinimum/Tests/Performance/CacheValueOverrideUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/CacheValueOverrideUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the CacheValueOverride sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\CacheValueOverrideSniff */ class CacheValueOverrideUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php b/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php index fa4a8551..d5c94d9c 100644 --- a/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/FetchingRemoteDataUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the ExitAfterRedirect sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\FetchingRemoteDataSniff */ class FetchingRemoteDataUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/LowExpiryCacheTimeUnitTest.php b/WordPressVIPMinimum/Tests/Performance/LowExpiryCacheTimeUnitTest.php index 6befe13e..81a4da60 100644 --- a/WordPressVIPMinimum/Tests/Performance/LowExpiryCacheTimeUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/LowExpiryCacheTimeUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the LowExpiryCacheTime sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\LowExpiryCacheTimeSniff */ class LowExpiryCacheTimeUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/NoPagingUnitTest.php b/WordPressVIPMinimum/Tests/Performance/NoPagingUnitTest.php index b37f11c2..58522936 100644 --- a/WordPressVIPMinimum/Tests/Performance/NoPagingUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/NoPagingUnitTest.php @@ -15,6 +15,8 @@ * @package VIPCS\WordPressVIPMinimum * * @since 0.5.0 + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\NoPagingSniff */ class NoPagingUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/OrderByRandUnitTest.php b/WordPressVIPMinimum/Tests/Performance/OrderByRandUnitTest.php index f17cd8be..2192a44f 100644 --- a/WordPressVIPMinimum/Tests/Performance/OrderByRandUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/OrderByRandUnitTest.php @@ -15,6 +15,8 @@ * @package VIPCS\WordPressVIPMinimum * * @since 0.5.0 + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\OrderByRandSniff */ class OrderByRandUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/RegexpCompareUnitTest.php b/WordPressVIPMinimum/Tests/Performance/RegexpCompareUnitTest.php index 0aa1c004..a647a605 100644 --- a/WordPressVIPMinimum/Tests/Performance/RegexpCompareUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/RegexpCompareUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the RegexpCompare sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\RegexpCompareSniff */ class RegexpCompareUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/RemoteRequestTimeoutUnitTest.php b/WordPressVIPMinimum/Tests/Performance/RemoteRequestTimeoutUnitTest.php index 49c7a2e7..46586bc1 100644 --- a/WordPressVIPMinimum/Tests/Performance/RemoteRequestTimeoutUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/RemoteRequestTimeoutUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the RemoteRequestTimeout sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\RemoteRequestTimeoutSniff */ class RemoteRequestTimeoutUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/TaxonomyMetaInOptionsUnitTest.php b/WordPressVIPMinimum/Tests/Performance/TaxonomyMetaInOptionsUnitTest.php index af1e0c5d..215fc19d 100644 --- a/WordPressVIPMinimum/Tests/Performance/TaxonomyMetaInOptionsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/TaxonomyMetaInOptionsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the TaxonomyMetaInOptions sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\TaxonomyMetaInOptionsSniff */ class TaxonomyMetaInOptionsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Performance/WPQueryParamsUnitTest.php b/WordPressVIPMinimum/Tests/Performance/WPQueryParamsUnitTest.php index d63892f7..1ccbfc4c 100644 --- a/WordPressVIPMinimum/Tests/Performance/WPQueryParamsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Performance/WPQueryParamsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the WP_Query params sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Performance\WPQueryParamsSniff */ class WPQueryParamsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/EscapingVoidReturnFunctionsUnitTest.php b/WordPressVIPMinimum/Tests/Security/EscapingVoidReturnFunctionsUnitTest.php index 0dee7479..355340e2 100644 --- a/WordPressVIPMinimum/Tests/Security/EscapingVoidReturnFunctionsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/EscapingVoidReturnFunctionsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the EscapingVoidReturnFunctions sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\EscapingVoidReturnFunctionsSniff */ class EscapingVoidReturnFunctionsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/ExitAfterRedirectUnitTest.php b/WordPressVIPMinimum/Tests/Security/ExitAfterRedirectUnitTest.php index 053d9ebe..b5aff55c 100644 --- a/WordPressVIPMinimum/Tests/Security/ExitAfterRedirectUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/ExitAfterRedirectUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the ExitAfterRedirect sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\ExitAfterRedirectSniff */ class ExitAfterRedirectUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/MustacheUnitTest.php b/WordPressVIPMinimum/Tests/Security/MustacheUnitTest.php index d7f38041..1d68d752 100644 --- a/WordPressVIPMinimum/Tests/Security/MustacheUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/MustacheUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the unescaped output in Mustache templating engine. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\MustacheSniff */ class MustacheUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php index 1d908a4d..05e91e52 100644 --- a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the WP_Query params sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\PHPFilterFunctionsSniff */ class PHPFilterFunctionsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php b/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php index 8fa5dd4e..ed63adcf 100644 --- a/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the ProperEscapingFunction sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\ProperEscapingFunctionSniff */ class ProperEscapingFunctionUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/StaticStrreplaceUnitTest.php b/WordPressVIPMinimum/Tests/Security/StaticStrreplaceUnitTest.php index cc3ed4e6..6006601f 100644 --- a/WordPressVIPMinimum/Tests/Security/StaticStrreplaceUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/StaticStrreplaceUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the StaticStrreplace sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\StaticStrreplaceSniff */ class StaticStrreplaceUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/TwigUnitTest.php b/WordPressVIPMinimum/Tests/Security/TwigUnitTest.php index 19989225..4d4632ae 100644 --- a/WordPressVIPMinimum/Tests/Security/TwigUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/TwigUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the unescaped output in Twig templating engine. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\TwigSniff */ class TwigUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/UnderscorejsUnitTest.php b/WordPressVIPMinimum/Tests/Security/UnderscorejsUnitTest.php index 29b88003..1043c3e8 100644 --- a/WordPressVIPMinimum/Tests/Security/UnderscorejsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/UnderscorejsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the unescaped output in Underscore.js templating engine. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\UnderscorejsSniff */ class UnderscorejsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Security/VuejsUnitTest.php b/WordPressVIPMinimum/Tests/Security/VuejsUnitTest.php index 7979c7a5..1222b57f 100644 --- a/WordPressVIPMinimum/Tests/Security/VuejsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/VuejsUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the unescaped output in Vue.js templating engine. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Security\VuejsSniff */ class VuejsUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/UserExperience/AdminBarRemovalUnitTest.php b/WordPressVIPMinimum/Tests/UserExperience/AdminBarRemovalUnitTest.php index 5e427e36..7eefb77f 100644 --- a/WordPressVIPMinimum/Tests/UserExperience/AdminBarRemovalUnitTest.php +++ b/WordPressVIPMinimum/Tests/UserExperience/AdminBarRemovalUnitTest.php @@ -15,6 +15,8 @@ * @package VIPCS\WordPressVIPMinimum * * @since 0.5.0 + * + * @covers \WordPressVIPMinimum\Sniffs\UserExperience\AdminBarRemovalSniff */ class AdminBarRemovalUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php index 37ef4079..487c1ee0 100644 --- a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php +++ b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php @@ -16,6 +16,8 @@ * * @since 0.3.0 * @since 0.13.0 Class name changed: this class is now namespaced. + * + * @covers \WordPressVIPMinimum\Sniffs\Variables\RestrictedVariablesSniff */ class RestrictedVariablesUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Variables/ServerVariablesUnitTest.php b/WordPressVIPMinimum/Tests/Variables/ServerVariablesUnitTest.php index 66579128..862efebd 100644 --- a/WordPressVIPMinimum/Tests/Variables/ServerVariablesUnitTest.php +++ b/WordPressVIPMinimum/Tests/Variables/ServerVariablesUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the Variable Analysis sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Variables\ServerVariablesSniff */ class ServerVariablesUnitTest extends AbstractSniffUnitTest { diff --git a/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php b/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php index 44fd0aba..34a9b34d 100644 --- a/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php +++ b/WordPressVIPMinimum/Tests/Variables/VariableAnalysisUnitTest.php @@ -13,6 +13,8 @@ * Unit test class for the Variable Analysis sniff. * * @package VIPCS\WordPressVIPMinimum + * + * @covers \WordPressVIPMinimum\Sniffs\Variables\VariableAnalysisSniff */ class VariableAnalysisUnitTest extends AbstractSniffUnitTest { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index aba257c8..82c63521 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,6 +5,7 @@ backupGlobals="true" bootstrap="./tests/bootstrap.php" beStrictAboutTestsThatDoNotTestAnything="false" + forceCoversAnnotation="true" colors="true" > From 2e141c1c765157dacd016ae06211040bdd248d0c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 29 Jul 2020 13:00:28 +0200 Subject: [PATCH 30/35] Test scripts: add ability to pass additional command line arguments --- bin/unit-tests | 8 +++++++- bin/unit-tests-coverage | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/bin/unit-tests b/bin/unit-tests index 58afa1fd..adc03b12 100755 --- a/bin/unit-tests +++ b/bin/unit-tests @@ -9,5 +9,11 @@ # # ./bin/unit-tests # +# The script allows to pass additional PHPUnit CLI arguments. +# For instance, if you only want to run the tests for one particular sniff, +# use the following, replacing "SniffName" with the name of the target sniff: +# +# ./bin/unit-tests --filter SniffName +# -"$(pwd)/vendor/bin/phpunit" --filter WordPressVIPMinimum "$(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php" --no-coverage +"$(pwd)/vendor/bin/phpunit" --filter WordPressVIPMinimum "$(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php" --no-coverage $@ diff --git a/bin/unit-tests-coverage b/bin/unit-tests-coverage index c0fdf90d..89026123 100755 --- a/bin/unit-tests-coverage +++ b/bin/unit-tests-coverage @@ -8,5 +8,12 @@ # # ./bin/unit-tests-coverage # +# The script allows to pass additional PHPUnit CLI arguments. +# For instance, if you only want to run the tests with code coverage for one +# particular sniff, use the following, replacing "SniffName" with the name +# of the target sniff: +# +# ./bin/unit-tests-coverage --filter SniffName +# -"$(pwd)/vendor/bin/phpunit" --filter WordPressVIPMinimum "$(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php" +"$(pwd)/vendor/bin/phpunit" --filter WordPressVIPMinimum "$(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php" $@ From 307db72e72246284a2945b13b5b8ec138e5e6331 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Sat, 29 Aug 2020 11:14:30 +0100 Subject: [PATCH 31/35] Composer: Change minimum stability to stable We don't require or require-dev any packages that are not stable, so no need to continue allowing RC at this time. Fixes #562. --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index dd892443..9c52020c 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,6 @@ "suggest": { "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will manage the PHPCS 'installed_paths' automatically." }, - "minimum-stability": "RC", "scripts": { "install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", "ruleset": "bin/ruleset-tests", From 6d0a6f1ba3df7a89c086e072c4cfe4de069a594c Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Sat, 29 Aug 2020 12:49:28 +0100 Subject: [PATCH 32/35] ProperEscaping: Fix message for action attribute Recognise that a form `action` attribute expects to have a URL value, and therefore expected to be escaped with `esc_url()`, rather than `esc_attr()`. Fixes #554 --- .../Security/ProperEscapingFunctionSniff.php | 22 +++++++++---------- .../ProperEscapingFunctionUnitTest.inc | 6 ++++- .../ProperEscapingFunctionUnitTest.php | 1 + 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php b/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php index 3e9038dc..f94abdf2 100644 --- a/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/ProperEscapingFunctionSniff.php @@ -82,8 +82,8 @@ public function process_token( $stackPtr ) { $data = [ $function_name ]; - if ( $function_name !== 'esc_url' && $this->is_href_or_src( $this->tokens[ $html ]['content'] ) ) { - $message = 'Wrong escaping function. href and src attributes should be escaped by `esc_url()`, not by `%s()`.'; + if ( $function_name !== 'esc_url' && $this->attr_expects_url( $this->tokens[ $html ]['content'] ) ) { + $message = 'Wrong escaping function. href, src, and action attributes should be escaped by `esc_url()`, not by `%s()`.'; $this->phpcsFile->addError( $message, $stackPtr, 'hrefSrcEscUrl', $data ); return; } @@ -95,15 +95,15 @@ public function process_token( $stackPtr ) { } /** - * Tests whether provided string ends with open src or href attribute. + * Tests whether provided string ends with open attribute which expects a URL value. * - * @param string $content Haystack in which we look for an open src or href attribute. + * @param string $content Haystack in which we look for an open attribute which exects a URL value. * - * @return bool True if string ends with open src or href attribute. + * @return bool True if string ends with open attribute which exects a URL value. */ - public function is_href_or_src( $content ) { - $is_href_or_src = false; - foreach ( [ 'href', 'src', 'url' ] as $attr ) { + public function attr_expects_url( $content ) { + $attr_expects_url = false; + foreach ( [ 'href', 'src', 'url', 'action' ] as $attr ) { foreach ( [ '="', "='", @@ -111,16 +111,16 @@ public function is_href_or_src( $content ) { '="\'', // The tokenizer does some fun stuff when it comes to mixing double and single quotes. ] as $ending ) { if ( $this->endswith( $content, $attr . $ending ) === true ) { - $is_href_or_src = true; + $attr_expects_url = true; break; } } } - return $is_href_or_src; + return $attr_expects_url; } /** - * Tests, whether provided string ends with open HMTL attribute. + * Tests whether provided string ends with open HMTL attribute. * * @param string $content Haystack in which we look for open HTML attribute. * diff --git a/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.inc b/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.inc index 9f801ace..415ebd90 100644 --- a/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.inc @@ -34,4 +34,8 @@ echo ''; // echo 'data-param-url="' . esc_url( $share_url ) . '"'; // OK. -echo 'data-param-url="' . esc_html( $share_url ) . '"'; // NOK. \ No newline at end of file +echo 'data-param-url="' . esc_html( $share_url ) . '"'; // NOK. + +?> + +
diff --git a/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php b/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php index ed63adcf..bf47a11e 100644 --- a/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/ProperEscapingFunctionUnitTest.php @@ -33,6 +33,7 @@ public function getErrorList() { 23 => 1, 33 => 1, 37 => 1, + 41 => 1, ]; } From 806992218ae877136c1aa5a06254cf2c47a25602 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Mon, 31 Aug 2020 11:37:45 +0100 Subject: [PATCH 33/35] Docs: Update notes for releasing --- .github/CONTRIBUTING.md | 15 +++++++++++++++ .github/ISSUE_TEMPLATE/release-template.md | 8 ++++---- README.md | 5 ++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index cae4b7ef..f652edc9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -193,3 +193,18 @@ An example where it might not would be when a ruleset references a local sniff o The `composer test` or `composer ruleset` commands run the `ruleset-test.php` files (one for each standard), which internally run `phpcs` against the "dirty" test files (`ruleset-test.inc`), and looks out for a known number of errors, warnings, and messages on each line. This is then compared against the expected errors, warnings and messages to see if there are any missing or unexpected violations or difference in messages. When adding or changing a sniff, the ruleset test files should be updated to match. + +## Releases + +- In a `changelog/x.y.z` branch off of `develop`, update the `CHANGELOG.md` with a list of all of the changes following the keepachangelog.com format. Include PR references and GitHub username props. +- Create a PR of `develop` <-- `changelog/x.y.z`, but do not merge until ready to release. +- Create a PR of `master` <-- `develop`, and copy-paste the [`release-template.md`](https://github.com/Automattic/VIP-Coding-Standards/blob/develop/.github/ISSUE_TEMPLATE/release-template.md) contents. +- When ready to release, merge the change log PR into `develop`, then merge the `develop` into `master` PR. +- Tag the commit in `master` with the appropriate version number. Ideally, have it signed. +- Close the current milestone. +- Open a new milestone for the next release. +- If any open PRs/issues which were milestoned for this release do not make it into the release, update their milestone. +- Write a Lobby post to inform VIP customers about the release, including the date when the Review Bot will be updated (usually about 1.5 weeks after the VIPCS release). +- Write an internal P2 post. +- Open a PR to update the [Review Bot dependencies](https://github.com/Automattic/vip-go-ci/blob/master/tools-init.sh). + diff --git a/.github/ISSUE_TEMPLATE/release-template.md b/.github/ISSUE_TEMPLATE/release-template.md index 534e45e4..3d1347ce 100644 --- a/.github/ISSUE_TEMPLATE/release-template.md +++ b/.github/ISSUE_TEMPLATE/release-template.md @@ -9,13 +9,13 @@ assignees: GaryJones, rebeccahum ⚠️ DO NOT MERGE (YET) ⚠️ -Please do add approvals if you agree. +[Remaining work for this Milestone](https://github.com/Automattic/VIP-Coding-Standards/milestone/X) -PR for tracking changes for the 2.x.y release. Target release date: DOW DD MMMM. +PR for tracking changes for the X.Y.Z release. Target release date: DOW DD MMMM YYYY. -- [ ] Add changelog for this release. +- [ ] Add change log for this release: PR #XXX - [ ] Merge this PR. -- [ ] Add release tag against `master`. +- [ ] Add signed release tag against `master`. - [ ] Close the current milestone. - [ ] Open a new milestone for the next release. - [ ] If any open PRs/issues which were milestoned for this release do not make it into the release, update their milestone. diff --git a/README.md b/README.md index 01001cd0..064eabe4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # VIP Coding Standards -This project contains [PHP_CodeSniffer (PHPCS) sniffs and rulesets](https://github.com/squizlabs/PHP_CodeSniffer) to validate code developed for [WordPress.com VIP](https://wpvip.com/). +This project contains [PHP_CodeSniffer (PHPCS) sniffs and rulesets](https://github.com/squizlabs/PHP_CodeSniffer) to validate code developed for [WordPress VIP](https://wpvip.com/). This project contains two rulesets: @@ -25,14 +25,13 @@ Go to https://wpvip.com/documentation/phpcs-review-feedback/ to learn about why This will install the latest compatible versions of PHPCS and WPCS. - Please refer to the [installation instructions for installing PHP_CodeSniffer for WordPress.com VIP](https://wpvip.com/documentation/how-to-install-php-code-sniffer-for-wordpress-com-vip/) for more details. We recommend the [PHP_CodeSniffer Standards Composer Installer Plugin](https://github.com/Dealerdirect/phpcodesniffer-composer-installer), which handles the registration of all of the installed standards, so there is no need to set the `installed_paths` config value manually, for single or multiple standards. Alternatively, you should register the standard to PHPCS by appending the VIPCS directory to the end of the installed paths. e.g. -`phpcs --config-set installed_paths /path/to/wpcsstandard,path/to/vipcsstandard,etc.` +`phpcs --config-set installed_paths /path/to/wpcsstandard,path/to/vipcsstandard` ## Contribution From 645f7f70ee52400dfabc0bca0cf210ce64b3752d Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Fri, 4 Sep 2020 11:27:37 +0100 Subject: [PATCH 34/35] Docs: Add comparisons and props for old versions --- CHANGELOG.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d82cf157..952b2441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), Bumps requirements to PHPCS 3.5.5+ and WPCS 2.3.0+. +Props: GaryJones, jenkoian, kevinfodness, rebeccahum. + ### Added - `get_page_by_path()` restricted function warning, to suggest `wpcom_vip_get_page_by_path()` function. @@ -41,6 +43,8 @@ This release switches from having WPCS `1.*` as a dependency, to WPCS `2.*`. It The sniffs in WPCS `2.*` are more accurate, so you may see new violations there weren't being reported before, and a reduction in violations for false positives. +Props: GaryJones, hanifn, paulscreiber, rebeccahum, tomjn. + ### Added - Switch to using WPCS `2.*`. @@ -88,6 +92,8 @@ This release contains many breaking changes. It requires PHP `>= 5.6`, PHPCS `3.2.3+`, and WPCS `1.*`. It does not work with WPCS `2.*`. +Props: GaryJones, rebeccahum, whyisjake, WPprodigy. + ### Reorganisation and Renaming The sniffs in VIPCS have been reorganised into different categories, with new sniff names and new violation codes. The changes are detailed in the table below. If you reference any of the old violations in your custom ruleset (to change severity, type, or message), or with `// phpcs:ignore` or `// phpcs:disable`, you will need to updates these references to the new violation codes. @@ -345,10 +351,12 @@ The sniffs in VIPCS have been reorganised into different categories, with new sn - Silence `WordPress.WP.AlternativeFunctions.file_system_read_fwrite` and `WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents` since we have `WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_*`. - Silence Short Echo tags on `WordPress-VIP-Go`. -## 0.4.0 - 2018-12-19 +## [0.4.0] - 2018-12-19 This release contains breaking changes. +Props: GaryJones, nickdaugherty, rebeccahum, tomjn. + ### Added - `WordPressVIPMinimum.Cache.LowExpiryCacheTime` sniff. - `WordPressVIPMinimum.Classes.RestrictedExtendedClasses` sniff, for `WP_CLI_Command`. @@ -398,6 +406,52 @@ This release contains breaking changes. - `wpcom_vip_get_page_by_path` from `WordPressVIPMinimum.VIP.RestrictedFunctions` - Version check for PHP 7 or less in `WordPressVIPMinimum.Variables.VariableAnalysis` unit test since tests are not failing anymore. +## [0.3.1] - 2018-12-04 + +Originally tagged as 0.2.5. + +Props: emrikol, GaryJones, gudmdharalds, mikeyarce, nickdaugherty, paulschreiber, rebeccahum, sboisvert, tomjn. + +## [0.3.0] - 2018-08-15 + +Props: BrookeDot, david-binda, GaryJones, gudmdharalds, rebeccahum, sboisvert, tomjn, uxcitizen. + +## [0.2.4] - 2018-07-18 + +Props: david-binda, sboisvert, tessneedham, trepmal. + +## [0.2.3] - 2018-03-29 + +Props: david-binda, jacklenox, pyronaur, sboisvert, trepmal, vaurdan. + +## [0.2.2] - 2018-01-19 + +Props: david-binda. + +## [0.2.1] - 2017-12-01 + +Props: david-binda, philipjohn, tomjn. + +## [0.2.0] - 2017-08-15 + +Props: david-binda. + +## [0.1.0] - 2017-08-14 + +Initial release. + +Props: david-binda, pkevan. + + [2.1.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/2.0.0...2.1.0 [2.0.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/1.0.0...2.0.0 [1.0.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/0.4.0...1.0.0 +[0.4.0]: https://github.com/automattic/vip-coding-standards/compare/0.3.1...0.4.0 +[0.3.1]: https://github.com/automattic/vip-coding-standards/compare/0.3.0...0.3.1 +[0.3.0]: https://github.com/automattic/vip-coding-standards/compare/0.2.4...0.3.0 +[0.2.4]: https://github.com/automattic/vip-coding-standards/compare/0.2.3...0.2.4 +[0.2.3]: https://github.com/automattic/vip-coding-standards/compare/0.2.2...0.2.3 +[0.2.2]: https://github.com/automattic/vip-coding-standards/compare/0.2.1...0.2.2 +[0.2.1]: https://github.com/automattic/vip-coding-standards/compare/0.2.0...0.2.1 +[0.2.0]: https://github.com/automattic/vip-coding-standards/compare/0.1.0...0.2.0 +[0.1.0]: https://github.com/automattic/vip-coding-standards/compare/f0e821c0b91f7e5b3850c5ae7bfab4f38d24e406...0.1.0 From 0bb1580712321e2585b4397f0e33c755c6b2a80d Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Sat, 29 Aug 2020 12:56:56 +0100 Subject: [PATCH 35/35] 2.2.0 change log --- CHANGELOG.md | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 952b2441..70a2051b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,46 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.2.0] - 2020-09-09 + +Props: GaryJones, jrfnl, rebeccahum. + +Technically, there's a breaking change due to the use of the VariableAnalysis package over the previous sniff. If you have `WordPressVIPMinimum.Variables.Variables` references in your PHPCS config file or in inline ignore comments, then these will need to be updated to `VariableAnalysis.CodeAnalysis.VariableAnalysis`. + +### Added +- [#494](https://github.com/Automattic/VIP-Coding-Standards/pull/494): `.gitattributes` file. +- [#495](https://github.com/Automattic/VIP-Coding-Standards/pull/495): `CODEOWNERS` file. +- [#450](https://github.com/Automattic/VIP-Coding-Standards/pull/450): [VariableAnalysis](https://github.com/sirbrillig/phpcs-variable-analysis/) package. +- [#560](https://github.com/Automattic/VIP-Coding-Standards/pull/560): Allow checking test code coverage. +- [#579](https://github.com/Automattic/VIP-Coding-Standards/pull/560): Docs: Add comparisons and props to change log for old versions. + +### Changed +- [#500](https://github.com/Automattic/VIP-Coding-Standards/pull/500): Travis: change from "trusty" to "xenial". +- [#501](https://github.com/Automattic/VIP-Coding-Standards/pull/501): Move and improve `CONTRIBUTING.md`. +- [#502](https://github.com/Automattic/VIP-Coding-Standards/pull/502): CS Ruleset: minor tweaks. +- [#508](https://github.com/Automattic/VIP-Coding-Standards/pull/508): RulesetTest: don't use the system default version of PHP. +- [#558](https://github.com/Automattic/VIP-Coding-Standards/pull/558): Test bootstrap: various minor tweaks. +- [#571](https://github.com/Automattic/VIP-Coding-Standards/pull/571): CS: change yoda conditions to non-yoda. +- [#573](https://github.com/Automattic/VIP-Coding-Standards/pull/573): Composer: Change minimum stability to stable. + +### Fixed +- [#503](https://github.com/Automattic/VIP-Coding-Standards/pull/503): RulesetTest, fix compatibility with Windows. +- [#504](https://github.com/Automattic/VIP-Coding-Standards/pull/504): RulesetTest: fail the build on failing ruleset tests, fix the failing ruleset test, and fix the test script to handle 0 values. +- [#505](https://github.com/Automattic/VIP-Coding-Standards/pull/505): DeclarationCompatibility: fix incorrect signature check for `Walker::walk()`. +- [#509](https://github.com/Automattic/VIP-Coding-Standards/pull/509): RulesetTest: Revert #485 and fix one of the three causes properly. +- [#559](https://github.com/Automattic/VIP-Coding-Standards/pull/559): Variables/RestrictedVariables: fix namespace of unit test file, fix the test. +- [#561](https://github.com/Automattic/VIP-Coding-Standards/pull/561): Functions/RestrictedFunctions: fix false positive on class instantiation. +- [#563](https://github.com/Automattic/VIP-Coding-Standards/pull/563): Hooks/AlwaysReturnInFilter: add support for hook-ins using short arrays. +- [#564](https://github.com/Automattic/VIP-Coding-Standards/pull/564): Hooks/PreGetPosts: add support for hook-ins using short arrays. +- [#565](https://github.com/Automattic/VIP-Coding-Standards/pull/565): PreGetPosts: improve the `isEarlyMainQueryCheck()` method. +- [#566](https://github.com/Automattic/VIP-Coding-Standards/pull/566): RestrictedFunctions: fix false negative - functions in `config_settings` would never match. +- [#569](https://github.com/Automattic/VIP-Coding-Standards/pull/569): RestrictedVariables: don't report on "use" in `isset()`. +- [#575](https://github.com/Automattic/VIP-Coding-Standards/pull/575): ProperEscaping: Fix message for action attribute. +- [#576](https://github.com/Automattic/VIP-Coding-Standards/pull/576): Docs: Update notes for releasing. + +### Deprecated +- [#450](https://github.com/Automattic/VIP-Coding-Standards/pull/450): Deprecate Variables/VariableAnalysisSniff. Will be removed in the next major release. + ## [2.1.0] - 2020-07-07 Bumps requirements to PHPCS 3.5.5+ and WPCS 2.3.0+. @@ -11,7 +51,6 @@ Bumps requirements to PHPCS 3.5.5+ and WPCS 2.3.0+. Props: GaryJones, jenkoian, kevinfodness, rebeccahum. ### Added - - `get_page_by_path()` restricted function warning, to suggest `wpcom_vip_get_page_by_path()` function. - `stats_get_csv()` restricted function error, since this is a Jetpack-only function. - Expanded list of HTMLExecutingFunctions to include `after`, `appendTo`, `before`, `insertAfter`, `insertBefore`, `prepend`, `prependTo`, `replaceAll` and `replaceWith`. @@ -19,7 +58,6 @@ Props: GaryJones, jenkoian, kevinfodness, rebeccahum. - PHP 8 nightly testing. ### Changed - - Expand message for `wp_remote_get()` usage. - Downgrade `append()` usage violation from Error to Warning for VIP Go, to be consistent with the other HTMLExecutingFunctions. - Downgrade AdminBarRemoval sniff from Error to Warning for VIP Go. @@ -28,12 +66,10 @@ Props: GaryJones, jenkoian, kevinfodness, rebeccahum. - Update issue templates. ### Fixed - - Use new `WordPress.DateTime.RestrictedFunctions` sniff instead of deprecated `WordPress.WP.TimezoneChange`. - Fixed warnings and information items in Travis. ### Removed - - `get_super_admins()` restricted function rule for VIP Go. - `WordPressVIPMinimum.VersionControl.MergeConflict` sniff in favour of `Generic.VersionControl.GitMergeConflict`. @@ -46,7 +82,6 @@ The sniffs in WPCS `2.*` are more accurate, so you may see new violations there Props: GaryJones, hanifn, paulscreiber, rebeccahum, tomjn. ### Added - - Switch to using WPCS `2.*`. - Remove reference to WPCS's `PHPAliases.php`. - Remove WPCS `1.*`'s `WordPress.VIP` references from rulesets. @@ -57,7 +92,6 @@ Props: GaryJones, hanifn, paulscreiber, rebeccahum, tomjn. - Update `DiscouragedPHPFunctions` group exclusion in `WordPressVIPMinimum` ruleset. ### Changed - - Downgrade use of file operation functions from Error to Warning: - `delete` - `file_put_contents` @@ -83,7 +117,6 @@ Props: GaryJones, hanifn, paulscreiber, rebeccahum, tomjn. - Switch development to a `git-flow` workflow. ## Fixed - - Fixed CS violations in VIPCS code. ## [1.0.0] - 2019-04-24 @@ -95,7 +128,6 @@ It requires PHP `>= 5.6`, PHPCS `3.2.3+`, and WPCS `1.*`. It does not work with Props: GaryJones, rebeccahum, whyisjake, WPprodigy. ### Reorganisation and Renaming - The sniffs in VIPCS have been reorganised into different categories, with new sniff names and new violation codes. The changes are detailed in the table below. If you reference any of the old violations in your custom ruleset (to change severity, type, or message), or with `// phpcs:ignore` or `// phpcs:disable`, you will need to updates these references to the new violation codes. | Original Violation | New Violation | @@ -216,7 +248,6 @@ The sniffs in VIPCS have been reorganised into different categories, with new sn | `WordPressVIPMinimum.VIP.WPQueryParams.post__not_in` | `WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn` | ### Added - - New violations: - `WordPressVIPMinimum.Functions.RestrictedFunctions.chmod_chgrp` - `WordPressVIPMinimum.Functions.RestrictedFunctions.chmod_chown` @@ -443,6 +474,7 @@ Initial release. Props: david-binda, pkevan. +[2.2.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/2.1.0...2.2.0 [2.1.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/2.0.0...2.1.0 [2.0.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/1.0.0...2.0.0 [1.0.0]: https://github.com/Automattic/VIP-Coding-Standards/compare/0.4.0...1.0.0