From 50ff813a25c4e3cf594bb23fde7a8ada273c7d7f Mon Sep 17 00:00:00 2001 From: JDGrimes Date: Thu, 21 Dec 2017 11:22:41 -0500 Subject: [PATCH 001/822] WP.AlternativeFunctions: Order filesystem function list alphabetically Will make it easier to see changes. --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index e96d41a557..095bd6b851 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -72,15 +72,15 @@ public function getGroups() { 'type' => 'warning', 'message' => 'File operations should use WP_Filesystem methods instead of direct PHP filesystem calls. Found: %s()', 'functions' => array( - 'readfile', - 'fopen', - 'fsockopen', - 'pfsockopen', 'fclose', + 'file_get_contents', + 'file_put_contents', + 'fopen', 'fread', + 'fsockopen', 'fwrite', - 'file_put_contents', - 'file_get_contents', + 'pfsockopen', + 'readfile', ), ), From d3b358637e896f53522fb23c00fed93adf42e99e Mon Sep 17 00:00:00 2001 From: JDGrimes Date: Thu, 21 Dec 2017 11:28:10 -0500 Subject: [PATCH 002/822] WP.AlternativeFunctions: Add more functions to filesystem functions list These functions were in the `VIP.FileSystemWritesDisallowed` sniff, and it seemed like a good idea to add them here as well. --- .../Sniffs/WP/AlternativeFunctionsSniff.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index 095bd6b851..2366cb83a2 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -72,15 +72,35 @@ public function getGroups() { 'type' => 'warning', 'message' => 'File operations should use WP_Filesystem methods instead of direct PHP filesystem calls. Found: %s()', 'functions' => array( + 'chgrp', + 'chmod', + 'chown', + 'delete', 'fclose', 'file_get_contents', 'file_put_contents', + 'flock', 'fopen', + 'fputcsv', + 'fputs', 'fread', 'fsockopen', + 'ftruncate', 'fwrite', + 'is_writable', + 'is_writeable', + 'lchgrp', + 'lchown', + 'link', + 'mkdir', 'pfsockopen', 'readfile', + 'rename', + 'rmdir', + 'symlink', + 'tempnam', + 'touch', + 'unlink', ), ), From 6275522d37ea849d5c4fb7a4eb9e763eb17ecf24 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 9 Apr 2020 22:49:26 +0200 Subject: [PATCH 003/822] Composer/Travis: change the minimum PHPCS version Update the minimum required PHPCS version to `3.5.0`. --- .travis.yml | 10 +++++----- composer.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4369ad0926..8cd9fc1b4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,10 +22,10 @@ php: - "nightly" env: - # `master` is now 3.x. + # PHPCS `master`. - PHPCS_BRANCH="dev-master" LINT=1 # Lowest supported release in the 3.x series with which WPCS is compatible. - - PHPCS_BRANCH="3.3.1" + - PHPCS_BRANCH="3.5.0" # Define the stages used. # For non-PRs, only the sniff, ruleset and quicktest stages are run. @@ -101,7 +101,7 @@ jobs: - stage: rulesets php: 7.4 - env: PHPCS_BRANCH="3.3.1" + env: PHPCS_BRANCH="3.5.0" script: - $(pwd)/vendor/bin/phpcs -ps ./bin/class-ruleset-test.php --standard=WordPress-Core - $(pwd)/vendor/bin/phpcs -ps ./bin/class-ruleset-test.php --standard=WordPress-Docs @@ -115,11 +115,11 @@ jobs: php: 7.4 env: PHPCS_BRANCH="dev-master" LINT=1 - php: 7.3 - env: PHPCS_BRANCH="3.3.1" + env: PHPCS_BRANCH="3.5.0" - php: 5.4 env: PHPCS_BRANCH="dev-master" LINT=1 - php: 5.4 - env: PHPCS_BRANCH="3.3.1" + env: PHPCS_BRANCH="3.5.0" #### TEST STAGE #### # Add extra build to test against PHPCS 4. diff --git a/composer.json b/composer.json index 7e3c558fb3..d5ee2400d5 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ ], "require": { "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" + "squizlabs/php_codesniffer": "^3.5.0" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", From f73d151ddde46cee7b33d3d47a881f0030e024c9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 9 Apr 2020 22:49:26 +0200 Subject: [PATCH 004/822] Composer: add PHPCSUtils and PHPCSExtra as dependencies Composer: * Add PHPCSUtils and PHPCSExtra as dependencies. * Remove the DealerDirect plugin from `require-dev` as well as from `suggests` as it comes with PHPCSUtils/PHPCSExtra automatically and not having it here may prevent conflicts with allowed versions in the future. Travis: * Alias PHPCS 4.x to `3.9.99` to allow testing with the dependencies before PHPCS 4.x is officially supported by them. * When testing with PHPCS 4.x, we need `--prefer-source` as otherwise the test files we use from PHPCS itself won't be included. The way I've implemented this uses a [new feature](https://github.com/composer/composer/issues/6301) which is available since Composer 1.10.0 to selectively download from source. This prevents *all* packages being downloaded from source for the PHPCS `4.x` build, which would slow down the build and negate the Travis caching. Note: the install/upgrade instructions in the Readme and other documentation will be addressed in a separate PR late in the 3.0 cycle, so as not to confuse people using the latest release, while 3.0.0 development is ongoing. --- .travis.yml | 20 +++++++++++--------- composer.json | 11 +++++------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8cd9fc1b4f..51f40fe794 100644 --- a/.travis.yml +++ b/.travis.yml @@ -125,12 +125,12 @@ jobs: # Add extra build to test against PHPCS 4. - stage: test php: 7.4 - env: PHPCS_BRANCH="4.0.x-dev" + env: PHPCS_BRANCH="4.0.x-dev as 3.9.99" allow_failures: # Allow failures for unstable builds. - php: "nightly" - - env: PHPCS_BRANCH="4.0.x-dev" + - env: PHPCS_BRANCH="4.0.x-dev as 3.9.99" before_install: # Speed up build time by disabling Xdebug. @@ -147,21 +147,23 @@ before_install: - export XMLLINT_INDENT=" " - export PHPUNIT_DIR=/tmp/phpunit + - | - if [[ $TRAVIS_PHP_VERSION == "nightly" || $PHPCS_BRANCH == "4.0.x-dev" ]]; then - # Even though we're not doing a dev install, dev requirements are still checked. - # Neither the PHPCS Composer plugin nor PHPCompatibility allows yet for PHPCS 4.x. - # The Composer plugin also doesn't allow for installation on PHP 8.x/nightly. - composer remove --dev dealerdirect/phpcodesniffer-composer-installer phpcompatibility/php-compatibility --no-update --no-scripts + if [[ ${PHPCS_BRANCH:0:2} == "4." ]]; then + # Set Composer up to download only PHPCS from source for PHPCS 4.x. + # The source is needed to get the base testcase from PHPCS. + composer config preferred-install.squizlabs/php_codesniffer source + else + composer config preferred-install.squizlabs/php_codesniffer auto fi - - composer require squizlabs/php_codesniffer:${PHPCS_BRANCH} --update-no-dev --no-suggest --no-scripts + - composer require squizlabs/php_codesniffer:"${PHPCS_BRANCH}" --update-no-dev --no-suggest --no-scripts - | if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Sniff" ]]; then composer install --dev --no-suggest # The `dev` required DealerDirect Composer plugin takes care of the installed_paths. else # The above require already does the install. - $(pwd)/vendor/bin/phpcs --config-set installed_paths $(pwd) + composer install-codestandards fi # Download PHPUnit 7.x for builds on PHP >= 7.2 as the PHPCS # test suite is currently not compatible with PHPUnit 8.x. diff --git a/composer.json b/composer.json index d5ee2400d5..080051f723 100644 --- a/composer.json +++ b/composer.json @@ -16,18 +16,17 @@ ], "require": { "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.5.0" + "squizlabs/php_codesniffer": "^3.5.0", + "phpcsstandards/phpcsutils": "^1.0", + "phpcsstandards/phpcsextra": "^1.0" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", "phpcompatibility/php-compatibility": "^9.0", "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0", "phpcsstandards/phpcsdevtools": "^1.0" }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." - }, - "minimum-stability": "RC", + "minimum-stability": "dev", + "prefer-stable": true, "scripts": { "check-cs": [ "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" From 9d410e22c6cd0cd5bad0a06a9816c089f0c7cff5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 30 Jun 2020 07:06:27 +0200 Subject: [PATCH 005/822] Travis: simplify the script Current situation: * The Travis native PHPUnit is used in most cases, though on PHP > 7.1, a PHPUnit phar is downloaded. New situation: * Always installed PHPUnit with Composer. For PHP 8 (`nightly`) ignore platform requirements to allow PHPUnit 7.x to install. This makes us less dependent on the Travis images being correct (we've seen problems before aka the current special casing) and as the Travis cache should retain the downloaded Composer packages, this should really have much impact on the build time and gives us more flexibility to add other dev tools. --- .travis.yml | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51f40fe794..e677b3a8e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -146,8 +146,8 @@ before_install: fi - export XMLLINT_INDENT=" " - - export PHPUNIT_DIR=/tmp/phpunit +install: - | if [[ ${PHPCS_BRANCH:0:2} == "4." ]]; then # Set Composer up to download only PHPCS from source for PHPCS 4.x. @@ -156,27 +156,20 @@ before_install: else composer config preferred-install.squizlabs/php_codesniffer auto fi - - composer require squizlabs/php_codesniffer:"${PHPCS_BRANCH}" --update-no-dev --no-suggest --no-scripts + - composer require squizlabs/php_codesniffer:"${PHPCS_BRANCH}" --no-update --no-suggest --no-scripts - | - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Sniff" ]]; then - composer install --dev --no-suggest - # The `dev` required DealerDirect Composer plugin takes care of the installed_paths. + if [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + # PHPUnit 7.x does not allow for installation on PHP 8, so ignore platform + # requirements to get PHPUnit 7.x to install on nightly. + composer install --ignore-platform-reqs --no-suggest else - # The above require already does the install. - composer install-codestandards + # Do a normal dev install in all other cases. + composer install --no-suggest fi - # Download PHPUnit 7.x for builds on PHP >= 7.2 as the PHPCS - # test suite is currently not compatible with PHPUnit 8.x. - - if [[ ${TRAVIS_PHP_VERSION:0:3} > "7.1" ]]; then wget -P $PHPUNIT_DIR https://phar.phpunit.de/phpunit-7.phar && chmod +x $PHPUNIT_DIR/phpunit-7.phar; fi script: # Lint the PHP files against parse errors. - if [[ "$LINT" == "1" ]]; then if find . -path ./vendor -prune -o -path ./bin -prune -o -name "*.php" -exec php -l {} \; | grep "^[Parse error|Fatal error]"; then exit 1; fi; fi # Run the unit tests. - - | - if [[ ${TRAVIS_PHP_VERSION:0:3} > "7.1" ]]; then - php $PHPUNIT_DIR/phpunit-7.phar --filter WordPress --bootstrap="$(pwd)/vendor/squizlabs/php_codesniffer/tests/bootstrap.php" $(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php - else - phpunit --filter WordPress --bootstrap="$(pwd)/vendor/squizlabs/php_codesniffer/tests/bootstrap.php" $(pwd)/vendor/squizlabs/php_codesniffer/tests/AllTests.php - fi + - composer run-tests From a9d6ed36511df18bd1b283b103bf3569acc8fa01 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 9 Apr 2020 15:30:28 +0200 Subject: [PATCH 006/822] Tests: add a bootstrap file While not strictly necessary, it makes life easier to have this bootstrap in place. The bootstrap file will: * Load the PHPCS autoloader (was previously done from the command-line); * Load the Composer autoload file. * Will automatically set the `PHPCS_IGNORE_TESTS` environment variable to the correct value to prevent running tests from other standards. --- .gitattributes | 1 + Tests/bootstrap.php | 85 +++++++++++++++++++++++++++++++++++++++++++++ composer.json | 2 +- phpunit.xml.dist | 7 +--- 4 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 Tests/bootstrap.php diff --git a/.gitattributes b/.gitattributes index c12f94cfb3..f4790dee63 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,6 +9,7 @@ /phpunit.xml.dist export-ignore /.github export-ignore /bin export-ignore +/Tests export-ignore /WordPress/Tests export-ignore # diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php new file mode 100644 index 0000000000..fd4c952893 --- /dev/null +++ b/Tests/bootstrap.php @@ -0,0 +1,85 @@ + true, +); + +$allStandards = PHP_CodeSniffer\Util\Standards::getInstalledStandards(); +$allStandards[] = 'Generic'; + +$standardsToIgnore = array(); +foreach ( $allStandards as $standard ) { + if ( isset( $wpcsStandards[ $standard ] ) === true ) { + continue; + } + + $standardsToIgnore[] = $standard; +} + +$standardsToIgnoreString = implode( ',', $standardsToIgnore ); + +// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_putenv -- This is not production, but test code. +putenv( "PHPCS_IGNORE_TESTS={$standardsToIgnoreString}" ); + +// Clean up. +unset( $ds, $phpcsDir, $composerPHPCSPath, $allStandards, $standardsToIgnore, $standard, $standardsToIgnoreString ); diff --git a/composer.json b/composer.json index 080051f723..5aa842317a 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run" ], "run-tests": [ - "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress --bootstrap=\"./vendor/squizlabs/php_codesniffer/tests/bootstrap.php\" ./vendor/squizlabs/php_codesniffer/tests/AllTests.php" + "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php" ], "check-complete": [ "@php ./vendor/phpcsstandards/phpcsdevtools/bin/phpcs-check-feature-completeness -q ./WordPress" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index ccacc14806..4bd81b342a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,6 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd" backupGlobals="true" + bootstrap="./Tests/bootstrap.php" beStrictAboutTestsThatDoNotTestAnything="false" colors="true"> @@ -12,10 +13,4 @@ - - - - From 7cae307243a09dac4a5e4b166218976d85f2a1f7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Apr 2020 10:26:08 +0200 Subject: [PATCH 007/822] Remove deprecated `Sniff::has_whitelist_comment()` method and all references to it 1. Remove the method which was deprecated in WPCS 2.0.0. 2. Remove all function calls to the method. Includes: * Removing the `SlowQuerySniff::process_token()` method. This will now fall through automatically to the method in the parent class. * Removing the `GlobalVariablesOverrideSniff::maybe_add_error() method. This method no longer has a function. 3. Adjusting the unit tests. * Where tests could be removed without having to renumber a lot, especially when the test was more about testing the whitelist functionality than testing the sniff, I've removed them. * In all other cases, I've changed the previous deprecation warning in the lines lists to a "normal" error/warning and annotated the change in behaviour. * Note: in the `PrefixAllGlobals` tests, there were two testcases which would previously throw a warning for the whitelist comment, but where the whitelist comment had no function anyway as the sniff had already been adjusted to no longer throw an error for those cases. For those, I've removed the whitelist comments. Includes: * Removing an exclusion for a whitelist comment deprecation notice from the WPCS native PHPCS ruleset. * Updating the instructions regarding the old whitelist comments in the CONTRIBUTING file. :question_mark: As an alternative, the reference to the old-style whitelist comments could be removed completely from the CONTRIBUTING file. Fixes 1583 --- .github/CONTRIBUTING.md | 4 +- .phpcs.xml.dist | 6 - WordPress/Sniff.php | 107 ------------------ .../DB/PreparedSQLPlaceholdersSniff.php | 11 +- WordPress/Sniffs/DB/PreparedSQLSniff.php | 4 - WordPress/Sniffs/DB/SlowDBQuerySniff.php | 21 ---- .../PrefixAllGlobalsSniff.php | 12 -- .../Sniffs/PHP/StrictComparisonsSniff.php | 6 +- .../Sniffs/Security/EscapeOutputSniff.php | 5 - .../Security/NonceVerificationSniff.php | 4 - .../Security/ValidatedSanitizedInputSniff.php | 4 - WordPress/Sniffs/WP/CapitalPDangitSniff.php | 5 - .../WP/GlobalVariablesOverrideSniff.php | 25 +--- .../WhiteSpace/PrecisionAlignmentSniff.php | 2 +- .../DB/PreparedSQLPlaceholdersUnitTest.inc | 4 +- .../DB/PreparedSQLPlaceholdersUnitTest.php | 4 +- WordPress/Tests/DB/PreparedSQLUnitTest.inc | 16 +-- WordPress/Tests/DB/PreparedSQLUnitTest.php | 9 +- WordPress/Tests/DB/SlowDBQueryUnitTest.inc | 17 --- WordPress/Tests/DB/SlowDBQueryUnitTest.php | 4 - .../PrefixAllGlobalsUnitTest.1.inc | 10 +- .../PrefixAllGlobalsUnitTest.php | 8 +- .../Tests/PHP/StrictComparisonsUnitTest.inc | 12 +- .../Tests/PHP/StrictComparisonsUnitTest.php | 4 +- .../Tests/Security/EscapeOutputUnitTest.inc | 2 +- .../Tests/Security/EscapeOutputUnitTest.php | 17 +-- .../Security/NonceVerificationUnitTest.inc | 2 +- .../Security/NonceVerificationUnitTest.php | 5 +- .../ValidatedSanitizedInputUnitTest.inc | 2 +- .../ValidatedSanitizedInputUnitTest.php | 5 +- WordPress/Tests/WP/CapitalPDangitUnitTest.inc | 2 +- .../Tests/WP/CapitalPDangitUnitTest.inc.fixed | 4 +- WordPress/Tests/WP/CapitalPDangitUnitTest.php | 2 +- .../WP/GlobalVariablesOverrideUnitTest.1.inc | 2 +- .../WP/GlobalVariablesOverrideUnitTest.php | 15 +-- .../PrecisionAlignmentUnitTest.1.inc | 2 +- .../WhiteSpace/PrecisionAlignmentUnitTest.php | 2 +- 37 files changed, 52 insertions(+), 314 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 34b96be5c7..21453cd37a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -37,9 +37,7 @@ When you introduce new `public` sniff properties, or your sniff extends a class > **Important**: > PHPCS 3.2.0 introduced new selective ignore annotations, which can be considered an improved version of the whitelist mechanism which WPCS contains. > -> Support for the WPCS native whitelist comments has been deprecated in WPCS 2.0.0 and will be removed in WPCS 3.0.0. -> -> With that in mind, (new) sniffs should not introduce new WPCS native whitelist comments. +> Support for the WPCS native whitelist comments has been deprecated in WPCS 2.0.0 and removed in WPCS 3.0.0. # Unit Testing diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index ef779c2dc3..6a4fba088f 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -47,10 +47,4 @@ - - - /WordPress/AbstractClassRestrictionsSniff\.php$ - - diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 55ca6e7419..aea262ef23 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -1149,113 +1149,6 @@ protected function get_wp_version_from_cl() { } } - /** - * Find whitelisting comment. - * - * Comment must be at the end of the line or at the end of the statement - * and must use // format. - * It can be prefixed or suffixed with anything e.g. "foobar" will match: - * ... // foobar okay - * ... // WPCS: foobar whitelist. - * - * There is an exception, and that is when PHP is being interspersed with HTML. - * In that case, the comment should always come at the end of the statement (right - * before the closing tag, ?>). For example: - * - * - * - * @since 0.4.0 - * @since 0.14.0 Whitelist comments at the end of the statement are now also accepted. - * - * @deprecated 2.0.0 Use the PHPCS native `phpcs:ignore` annotations instead. - * - * @param string $comment Comment to find. - * @param integer $stackPtr The position of the current token in the stack passed - * in $tokens. - * - * @return boolean True if whitelisting comment was found, false otherwise. - */ - protected function has_whitelist_comment( $comment, $stackPtr ) { - - // Respect the PHPCS 3.x --ignore-annotations setting. - if ( true === PHPCSHelper::ignore_annotations( $this->phpcsFile ) ) { - return false; - } - - static $thrown_notices = array(); - - $deprecation_notice = 'Using the WPCS native whitelist comments is deprecated. Please use the PHPCS native "phpcs:ignore Standard.Category.SniffName.ErrorCode" annotations instead. Found: %s'; - $deprecation_code = 'DeprecatedWhitelistCommentFound'; - $filename = $this->phpcsFile->getFileName(); - - $regex = '#\b' . preg_quote( $comment, '#' ) . '\b#i'; - - // There is a findEndOfStatement() method, but it considers more tokens than - // we need to consider here. - $end_of_statement = $this->phpcsFile->findNext( array( \T_CLOSE_TAG, \T_SEMICOLON ), $stackPtr ); - - if ( false !== $end_of_statement ) { - // If the statement was ended by a semicolon, check if there is a whitelist comment directly after it. - if ( \T_SEMICOLON === $this->tokens[ $end_of_statement ]['code'] ) { - $lastPtr = $this->phpcsFile->findNext( \T_WHITESPACE, ( $end_of_statement + 1 ), null, true ); - } elseif ( \T_CLOSE_TAG === $this->tokens[ $end_of_statement ]['code'] ) { - // If the semicolon was left out and it was terminated by an ending tag, we need to look backwards. - $lastPtr = $this->phpcsFile->findPrevious( \T_WHITESPACE, ( $end_of_statement - 1 ), null, true ); - } - - if ( ( \T_COMMENT === $this->tokens[ $lastPtr ]['code'] - || ( isset( Tokens::$phpcsCommentTokens[ $this->tokens[ $lastPtr ]['code'] ] ) - && \T_PHPCS_SET !== $this->tokens[ $lastPtr ]['code'] ) ) - && $this->tokens[ $lastPtr ]['line'] === $this->tokens[ $end_of_statement ]['line'] - && preg_match( $regex, $this->tokens[ $lastPtr ]['content'] ) === 1 - ) { - if ( isset( $thrown_notices[ $filename ][ $lastPtr ] ) === false - && isset( Tokens::$phpcsCommentTokens[ $this->tokens[ $lastPtr ]['code'] ] ) === false - ) { - $this->phpcsFile->addWarning( - $deprecation_notice, - $lastPtr, - $deprecation_code, - array( $this->tokens[ $lastPtr ]['content'] ) - ); - - $thrown_notices[ $filename ][ $lastPtr ] = true; - } - - return true; - } - } - - // No whitelist comment found so far. Check at the end of the stackPtr line. - // Note: a T_COMMENT includes the new line character, so may be the last token on the line! - $end_of_line = $this->get_last_ptr_on_line( $stackPtr ); - $lastPtr = $this->phpcsFile->findPrevious( \T_WHITESPACE, $end_of_line, null, true ); - - if ( ( \T_COMMENT === $this->tokens[ $lastPtr ]['code'] - || ( isset( Tokens::$phpcsCommentTokens[ $this->tokens[ $lastPtr ]['code'] ] ) - && \T_PHPCS_SET !== $this->tokens[ $lastPtr ]['code'] ) ) - && $this->tokens[ $lastPtr ]['line'] === $this->tokens[ $stackPtr ]['line'] - && preg_match( $regex, $this->tokens[ $lastPtr ]['content'] ) === 1 - ) { - if ( isset( $thrown_notices[ $filename ][ $lastPtr ] ) === false - && isset( Tokens::$phpcsCommentTokens[ $this->tokens[ $lastPtr ]['code'] ] ) === false - ) { - $this->phpcsFile->addWarning( - $deprecation_notice, - $lastPtr, - $deprecation_code, - array( $this->tokens[ $lastPtr ]['content'] ) - ); - - $thrown_notices[ $filename ][ $lastPtr ] = true; - } - - return true; - } - - return false; - } - /** * Check if a token is used within a unit test. * diff --git a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php index 8f184c6be7..876ebf179c 100644 --- a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php @@ -445,11 +445,6 @@ public function process_token( $stackPtr ) { return; } - $count_diff_whitelisted = $this->has_whitelist_comment( - 'PreparedSQLPlaceholders replacement count', - $stackPtr - ); - if ( 0 === $total_placeholders ) { if ( 1 === $total_parameters ) { if ( false === $variable_found && false === $sql_wildcard_found ) { @@ -465,7 +460,7 @@ public function process_token( $stackPtr ) { 'UnnecessaryPrepare' ); } - } elseif ( false === $count_diff_whitelisted && 0 === $valid_in_clauses['uses_in'] ) { + } elseif ( 0 === $valid_in_clauses['uses_in'] ) { $this->phpcsFile->addWarning( 'Replacement variables found, but no valid placeholders found in the query.', $i, @@ -486,10 +481,6 @@ public function process_token( $stackPtr ) { return; } - if ( true === $count_diff_whitelisted ) { - return; - } - $replacements = $parameters; array_shift( $replacements ); // Remove the query. diff --git a/WordPress/Sniffs/DB/PreparedSQLSniff.php b/WordPress/Sniffs/DB/PreparedSQLSniff.php index 1fe2ad96da..57781d61af 100644 --- a/WordPress/Sniffs/DB/PreparedSQLSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLSniff.php @@ -127,10 +127,6 @@ public function process_token( $stackPtr ) { return; } - if ( $this->has_whitelist_comment( 'unprepared SQL', $stackPtr ) ) { - return; - } - for ( $this->i; $this->i < $this->end; $this->i++ ) { if ( isset( $this->ignored_tokens[ $this->tokens[ $this->i ]['code'] ] ) ) { diff --git a/WordPress/Sniffs/DB/SlowDBQuerySniff.php b/WordPress/Sniffs/DB/SlowDBQuerySniff.php index 4feebdcb60..e6157cb020 100644 --- a/WordPress/Sniffs/DB/SlowDBQuerySniff.php +++ b/WordPress/Sniffs/DB/SlowDBQuerySniff.php @@ -47,27 +47,6 @@ public function getGroups() { ); } - /** - * Processes this test, when one of its tokens is encountered. - * - * @since 0.10.0 - * - * @param int $stackPtr The position of the current token in the stack. - * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. - */ - public function process_token( $stackPtr ) { - - if ( $this->has_whitelist_comment( 'slow query', $stackPtr ) ) { - return; - } elseif ( $this->has_whitelist_comment( 'tax_query', $stackPtr ) ) { - return; - } - - return parent::process_token( $stackPtr ); - } - /** * Callback to process each confirmed key, to check value. * This must be extended to add the logic to check assignment value. diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index 8374faf675..13c1437657 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -263,18 +263,6 @@ public function getGroups() { * normal file processing. */ public function process_token( $stackPtr ) { - /* - * Allow for whitelisting. - * - * Generally speaking a theme/plugin should *only* execute their own hooks, but there may be a - * good reason to execute a core hook. - * - * Similarly, newer PHP or WP functions or constants may need to be emulated for continued support - * of older PHP and WP versions. - */ - if ( $this->has_whitelist_comment( 'prefix', $stackPtr ) ) { - return; - } // Allow overruling the prefixes set in a ruleset via the command line. $cl_prefixes = trim( PHPCSHelper::get_config_data( 'prefixes' ) ); diff --git a/WordPress/Sniffs/PHP/StrictComparisonsSniff.php b/WordPress/Sniffs/PHP/StrictComparisonsSniff.php index 85fe055490..3b2566bfbb 100644 --- a/WordPress/Sniffs/PHP/StrictComparisonsSniff.php +++ b/WordPress/Sniffs/PHP/StrictComparisonsSniff.php @@ -47,10 +47,8 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( ! $this->has_whitelist_comment( 'loose comparison', $stackPtr ) ) { - $error = 'Found: ' . $this->tokens[ $stackPtr ]['content'] . '. Use strict comparisons (=== or !==).'; - $this->phpcsFile->addWarning( $error, $stackPtr, 'LooseComparison' ); - } + $error = 'Found: ' . $this->tokens[ $stackPtr ]['content'] . '. Use strict comparisons (=== or !==).'; + $this->phpcsFile->addWarning( $error, $stackPtr, 'LooseComparison' ); } } diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index 48a4766bad..89b1cb3961 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -214,11 +214,6 @@ public function process_token( $stackPtr ) { } } - // Checking for the ignore comment, ex: //xss ok. - if ( $this->has_whitelist_comment( 'xss', $stackPtr ) ) { - return; - } - if ( isset( $this->unsafePrintingFunctions[ $function ] ) ) { $error = $this->phpcsFile->addError( "All output should be run through an escaping function (like %s), found '%s'.", diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php index 15f4a60408..934ff8004d 100644 --- a/WordPress/Sniffs/Security/NonceVerificationSniff.php +++ b/WordPress/Sniffs/Security/NonceVerificationSniff.php @@ -111,10 +111,6 @@ public function process_token( $stackPtr ) { return; } - if ( $this->has_whitelist_comment( 'CSRF', $stackPtr ) ) { - return; - } - if ( $this->is_assignment( $stackPtr ) ) { return; } diff --git a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php index a545c58078..54b43184e7 100644 --- a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php +++ b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php @@ -171,10 +171,6 @@ function ( $symbol ) { ); } - if ( $this->has_whitelist_comment( 'sanitization', $stackPtr ) ) { - return; - } - // If this variable is being tested with one of the `is_..()` functions, sanitization isn't needed. if ( $this->is_in_type_test( $stackPtr ) ) { return; diff --git a/WordPress/Sniffs/WP/CapitalPDangitSniff.php b/WordPress/Sniffs/WP/CapitalPDangitSniff.php index bf98233fb9..f5f9512ef4 100644 --- a/WordPress/Sniffs/WP/CapitalPDangitSniff.php +++ b/WordPress/Sniffs/WP/CapitalPDangitSniff.php @@ -115,11 +115,6 @@ public function register() { * normal file processing. */ public function process_token( $stackPtr ) { - - if ( $this->has_whitelist_comment( 'spelling', $stackPtr ) ) { - return; - } - /* * Ignore tokens within an array definition as this is a false positive in 80% of all cases. * diff --git a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php index 37bf68b2a7..b69a5119f1 100644 --- a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php +++ b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php @@ -198,10 +198,6 @@ protected function process_list_assignment( $stackPtr ) { */ protected function process_variable_assignment( $stackPtr, $in_list = false ) { - if ( $this->has_whitelist_comment( 'override', $stackPtr ) === true ) { - return; - } - $token = $this->tokens[ $stackPtr ]; $var_name = substr( $token['content'], 1 ); // Strip the dollar sign. $data = array(); @@ -410,34 +406,17 @@ protected function process_global_statement( $stackPtr, $in_function_scope ) { } if ( true === $this->is_assignment( $ptr ) ) { - $this->maybe_add_error( $ptr ); + $this->add_error( $ptr ); continue; } // Check if this is a variable assignment within a `foreach()` declaration. if ( $this->is_foreach_as( $ptr ) === true ) { - $this->maybe_add_error( $ptr ); + $this->add_error( $ptr ); } } } - /** - * Add the error if there is no whitelist comment present. - * - * @since 0.11.0 - * @since 1.1.0 - Visibility changed from public to protected. - * - Check for being in a test class moved to the process_token() method. - * - * @param int $stackPtr The position of the token to throw the error for. - * - * @return void - */ - protected function maybe_add_error( $stackPtr ) { - if ( $this->has_whitelist_comment( 'override', $stackPtr ) === false ) { - $this->add_error( $stackPtr ); - } - } - /** * Add the error. * diff --git a/WordPress/Sniffs/WhiteSpace/PrecisionAlignmentSniff.php b/WordPress/Sniffs/WhiteSpace/PrecisionAlignmentSniff.php index 010ec9438b..f5e822bdc3 100644 --- a/WordPress/Sniffs/WhiteSpace/PrecisionAlignmentSniff.php +++ b/WordPress/Sniffs/WhiteSpace/PrecisionAlignmentSniff.php @@ -182,7 +182,7 @@ public function process_token( $stackPtr ) { break; } - if ( $spaces > 0 && ! $this->has_whitelist_comment( 'precision alignment', $i ) ) { + if ( $spaces > 0 ) { $this->phpcsFile->addWarning( 'Found precision alignment of %s spaces.', $i, diff --git a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc index d703013123..04548fc74d 100644 --- a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc @@ -59,13 +59,13 @@ $sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login $replacements = [1, "admin", $variable]; $sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", $replacements ); // Bad. -$sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", $replacements ); // WPCS: PreparedSQLPlaceholders replacement count OK. +$sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", $replacements ); // Bad - old-style whitelist comment. WPCS: PreparedSQLPlaceholders replacement count OK. // Valid test case as found in WP core /wp-admin/includes/export.php $esses = array_fill( 0, count($post_types), '%s' ); $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); // Warning. // Testing that whitelist comment work for this mismatch too. -$where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); // WPCS: PreparedSQLPlaceholders replacement count OK. +$where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); // Bad - old-style whitelist comment. WPCS: PreparedSQLPlaceholders replacement count OK. /* * Test correctly recognizing queries using IN in combination with dynamic placeholder creation. diff --git a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php index 1cf42f021f..e8446786cb 100644 --- a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php @@ -85,9 +85,9 @@ public function getWarningList() { 57 => 1, 58 => 1, 61 => 1, - 62 => 1, // Whitelist comment deprecation warning. + 62 => 1, // Old-style WPCS whitelist comments are no longer supported. 66 => 1, - 68 => 1, // Whitelist comment deprecation warning. + 68 => 1, // Old-style WPCS whitelist comments are no longer supported. 126 => 1, 139 => 1, 160 => 2, diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.inc index 52ef3a0e31..b09bfdb8e5 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.inc @@ -8,8 +8,8 @@ $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '$var';" ) ); // Bad. $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE %s;", $_GET['title'] ) ); // Ok. -$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . $escaped_var . "';" ); // WPCS: unprepared SQL OK. -$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '{$escaped_var}';" ); // WPCS: unprepared SQL OK. +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . $escaped_var . "';" ); // Bad: old-style whitelist comment. WPCS: unprepared SQL OK. +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '{$escaped_var}';" ); // Bad: old-style whitelist comment. WPCS: unprepared SQL OK. $wpdb->query( $wpdb->prepare( "SELECT SUBSTRING( post_name, %d + 1 ) REGEXP '^[0-9]+$'", array( 123 ) ) ); // Ok. $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title = 'The \$_GET var can be evil.' AND ID = %s", array( 123 ) ) ); // Ok. @@ -90,18 +90,6 @@ $wpdb->query( // Some arbitrary comment. WHERE post_title LIKE '" . $escaped_var . "';" ); // Bad x 1. -$wpdb->query( - "SELECT * - FROM $wpdb->posts - WHERE post_title LIKE '" . $escaped_var . "';" -); // WPCS: unprepared SQL OK. - -$wpdb->query( // WPCS: unprepared SQL OK. - "SELECT * - FROM $wpdb->posts - WHERE post_title LIKE '" . $escaped_var . "';" -); - $wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . (int) $foo . ";" ); // Ok. $wpdb->query( "SELECT * FROM $wpdb->posts WHERE value = " . (float) $foo . ";" ); // Ok. diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.php b/WordPress/Tests/DB/PreparedSQLUnitTest.php index 03f7c6d8fa..329baaa3cc 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.php @@ -36,6 +36,8 @@ public function getErrorList() { 5 => 1, 7 => 1, 8 => 1, + 11 => 1, // Old-style WPCS whitelist comments are no longer supported. + 12 => 1, // Old-style WPCS whitelist comments are no longer supported. 16 => 1, 17 => 1, 18 => 1, @@ -57,12 +59,7 @@ public function getErrorList() { * @return array => */ public function getWarningList() { - return array( - 11 => 1, // Whitelist comment deprecation warning. - 12 => 1, // Whitelist comment deprecation warning. - 97 => 1, // Whitelist comment deprecation warning. - 99 => 1, // Whitelist comment deprecation warning. - ); + return array(); } } diff --git a/WordPress/Tests/DB/SlowDBQueryUnitTest.inc b/WordPress/Tests/DB/SlowDBQueryUnitTest.inc index 6c8791aa8b..fea1379591 100644 --- a/WordPress/Tests/DB/SlowDBQueryUnitTest.inc +++ b/WordPress/Tests/DB/SlowDBQueryUnitTest.inc @@ -21,20 +21,3 @@ $query = 'foo=bar&meta_key=foo&meta_value=bar'; if ( ! isset( $widget['params'][0] ) ) { $widget['params'][0] = array(); } - - -// Testing whitelisting comments. -$test = array( - - // Single-line statements. - 'tax_query' => array(), // Bad. - 'tax_query' => array(), // WPCS: slow query ok. - 'tax_query' => array(), // WPCS: tax_query ok. - - // Multi-line statement. - 'tax_query' => array( // WPCS: slow query ok. - array( - 'taxonomy' => 'foo', - ), - ), -); diff --git a/WordPress/Tests/DB/SlowDBQueryUnitTest.php b/WordPress/Tests/DB/SlowDBQueryUnitTest.php index 987e4d412d..1d31c2b930 100644 --- a/WordPress/Tests/DB/SlowDBQueryUnitTest.php +++ b/WordPress/Tests/DB/SlowDBQueryUnitTest.php @@ -43,10 +43,6 @@ public function getWarningList() { 15 => 1, 16 => 1, 19 => 2, - 30 => 1, - 31 => 1, // Whitelist comment deprecation warning. - 32 => 1, // Whitelist comment deprecation warning. - 35 => 1, // Whitelist comment deprecation warning. ); } diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index 12404130e6..6290ff07f2 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -193,22 +193,22 @@ class Test_Class_D extends My_TestClass { // phpcs:set WordPress.NamingConventions.PrefixAllGlobals custom_test_class_whitelist[] -/* - * OK - whitelisted via whitelist comment. - */ if ( ! function_exists( 'intdiv' ) ) { // Fill in for a PHP function which is not available in low PHP versions. - function intdiv() { // WPCS: prefix ok. + function intdiv() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals // Some code. } } if ( ! defined( 'PHP_VERSION_ID' ) ) { $acronym_version = explode('.', PHP_VERSION); - define('PHP_VERSION_ID', (int) (($acronym_version[0] * 10000) + ($acronym_version[1] * 100) + $acronym_version[2])); // WPCS: prefix ok. + define('PHP_VERSION_ID', (int) (($acronym_version[0] * 10000) + ($acronym_version[1] * 100) + $acronym_version[2])); unset($acronym_version); } +/* + * Bad - whitelisted via old-style whitelist comment. + */ $something = 'abc'; // WPCS: prefix ok. // Executing a WP core action or filter is sometimes ok. diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php index eb8e4644b7..85d41bc79b 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php @@ -51,6 +51,9 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) { 39 => 1, 40 => 1, 90 => 1, + 212 => 1, // Old-style WPCS whitelist comments are no longer supported. + 215 => 1, // Old-style WPCS whitelist comments are no longer supported. + 216 => 1, // Old-style WPCS whitelist comments are no longer supported. // Backfills. 225 => ( function_exists( '\mb_strpos' ) ) ? 0 : 1, 230 => ( function_exists( '\array_column' ) ) ? 0 : 1, @@ -108,11 +111,6 @@ public function getWarningList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) { case 'PrefixAllGlobalsUnitTest.1.inc': return array( 1 => 3, // 3 x warning for potentially incorrect prefix passed. - 201 => 1, // Whitelist comment deprecation warning. - 208 => 1, // Whitelist comment deprecation warning. - 212 => 1, // Whitelist comment deprecation warning. - 215 => 1, // Whitelist comment deprecation warning. - 216 => 1, // Whitelist comment deprecation warning. 249 => 1, 250 => 1, 253 => 1, diff --git a/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc b/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc index 7c3ce84131..17da61c0d3 100644 --- a/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc +++ b/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc @@ -15,17 +15,7 @@ if ( true != $true ) { // Bad. echo 'False'; } -// Test for whitelisting. +// Bad - whitelisted via old-style whitelist comment. if ( true == $true ) { // Loose comparison, OK. echo 'True'; } - -// Test that whitelisting is not too eager. -if ( true == $true ) { - // The line above has a loose comparison, but no whitelist comment. - echo 'True'; -} - -if ( true == $true ) { // Loose comparisons FTW! - echo 'True'; -} diff --git a/WordPress/Tests/PHP/StrictComparisonsUnitTest.php b/WordPress/Tests/PHP/StrictComparisonsUnitTest.php index b7ada4d896..ec3d970412 100644 --- a/WordPress/Tests/PHP/StrictComparisonsUnitTest.php +++ b/WordPress/Tests/PHP/StrictComparisonsUnitTest.php @@ -40,9 +40,7 @@ public function getWarningList() { 3 => 1, 10 => 1, 12 => 1, - 19 => 1, // Whitelist comment deprecation warning. - 24 => 1, - 29 => 1, + 19 => 1, // Old-style WPCS whitelist comments are no longer supported. ); } diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.inc index bd74d93ac9..1926aad635 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.inc @@ -121,7 +121,7 @@ wp_die( -1 ); // Ok. 1, 114 => 1, 125 => 1, + 126 => 1, // Old-style WPCS whitelist comments are no longer supported. + 127 => 1, // Old-style WPCS whitelist comments are no longer supported. + 128 => 1, // Old-style WPCS whitelist comments are no longer supported. 131 => 1, 135 => 1, 138 => 1, @@ -73,11 +76,16 @@ public function getErrorList() { 223 => 1, 225 => 1, 226 => 1, + 241 => 1, // Old-style WPCS whitelist comments are no longer supported. + 245 => 1, // Old-style WPCS whitelist comments are no longer supported. + 249 => 1, // Old-style WPCS whitelist comments are no longer supported. 252 => 1, 253 => 1, 263 => 1, 264 => 1, 266 => 1, + 282 => 1, + 286 => 1, 289 => 1, 294 => 1, 297 => 1, @@ -90,14 +98,7 @@ public function getErrorList() { * @return array => */ public function getWarningList() { - return array( - 126 => 1, // Whitelist comment deprecation warning. - 127 => 1, // Whitelist comment deprecation warning. - 128 => 1, // Whitelist comment deprecation warning. - 241 => 1, // Whitelist comment deprecation warning. - 243 => 1, // Whitelist comment deprecation warning. - 250 => 1, // Whitelist comment deprecation warning. - ); + return array(); } } diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.inc index 41cf566594..cbfe01cbc7 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.inc @@ -83,7 +83,7 @@ function foo_2() { $_POST['settings'][ $setting ] = 'bb'; // OK. } -// Particular cases can be whitelisted with a comment. +// Bad - whitelisted via old-style whitelist comment. function foo_3() { bar( $_POST['var'] ); // WPCS: CSRF OK. bar( $_POST['var'] ); // Bad. diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index c3fb8a67b0..b53d02997d 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -36,6 +36,7 @@ public function getErrorList() { 44 => 1, 48 => 1, 69 => 1, + 88 => 1, // Old-style WPCS whitelist comments are no longer supported. 89 => 1, 113 => 1, 114 => 1, @@ -62,9 +63,7 @@ public function getErrorList() { * @return array => */ public function getWarningList() { - return array( - 88 => 1, // Whitelist comment deprecation warning. - ); + return array(); } } diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc index b70afe7f0a..005c2475f7 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc @@ -73,7 +73,7 @@ function zebra() { } } -echo $_GET['test']; // WPCS: sanitization OK. +echo $_GET['test']; // Bad: old-style whitelist comment. WPCS: sanitization OK. echo array_map( 'sanitize_text_field', wp_unslash( $_GET['test'] ) ); // Ok. echo array_map( 'foo', wp_unslash( $_GET['test'] ) ); // Bad. diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php index 493465ea3f..f1ba1e7949 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php @@ -35,6 +35,7 @@ public function getErrorList() { 20 => 1, 33 => 3, 65 => 1, + 76 => 2, // Old-style WPCS whitelist comments are no longer supported. 79 => 1, 80 => 1, 81 => 1, @@ -88,9 +89,7 @@ public function getErrorList() { * @return array => */ public function getWarningList() { - return array( - 76 => 1, // Whitelist comment deprecation warning. - ); + return array(); } } diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc index e29ee8942f..1a9fc3b723 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc @@ -162,7 +162,7 @@ $installed = self::check_plugin_is_installed( 'wordpress-importer' ); // OK. /* - * Test whitelisting + * Bad - whitelisted via old-style whitelist comment. */ echo 'This is an explanation about wordpress.'; // WPCS: spelling ok. diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed index 0a00f5ec0d..a711174177 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed @@ -162,9 +162,9 @@ $installed = self::check_plugin_is_installed( 'wordpress-importer' ); // OK. /* - * Test whitelisting + * Bad - whitelisted via old-style whitelist comment. */ -echo 'This is an explanation about wordpress.'; // WPCS: spelling ok. +echo 'This is an explanation about WordPress.'; // WPCS: spelling ok. /* * Test fixer with an ignored and a fixable misspelling in the same line. diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.php b/WordPress/Tests/WP/CapitalPDangitUnitTest.php index 0f7454a6ae..fa5f0bd835 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.php +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.php @@ -59,7 +59,7 @@ public function getWarningList() { 101 => 1, 139 => 1, 146 => 0, // False negative. - 167 => 1, // Whitelist comment deprecation warning. + 167 => 1, // Old-style WPCS whitelist comments are no longer supported. 173 => 1, 181 => 1, ); diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc index f544783056..5725b13c93 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc @@ -8,7 +8,7 @@ $wpdb = 'test'; // Bad. $post = get_post( 1 ); // Bad. global $post; -$post = get_post( 1 ); // Override ok. +$post = get_post( 1 ); // Bad: old-style whitelist comment. Override ok. // Bad: Using different types of assignment operators. function test_different_assignment_operators() { diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php index bd611b2830..83fcb3c1da 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php @@ -37,6 +37,7 @@ public function getErrorList( $testFile = '' ) { 3 => 1, 6 => 1, 8 => 1, + 11 => 1, // Old-style WPCS whitelist comments are no longer supported. 16 => 1, 17 => 1, 18 => 1, @@ -90,20 +91,10 @@ public function getErrorList( $testFile = '' ) { /** * Returns the lines where warnings should occur. * - * @param string $testFile The name of the file being tested. - * * @return array => */ - public function getWarningList( $testFile = '' ) { - switch ( $testFile ) { - case 'GlobalVariablesOverrideUnitTest.1.inc': - return array( - 11 => 1, // Whitelist comment deprecation warning. - ); - - default: - return array(); - } + public function getWarningList() { + return array(); } } diff --git a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc index 7bcca1217e..bcf06fe102 100644 --- a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc +++ b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc @@ -31,7 +31,7 @@ function exampleFunctionE() {} // Bad: [tab][space][space]. function exampleFunctionF() {} // Bad: [tab][space][space][space]. - function exampleFunctionG() {} // WPCS: precision alignment ok. + function exampleFunctionG() {} // Bad old-style whitelist comment: WPCS: precision alignment ok. ?> diff --git a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php index a7ed8c5601..32757ee5fb 100644 --- a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php +++ b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php @@ -69,7 +69,7 @@ public function getWarningList( $testFile = '' ) { 30 => 1, 31 => 1, 32 => 1, - 34 => 1, // Whitelist comment deprecation warning. + 34 => 1, // Old-style WPCS whitelist comments are no longer supported. 39 => 1, 65 => 1, ); From 7b1956ebc32a75bf6839e39057d8053697ce9945 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Apr 2020 11:26:34 +0200 Subject: [PATCH 008/822] Remove the WordPress.WP.TimezoneChange sniff This sniff was deprecated in WPCS 2.2.0 in favour of the `WordPress.DateTime.RestrictedFunctions` sniff (1805/1807). Fixes 1819 --- WordPress/Sniffs/WP/TimezoneChangeSniff.php | 88 ------------------- WordPress/Tests/WP/TimezoneChangeUnitTest.inc | 8 -- WordPress/Tests/WP/TimezoneChangeUnitTest.php | 50 ----------- WordPress/ruleset.xml | 6 +- 4 files changed, 1 insertion(+), 151 deletions(-) delete mode 100644 WordPress/Sniffs/WP/TimezoneChangeSniff.php delete mode 100644 WordPress/Tests/WP/TimezoneChangeUnitTest.inc delete mode 100644 WordPress/Tests/WP/TimezoneChangeUnitTest.php diff --git a/WordPress/Sniffs/WP/TimezoneChangeSniff.php b/WordPress/Sniffs/WP/TimezoneChangeSniff.php deleted file mode 100644 index f376c5e3a3..0000000000 --- a/WordPress/Sniffs/WP/TimezoneChangeSniff.php +++ /dev/null @@ -1,88 +0,0 @@ - false, - 'FoundPropertyForDeprecatedSniff' => false, - ); - - /** - * Don't use. - * - * @deprecated 2.2.0 - * - * @return array - */ - public function getGroups() { - $groups = parent::getGroups(); - return array( 'timezone_change' => $groups['timezone_change'] ); - } - - /** - * Don't use. - * - * @since 2.2.0 Added to allow for throwing the deprecation notices. - * @deprecated 2.2.0 - * - * @param int $stackPtr The position of the current token in the stack. - * - * @return void|int - */ - public function process_token( $stackPtr ) { - if ( false === $this->thrown['DeprecatedSniff'] ) { - $this->thrown['DeprecatedSniff'] = $this->phpcsFile->addWarning( - 'The "WordPress.WP.TimezoneChange" sniff has been deprecated. Use the "WordPress.DateTime.RestrictedFunctions" sniff instead. Please update your custom ruleset.', - 0, - 'DeprecatedSniff' - ); - } - - if ( ! empty( $this->exclude ) - && false === $this->thrown['FoundPropertyForDeprecatedSniff'] - ) { - $this->thrown['FoundPropertyForDeprecatedSniff'] = $this->phpcsFile->addWarning( - 'The "WordPress.WP.TimezoneChange" sniff has been deprecated. Use the "WordPress.DateTime.RestrictedFunctions" sniff instead. "exclude" property setting found. Please update your custom ruleset.', - 0, - 'FoundPropertyForDeprecatedSniff' - ); - } - - return parent::process_token( $stackPtr ); - } -} diff --git a/WordPress/Tests/WP/TimezoneChangeUnitTest.inc b/WordPress/Tests/WP/TimezoneChangeUnitTest.inc deleted file mode 100644 index c1a374c306..0000000000 --- a/WordPress/Tests/WP/TimezoneChangeUnitTest.inc +++ /dev/null @@ -1,8 +0,0 @@ - => - */ - public function getErrorList() { - return array( - 3 => 1, - ); - } - - /** - * Returns the lines where warnings should occur. - * - * @return array => - */ - public function getWarningList() { - return array( - 1 => 2, - ); - } - -} diff --git a/WordPress/ruleset.xml b/WordPress/ruleset.xml index 20ff9a38cc..fd24ae6318 100644 --- a/WordPress/ruleset.xml +++ b/WordPress/ruleset.xml @@ -8,10 +8,6 @@ --> - - - - - + From 2f3ac91307f1c6907192ef2c55ba2183d818bf84 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Apr 2020 19:00:00 +0200 Subject: [PATCH 009/822] Replace the `WordPress.CodeAnalysis.EmptyStatement` sniff ... with the same sniff as merged upstream in PHPCS as `Generic.CodeAnalysis.EmptyPHPStatement` in PHPCS 3.4.0. Fixes 1523 --- WordPress-Core/ruleset.xml | 2 +- .../CodeAnalysis/EmptyStatementSniff.php | 161 ------------------ .../CodeAnalysis/EmptyStatementUnitTest.1.inc | 52 ------ .../EmptyStatementUnitTest.1.inc.fixed | 47 ----- .../CodeAnalysis/EmptyStatementUnitTest.2.inc | 2 - .../CodeAnalysis/EmptyStatementUnitTest.php | 67 -------- 6 files changed, 1 insertion(+), 330 deletions(-) delete mode 100644 WordPress/Sniffs/CodeAnalysis/EmptyStatementSniff.php delete mode 100644 WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.1.inc delete mode 100644 WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.1.inc.fixed delete mode 100644 WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.2.inc delete mode 100644 WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.php diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 0bff5a0d43..9a8f2712c7 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -479,7 +479,7 @@ - + diff --git a/WordPress/Sniffs/CodeAnalysis/EmptyStatementSniff.php b/WordPress/Sniffs/CodeAnalysis/EmptyStatementSniff.php deleted file mode 100644 index 21e2201469..0000000000 --- a/WordPress/Sniffs/CodeAnalysis/EmptyStatementSniff.php +++ /dev/null @@ -1,161 +0,0 @@ -tokens[ $stackPtr ]['type'] ) { - /* - * Detect `something();;`. - */ - case 'T_SEMICOLON': - $prevNonEmpty = $this->phpcsFile->findPrevious( - Tokens::$emptyTokens, - ( $stackPtr - 1 ), - null, - true - ); - - if ( false === $prevNonEmpty - || ( \T_SEMICOLON !== $this->tokens[ $prevNonEmpty ]['code'] - && \T_OPEN_TAG !== $this->tokens[ $prevNonEmpty ]['code'] - && \T_OPEN_TAG_WITH_ECHO !== $this->tokens[ $prevNonEmpty ]['code'] ) - ) { - return; - } - - if ( isset( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) { - $nested = $this->tokens[ $stackPtr ]['nested_parenthesis']; - $last_closer = array_pop( $nested ); - if ( isset( $this->tokens[ $last_closer ]['parenthesis_owner'] ) - && \T_FOR === $this->tokens[ $this->tokens[ $last_closer ]['parenthesis_owner'] ]['code'] - ) { - // Empty for() condition. - return; - } - } - - $fix = $this->phpcsFile->addFixableWarning( - 'Empty PHP statement detected: superfluous semi-colon.', - $stackPtr, - 'SemicolonWithoutCodeDetected' - ); - if ( true === $fix ) { - $this->phpcsFile->fixer->beginChangeset(); - - if ( \T_OPEN_TAG === $this->tokens[ $prevNonEmpty ]['code'] - || \T_OPEN_TAG_WITH_ECHO === $this->tokens[ $prevNonEmpty ]['code'] - ) { - /* - * Check for superfluous whitespace after the semi-colon which will be - * removed as the `tokens[ ( $stackPtr + 1 ) ]['code'] ) { - $replacement = str_replace( ' ', '', $this->tokens[ ( $stackPtr + 1 ) ]['content'] ); - $this->phpcsFile->fixer->replaceToken( ( $stackPtr + 1 ), $replacement ); - } - } - - for ( $i = $stackPtr; $i > $prevNonEmpty; $i-- ) { - if ( \T_SEMICOLON !== $this->tokens[ $i ]['code'] - && \T_WHITESPACE !== $this->tokens[ $i ]['code'] - ) { - break; - } - $this->phpcsFile->fixer->replaceToken( $i, '' ); - } - - $this->phpcsFile->fixer->endChangeset(); - } - break; - - /* - * Detect ``. - */ - case 'T_CLOSE_TAG': - $prevNonEmpty = $this->phpcsFile->findPrevious( - \T_WHITESPACE, - ( $stackPtr - 1 ), - null, - true - ); - - if ( false === $prevNonEmpty - || ( \T_OPEN_TAG !== $this->tokens[ $prevNonEmpty ]['code'] - && \T_OPEN_TAG_WITH_ECHO !== $this->tokens[ $prevNonEmpty ]['code'] ) - ) { - return; - } - - $fix = $this->phpcsFile->addFixableWarning( - 'Empty PHP open/close tag combination detected.', - $prevNonEmpty, - 'EmptyPHPOpenCloseTagsDetected' - ); - if ( true === $fix ) { - $this->phpcsFile->fixer->beginChangeset(); - for ( $i = $prevNonEmpty; $i <= $stackPtr; $i++ ) { - $this->phpcsFile->fixer->replaceToken( $i, '' ); - } - $this->phpcsFile->fixer->endChangeset(); - } - break; - - default: - /* Deliberately left empty. */ - break; - } - } - -} diff --git a/WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.1.inc b/WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.1.inc deleted file mode 100644 index 5017e7b7aa..0000000000 --- a/WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.1.inc +++ /dev/null @@ -1,52 +0,0 @@ - - - - -/* - * Test empty statement: no code between PHP open and close tag. - */ - - - - - - - - - - - - - - - - - - - - -/* - * Test empty statement: no code between PHP open and close tag. - */ - - - - - - - - - - - - - - - -" /> - diff --git a/WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.php b/WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.php deleted file mode 100644 index 7c0d72be94..0000000000 --- a/WordPress/Tests/CodeAnalysis/EmptyStatementUnitTest.php +++ /dev/null @@ -1,67 +0,0 @@ - => - */ - public function getErrorList() { - return array(); - } - - /** - * Returns the lines where warnings should occur. - * - * @param string $testFile The name of the file being tested. - * - * @return array => - */ - public function getWarningList( $testFile = '' ) { - switch ( $testFile ) { - case 'EmptyStatementUnitTest.1.inc': - return array( - 9 => 1, - 12 => 1, - 15 => 1, - 18 => 1, - 21 => 1, - 22 => 1, - 31 => 1, - 33 => 1, - 43 => 1, - 45 => 1, - ); - - case 'EmptyStatementUnitTest.2.inc': - return array( - 1 => 1, // Internal.NoCode warning when short open tags is off, otherwise EmptyStatement warning. - 2 => 1, - ); - - default: - return array(); - } - } - -} From 1d6df5f9cde72ca04aab2719994e6735d0f13169 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Apr 2020 19:19:03 +0200 Subject: [PATCH 010/822] Replace the `WordPress.PHP.DisallowShortTernary` sniff ... with the same sniff as merged upstream in PHPCSExtra as `Universal.Operators.DisallowShortTernary`. --- WordPress-Core/ruleset.xml | 2 +- .../Docs/PHP/DisallowShortTernaryStandard.xml | 20 ------ .../Sniffs/PHP/DisallowShortTernarySniff.php | 65 ------------------- .../PHP/DisallowShortTernaryUnitTest.inc | 12 ---- .../PHP/DisallowShortTernaryUnitTest.php | 46 ------------- 5 files changed, 1 insertion(+), 144 deletions(-) delete mode 100644 WordPress/Docs/PHP/DisallowShortTernaryStandard.xml delete mode 100644 WordPress/Sniffs/PHP/DisallowShortTernarySniff.php delete mode 100644 WordPress/Tests/PHP/DisallowShortTernaryUnitTest.inc delete mode 100644 WordPress/Tests/PHP/DisallowShortTernaryUnitTest.php diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 0bff5a0d43..aa10b71f35 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -378,7 +378,7 @@ https://github.com/WordPress/WordPress-Coding-Standards/issues/643 --> - + - + diff --git a/WordPress/Docs/WhiteSpace/DisallowInlineTabsStandard.xml b/WordPress/Docs/WhiteSpace/DisallowInlineTabsStandard.xml deleted file mode 100644 index 16f1da2fb9..0000000000 --- a/WordPress/Docs/WhiteSpace/DisallowInlineTabsStandard.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - [space]=> 'lor', - 'b'[space][space][space]=> 'em', -); - ]]> - - - [tab]=> 'lor', - 'b'[tab]=> 'em', -); - ]]> - - - diff --git a/WordPress/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php b/WordPress/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php deleted file mode 100644 index c20a4d33e6..0000000000 --- a/WordPress/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php +++ /dev/null @@ -1,104 +0,0 @@ -tab_width ) ) { - $this->tab_width = PHPCSHelper::get_tab_width( $this->phpcsFile ); - } - - $check_tokens = array( - \T_WHITESPACE => true, - \T_DOC_COMMENT_WHITESPACE => true, - \T_DOC_COMMENT_STRING => true, - ); - - for ( $i = ( $stackPtr + 1 ); $i < $this->phpcsFile->numTokens; $i++ ) { - // Skip all non-whitespace tokens and skip whitespace at the start of a new line. - if ( ! isset( $check_tokens[ $this->tokens[ $i ]['code'] ] ) || 1 === $this->tokens[ $i ]['column'] ) { - continue; - } - - // If tabs are being converted to spaces by the tokenizer, the - // original content should be checked instead of the converted content. - if ( isset( $this->tokens[ $i ]['orig_content'] ) ) { - $content = $this->tokens[ $i ]['orig_content']; - } else { - $content = $this->tokens[ $i ]['content']; - } - - if ( '' === $content || strpos( $content, "\t" ) === false ) { - continue; - } - - $fix = $this->phpcsFile->addFixableError( - 'Spaces must be used for mid-line alignment; tabs are not allowed', - $i, - 'NonIndentTabsUsed' - ); - if ( true === $fix ) { - if ( isset( $this->tokens[ $i ]['orig_content'] ) ) { - // Use the replacement that PHPCS has already done. - $this->phpcsFile->fixer->replaceToken( $i, $this->tokens[ $i ]['content'] ); - } else { - // Replace tabs with spaces, using an indent of $tab_width. - // Other sniffs can then correct the indent if they need to. - $spaces = str_repeat( ' ', $this->tab_width ); - $newContent = str_replace( "\t", $spaces, $this->tokens[ $i ]['content'] ); - $this->phpcsFile->fixer->replaceToken( $i, $newContent ); - } - } - } - - // Ignore the rest of the file. - return ( $this->phpcsFile->numTokens + 1 ); - } - -} diff --git a/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.inc b/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.inc deleted file mode 100644 index 5d7178c14d..0000000000 --- a/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.inc +++ /dev/null @@ -1,39 +0,0 @@ -tokens[ $closer ]['column'] - 1 ); - $error = 'Array closer not aligned correctly; expected %s space(s) but found %s'; - $data = array( - $expected_value => 'data', - $found => 'more_data', - ); - -/** - * @param int $var Description - Bad: alignment using tabs. - * @param string $string Another description. - */ - - $expected = ( $column - 1 ); - $found = ( $this->tokens[ $closer ]['column'] - 1 ); // Bad. - $error = 'Array closer not aligned correctly; expected %s space(s) but found %s'; // Bad. - $data = array( // Bad. - $expected_value => 'data', - $found => 'more_data', // Bad. - ); - -/* - * Test that the tab replacements do not negatively influence the existing mid-line alignments. - */ -$a = true; -$aa = true; -$aaa = true; -$aaaa = true; -$aaaaa = true; -$aaaaaa = true; -$aaaaaaa = true; -$aaaaaaaa = true; diff --git a/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.inc.fixed b/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.inc.fixed deleted file mode 100644 index 20f2877f69..0000000000 --- a/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.inc.fixed +++ /dev/null @@ -1,39 +0,0 @@ -tokens[ $closer ]['column'] - 1 ); - $error = 'Array closer not aligned correctly; expected %s space(s) but found %s'; - $data = array( - $expected_value => 'data', - $found => 'more_data', - ); - -/** - * @param int $var Description - Bad: alignment using tabs. - * @param string $string Another description. - */ - - $expected = ( $column - 1 ); - $found = ( $this->tokens[ $closer ]['column'] - 1 ); // Bad. - $error = 'Array closer not aligned correctly; expected %s space(s) but found %s'; // Bad. - $data = array( // Bad. - $expected_value => 'data', - $found => 'more_data', // Bad. - ); - -/* - * Test that the tab replacements do not negatively influence the existing mid-line alignments. - */ -$a = true; -$aa = true; -$aaa = true; -$aaaa = true; -$aaaaa = true; -$aaaaaa = true; -$aaaaaaa = true; -$aaaaaaaa = true; diff --git a/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php b/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php deleted file mode 100644 index edaac2c7ea..0000000000 --- a/WordPress/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php +++ /dev/null @@ -1,73 +0,0 @@ -tabWidth = $this->tab_width; - } - - /** - * Returns the lines where errors should occur. - * - * @return array => - */ - public function getErrorList() { - return array( - 17 => 1, - 22 => 1, - 23 => 1, - 24 => 1, - 26 => 1, - 32 => 1, - 33 => 1, - 34 => 1, - 35 => 1, - 36 => 1, - 37 => 1, - ); - } - - /** - * Returns the lines where warnings should occur. - * - * @return array => - */ - public function getWarningList() { - return array(); - } - -} From 00b895c92f41a49923c37df58b370b801080a204 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 30 Jun 2020 08:14:19 +0200 Subject: [PATCH 012/822] Tests/RestrictedClasses: compatibility with PHPCS 4.x PHPCS 4.x is set up to use PHPUnit 8+, including using the `void` return type for the `setUp[BeforeClass]()` and `tearDown[AfterClass]()` fixtures. This commit makes our tests compatible with both PHPCS 3.x as well as 4.x and with PHPUnit < 8 and 8+. This is done by: * Renaming the fixtures in use in our test suite to use a different method name (only this class). * And using the PHPUnit `@before` and `@after` annotations, which translate to `setUp()` and `tearDown()` to get round the `void` return type requirement. --- WordPress/Tests/DB/RestrictedClassesUnitTest.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/WordPress/Tests/DB/RestrictedClassesUnitTest.php b/WordPress/Tests/DB/RestrictedClassesUnitTest.php index b5df274d02..183af9717a 100644 --- a/WordPress/Tests/DB/RestrictedClassesUnitTest.php +++ b/WordPress/Tests/DB/RestrictedClassesUnitTest.php @@ -19,6 +19,7 @@ * * @since 0.10.0 * @since 0.13.0 Class name changed: this class is now namespaced. + * @since 3.0.0 Renamed the fixtures to create compatibility with PHPCS 4.x/PHPUnit >=8. */ class RestrictedClassesUnitTest extends AbstractSniffUnitTest { @@ -28,8 +29,10 @@ class RestrictedClassesUnitTest extends AbstractSniffUnitTest { * * Note: as that class extends the abstract FunctionRestrictions class, that's * where we are passing the parameters to. + * + * @before */ - protected function setUp() { + protected function enhanceGroups() { parent::setUp(); AbstractFunctionRestrictionsSniff::$unittest_groups = array( @@ -46,8 +49,10 @@ protected function setUp() { /** * Reset the $groups property. + * + * @after */ - protected function tearDown() { + protected function resetGroups() { AbstractFunctionRestrictionsSniff::$unittest_groups = array(); parent::tearDown(); } From 8d52417615676068165a9a9bf53cb3fc8110f268 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 10 Apr 2020 19:06:12 +0200 Subject: [PATCH 013/822] TypeCasts: remove sniffing for `T_STRING_CAST` That token is no longer needed as the tokenization in PHPCS upstream was fixed in PHPCS 3.4.0. Fixes 1600 --- WordPress/Sniffs/PHP/TypeCastsSniff.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/WordPress/Sniffs/PHP/TypeCastsSniff.php b/WordPress/Sniffs/PHP/TypeCastsSniff.php index 7aded55fec..f41cce5f5d 100644 --- a/WordPress/Sniffs/PHP/TypeCastsSniff.php +++ b/WordPress/Sniffs/PHP/TypeCastsSniff.php @@ -38,7 +38,6 @@ public function register() { return array( \T_DOUBLE_CAST, \T_UNSET_CAST, - \T_STRING_CAST, \T_BINARY_CAST, ); } @@ -80,12 +79,7 @@ public function process_token( $stackPtr ) { ); break; - case \T_STRING_CAST: case \T_BINARY_CAST: - if ( \T_STRING_CAST === $token_code && '(binary)' !== $typecast_lc ) { - break; - } - $this->phpcsFile->addWarning( 'Using binary casting is strongly discouraged. Found: "%s"', $stackPtr, From f092f0dcba9ef48ccb2e24f6ea4afc5585e6d1bc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 1 Jul 2020 18:35:52 +0200 Subject: [PATCH 014/822] Tests: improve language used in inline comments ... which explain what something is testing and/or what has changed. --- .../Tests/DB/PreparedSQLPlaceholdersUnitTest.inc | 6 +++--- .../Tests/DB/PreparedSQLPlaceholdersUnitTest.php | 4 ++-- WordPress/Tests/DB/PreparedSQLUnitTest.inc | 4 ++-- WordPress/Tests/DB/PreparedSQLUnitTest.php | 4 ++-- .../NamingConventions/PrefixAllGlobalsUnitTest.1.inc | 2 +- .../NamingConventions/PrefixAllGlobalsUnitTest.php | 6 +++--- WordPress/Tests/PHP/StrictComparisonsUnitTest.inc | 2 +- WordPress/Tests/PHP/StrictComparisonsUnitTest.php | 2 +- WordPress/Tests/Security/EscapeOutputUnitTest.inc | 2 +- WordPress/Tests/Security/EscapeOutputUnitTest.php | 12 ++++++------ .../Tests/Security/NonceVerificationUnitTest.inc | 2 +- .../Tests/Security/NonceVerificationUnitTest.php | 2 +- .../Security/ValidatedSanitizedInputUnitTest.inc | 2 +- .../Security/ValidatedSanitizedInputUnitTest.php | 2 +- WordPress/Tests/WP/CapitalPDangitUnitTest.inc | 2 +- WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed | 2 +- WordPress/Tests/WP/CapitalPDangitUnitTest.php | 2 +- .../Tests/WP/GlobalVariablesOverrideUnitTest.1.inc | 2 +- .../Tests/WP/GlobalVariablesOverrideUnitTest.php | 2 +- .../WhiteSpace/PrecisionAlignmentUnitTest.1.inc | 2 +- .../Tests/WhiteSpace/PrecisionAlignmentUnitTest.php | 2 +- 21 files changed, 33 insertions(+), 33 deletions(-) diff --git a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc index 04548fc74d..60cdc8b008 100644 --- a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.inc @@ -59,13 +59,13 @@ $sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login $replacements = [1, "admin", $variable]; $sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", $replacements ); // Bad. -$sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", $replacements ); // Bad - old-style whitelist comment. WPCS: PreparedSQLPlaceholders replacement count OK. +$sql = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", $replacements ); // Bad - old-style ignore comment. WPCS: PreparedSQLPlaceholders replacement count OK. // Valid test case as found in WP core /wp-admin/includes/export.php $esses = array_fill( 0, count($post_types), '%s' ); $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); // Warning. -// Testing that whitelist comment work for this mismatch too. -$where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); // Bad - old-style whitelist comment. WPCS: PreparedSQLPlaceholders replacement count OK. +// Testing that ignore comment works for this mismatch too. +$where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types ); // Bad - old-style ignore comment. WPCS: PreparedSQLPlaceholders replacement count OK. /* * Test correctly recognizing queries using IN in combination with dynamic placeholder creation. diff --git a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php index e8446786cb..68c908da66 100644 --- a/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLPlaceholdersUnitTest.php @@ -85,9 +85,9 @@ public function getWarningList() { 57 => 1, 58 => 1, 61 => 1, - 62 => 1, // Old-style WPCS whitelist comments are no longer supported. + 62 => 1, // Old-style WPCS ignore comments are no longer supported. 66 => 1, - 68 => 1, // Old-style WPCS whitelist comments are no longer supported. + 68 => 1, // Old-style WPCS ignore comments are no longer supported. 126 => 1, 139 => 1, 160 => 2, diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.inc index b09bfdb8e5..3fa34f89e7 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.inc @@ -8,8 +8,8 @@ $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '$var';" ) ); // Bad. $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE %s;", $_GET['title'] ) ); // Ok. -$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . $escaped_var . "';" ); // Bad: old-style whitelist comment. WPCS: unprepared SQL OK. -$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '{$escaped_var}';" ); // Bad: old-style whitelist comment. WPCS: unprepared SQL OK. +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . $escaped_var . "';" ); // Bad: old-style ignore comment. WPCS: unprepared SQL OK. +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '{$escaped_var}';" ); // Bad: old-style ignore comment. WPCS: unprepared SQL OK. $wpdb->query( $wpdb->prepare( "SELECT SUBSTRING( post_name, %d + 1 ) REGEXP '^[0-9]+$'", array( 123 ) ) ); // Ok. $wpdb->query( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_title = 'The \$_GET var can be evil.' AND ID = %s", array( 123 ) ) ); // Ok. diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.php b/WordPress/Tests/DB/PreparedSQLUnitTest.php index 329baaa3cc..78e484a076 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.php @@ -36,8 +36,8 @@ public function getErrorList() { 5 => 1, 7 => 1, 8 => 1, - 11 => 1, // Old-style WPCS whitelist comments are no longer supported. - 12 => 1, // Old-style WPCS whitelist comments are no longer supported. + 11 => 1, // Old-style WPCS ignore comments are no longer supported. + 12 => 1, // Old-style WPCS ignore comments are no longer supported. 16 => 1, 17 => 1, 18 => 1, diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index 6290ff07f2..c5212b1042 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -207,7 +207,7 @@ if ( ! defined( 'PHP_VERSION_ID' ) ) { } /* - * Bad - whitelisted via old-style whitelist comment. + * Bad - ignored via old-style ignore comment. */ $something = 'abc'; // WPCS: prefix ok. diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php index 85d41bc79b..b6ace2e4e0 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php @@ -51,9 +51,9 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) { 39 => 1, 40 => 1, 90 => 1, - 212 => 1, // Old-style WPCS whitelist comments are no longer supported. - 215 => 1, // Old-style WPCS whitelist comments are no longer supported. - 216 => 1, // Old-style WPCS whitelist comments are no longer supported. + 212 => 1, // Old-style WPCS ignore comments are no longer supported. + 215 => 1, // Old-style WPCS ignore comments are no longer supported. + 216 => 1, // Old-style WPCS ignore comments are no longer supported. // Backfills. 225 => ( function_exists( '\mb_strpos' ) ) ? 0 : 1, 230 => ( function_exists( '\array_column' ) ) ? 0 : 1, diff --git a/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc b/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc index 17da61c0d3..507e7f1277 100644 --- a/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc +++ b/WordPress/Tests/PHP/StrictComparisonsUnitTest.inc @@ -15,7 +15,7 @@ if ( true != $true ) { // Bad. echo 'False'; } -// Bad - whitelisted via old-style whitelist comment. +// Bad - ignored via old-style ignore comment. if ( true == $true ) { // Loose comparison, OK. echo 'True'; } diff --git a/WordPress/Tests/PHP/StrictComparisonsUnitTest.php b/WordPress/Tests/PHP/StrictComparisonsUnitTest.php index ec3d970412..1648efab9e 100644 --- a/WordPress/Tests/PHP/StrictComparisonsUnitTest.php +++ b/WordPress/Tests/PHP/StrictComparisonsUnitTest.php @@ -40,7 +40,7 @@ public function getWarningList() { 3 => 1, 10 => 1, 12 => 1, - 19 => 1, // Old-style WPCS whitelist comments are no longer supported. + 19 => 1, // Old-style WPCS ignore comments are no longer supported. ); } diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.inc index 1926aad635..777c72e6dc 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.inc @@ -121,7 +121,7 @@ wp_die( -1 ); // Ok. 1, 114 => 1, 125 => 1, - 126 => 1, // Old-style WPCS whitelist comments are no longer supported. - 127 => 1, // Old-style WPCS whitelist comments are no longer supported. - 128 => 1, // Old-style WPCS whitelist comments are no longer supported. + 126 => 1, // Old-style WPCS ignore comments are no longer supported. + 127 => 1, // Old-style WPCS ignore comments are no longer supported. + 128 => 1, // Old-style WPCS ignore comments are no longer supported. 131 => 1, 135 => 1, 138 => 1, @@ -76,9 +76,9 @@ public function getErrorList() { 223 => 1, 225 => 1, 226 => 1, - 241 => 1, // Old-style WPCS whitelist comments are no longer supported. - 245 => 1, // Old-style WPCS whitelist comments are no longer supported. - 249 => 1, // Old-style WPCS whitelist comments are no longer supported. + 241 => 1, // Old-style WPCS ignore comments are no longer supported. + 245 => 1, // Old-style WPCS ignore comments are no longer supported. + 249 => 1, // Old-style WPCS ignore comments are no longer supported. 252 => 1, 253 => 1, 263 => 1, diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.inc index cbfe01cbc7..4f60f45aec 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.inc @@ -83,7 +83,7 @@ function foo_2() { $_POST['settings'][ $setting ] = 'bb'; // OK. } -// Bad - whitelisted via old-style whitelist comment. +// Bad - ignored via old-style ignore comment. function foo_3() { bar( $_POST['var'] ); // WPCS: CSRF OK. bar( $_POST['var'] ); // Bad. diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.php b/WordPress/Tests/Security/NonceVerificationUnitTest.php index b53d02997d..825c5f289e 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.php +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.php @@ -36,7 +36,7 @@ public function getErrorList() { 44 => 1, 48 => 1, 69 => 1, - 88 => 1, // Old-style WPCS whitelist comments are no longer supported. + 88 => 1, // Old-style WPCS ignore comments are no longer supported. 89 => 1, 113 => 1, 114 => 1, diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc index 005c2475f7..12f9f65309 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc @@ -73,7 +73,7 @@ function zebra() { } } -echo $_GET['test']; // Bad: old-style whitelist comment. WPCS: sanitization OK. +echo $_GET['test']; // Bad: old-style ignore comment. WPCS: sanitization OK. echo array_map( 'sanitize_text_field', wp_unslash( $_GET['test'] ) ); // Ok. echo array_map( 'foo', wp_unslash( $_GET['test'] ) ); // Bad. diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php index f1ba1e7949..8643c2a78d 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php @@ -35,7 +35,7 @@ public function getErrorList() { 20 => 1, 33 => 3, 65 => 1, - 76 => 2, // Old-style WPCS whitelist comments are no longer supported. + 76 => 2, // Old-style WPCS ignore comments are no longer supported. 79 => 1, 80 => 1, 81 => 1, diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc index 1a9fc3b723..1f197ec6e5 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc @@ -162,7 +162,7 @@ $installed = self::check_plugin_is_installed( 'wordpress-importer' ); // OK. /* - * Bad - whitelisted via old-style whitelist comment. + * Bad - ignored via old-style ignore comment. */ echo 'This is an explanation about wordpress.'; // WPCS: spelling ok. diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed index a711174177..44d2e489d4 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.inc.fixed @@ -162,7 +162,7 @@ $installed = self::check_plugin_is_installed( 'wordpress-importer' ); // OK. /* - * Bad - whitelisted via old-style whitelist comment. + * Bad - ignored via old-style ignore comment. */ echo 'This is an explanation about WordPress.'; // WPCS: spelling ok. diff --git a/WordPress/Tests/WP/CapitalPDangitUnitTest.php b/WordPress/Tests/WP/CapitalPDangitUnitTest.php index fa5f0bd835..0e6d2b268a 100644 --- a/WordPress/Tests/WP/CapitalPDangitUnitTest.php +++ b/WordPress/Tests/WP/CapitalPDangitUnitTest.php @@ -59,7 +59,7 @@ public function getWarningList() { 101 => 1, 139 => 1, 146 => 0, // False negative. - 167 => 1, // Old-style WPCS whitelist comments are no longer supported. + 167 => 1, // Old-style WPCS ignore comments are no longer supported. 173 => 1, 181 => 1, ); diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc index 5725b13c93..5d1c4ada4d 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc @@ -8,7 +8,7 @@ $wpdb = 'test'; // Bad. $post = get_post( 1 ); // Bad. global $post; -$post = get_post( 1 ); // Bad: old-style whitelist comment. Override ok. +$post = get_post( 1 ); // Bad: old-style ignore comment. Override ok. // Bad: Using different types of assignment operators. function test_different_assignment_operators() { diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php index 83fcb3c1da..b7700ed669 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.php @@ -37,7 +37,7 @@ public function getErrorList( $testFile = '' ) { 3 => 1, 6 => 1, 8 => 1, - 11 => 1, // Old-style WPCS whitelist comments are no longer supported. + 11 => 1, // Old-style WPCS ignore comments are no longer supported. 16 => 1, 17 => 1, 18 => 1, diff --git a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc index bcf06fe102..f7b840b0c4 100644 --- a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc +++ b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.1.inc @@ -31,7 +31,7 @@ function exampleFunctionE() {} // Bad: [tab][space][space]. function exampleFunctionF() {} // Bad: [tab][space][space][space]. - function exampleFunctionG() {} // Bad old-style whitelist comment: WPCS: precision alignment ok. + function exampleFunctionG() {} // Bad old-style ignore comment: WPCS: precision alignment ok. ?> diff --git a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php index 32757ee5fb..0b03b8f1fb 100644 --- a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php +++ b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.php @@ -69,7 +69,7 @@ public function getWarningList( $testFile = '' ) { 30 => 1, 31 => 1, 32 => 1, - 34 => 1, // Old-style WPCS whitelist comments are no longer supported. + 34 => 1, // Old-style WPCS ignore comments are no longer supported. 39 => 1, 65 => 1, ); From 22b85df02851cb119d9a232932a5be65b9df5c18 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 1 Jul 2020 18:33:04 +0200 Subject: [PATCH 015/822] CONTRIBUTING: remove section about the WPCS native selective ignore comments ... as support for those is now completely removed. --- .github/CONTRIBUTING.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 21453cd37a..dc8adf1b22 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -32,14 +32,6 @@ 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/WordPress-Coding-Standards/wiki/Customizable-sniff-properties) with the relevant details once your PR has been merged into the `develop` branch. -## Whitelist comments - -> **Important**: -> PHPCS 3.2.0 introduced new selective ignore annotations, which can be considered an improved version of the whitelist mechanism which WPCS contains. -> -> Support for the WPCS native whitelist comments has been deprecated in WPCS 2.0.0 and removed in WPCS 3.0.0. - - # Unit Testing ## Pre-requisites From d8ed55fb773baf393a039bace3355ed503d48fde Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 1 Jul 2020 18:41:06 +0200 Subject: [PATCH 016/822] README: fix language of header referring to ignore comments --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 42eda804b6..908d032f2c 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ + [Using PHPCS and WPCS from within your IDE](#using-phpcs-and-wpcs-from-within-your-ide) * [Running your code through WPCS automatically using CI tools](#running-your-code-through-wpcs-automatically-using-ci-tools) + [Travis CI](#travis-ci) -* [Fixing errors or whitelisting them](#fixing-errors-or-whitelisting-them) +* [Fixing errors or ignoring them](#fixing-errors-or-ignoring-them) + [Tools shipped with WPCS](#tools-shipped-with-wpcs) * [Contributing](#contributing) * [License](#license) @@ -267,7 +267,7 @@ script: More examples and advice about integrating PHPCS in your Travis build tests can be found here: https://github.com/jrfnl/make-phpcs-work-for-you/tree/master/travis-examples -## Fixing errors or whitelisting them +## Fixing errors or ignoring them You can find information on how to deal with some of the more frequent issues in the [wiki](https://github.com/WordPress/WordPress-Coding-Standards/wiki). From 953d7a9f199b66c67a85d3b39bdaeb1898ce7e66 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 30 Jun 2020 08:49:27 +0200 Subject: [PATCH 017/822] Replace the `WordPress.PHP.StrictComparisons` sniff ... with a similar sniff as merged upstream in PHPCSExtra as `Universal.Operators.StrictComparisons`. Notes: * The sniff in PHPCSExtra contains a fixer. As this is a risky fixer, this fixer is turned off for WPCS. * The sniff in PHPCSExtra will provide metrics about loose versus strict comparisons. --- WordPress-Core/ruleset.xml | 4 +- .../Sniffs/PHP/StrictComparisonsSniff.php | 54 ------------------- .../Tests/PHP/StrictComparisonsUnitTest.inc | 21 -------- .../Tests/PHP/StrictComparisonsUnitTest.php | 47 ---------------- bin/class-ruleset-test.php | 2 +- 5 files changed, 4 insertions(+), 124 deletions(-) delete mode 100644 WordPress/Sniffs/PHP/StrictComparisonsSniff.php delete mode 100644 WordPress/Tests/PHP/StrictComparisonsUnitTest.inc delete mode 100644 WordPress/Tests/PHP/StrictComparisonsUnitTest.php diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 0d0a55c9e0..f1449bcb8a 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -406,7 +406,9 @@ - + + warning + - + - + From 1914ebf19730e1da74814c64b6fcfc0374faf11e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 30 Jun 2020 08:57:25 +0200 Subject: [PATCH 026/822] Core ruleset: add PHPCSUtils requirement PHPCSUtils does not contain any sniffs, so adding this rule isn't strictly necessary, but by having the rule in the ruleset anyway, if PHPCSUtils is missing, the user will get a descriptive error message during the loading of the ruleset instead of a fatal "class not found" error once the sniffs start running. Adding this only in the `Core` ruleset is sufficient. Both `Extra` as well as `WordPress` include `Core` and `Docs` currently doesn't use any sniffs which use PHPCSUtils, so doesn't need it. --- WordPress-Core/ruleset.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 18be74004a..e3b77923c2 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -6,6 +6,15 @@ + + + -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] My_TestClass +phpcs:set WordPress.Files.FileName custom_test_classes[] My_TestClass -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample -phpcs:set WordPress.Files.FileName custom_test_class_whitelist[] Some\Name\TestSample +phpcs:set WordPress.Files.FileName custom_test_classes[] Some\Name\TestSample Date: Thu, 25 Feb 2021 21:28:37 +0100 Subject: [PATCH 090/822] Security/EscapeOutput: bug fix - allow for basename() being fully qualified --- WordPress/Sniffs/Security/EscapeOutputSniff.php | 2 +- WordPress/Tests/Security/EscapeOutputUnitTest.inc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index d70d7fe898..09cd206ff3 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -218,7 +218,7 @@ public function process_token( $stackPtr ) { } // Quick check. This disregards comments. - if ( preg_match( '`^basename\s*\(\s*__FILE__\s*\)$`', $first_param['raw'] ) === 1 ) { + if ( preg_match( '`^[\\\\]?basename\s*\(\s*__FILE__\s*\)$`', $first_param['raw'] ) === 1 ) { $stackPtr = ( $first_param['end'] + 2 ); } unset( $first_param ); diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.inc index e9fb752ce7..e5a3422869 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.inc @@ -298,3 +298,5 @@ _deprecated_file( $file, '1.3.0' ); // Error. trigger_error(); // Ignore. _deprecated_file(); // Ignore. + +\_deprecated_file( \basename( __FILE__ ), '1.3.0' ); // Ok. From 7c3f949c7af768d42a5b60bee7e1afa878ca4e38 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 6 Apr 2021 15:58:58 +0200 Subject: [PATCH 091/822] GH Actions: don't test against PHPCS 4.x (yet) As it looks like PHPCS 4.x is still quite a while away (2022 at the earliest), let's stop testing against PHPCS 4.x for the time being. This should allow build failure reporting to be more accurate, as currently every PR has a failure on PHPCS 4.x due to a bug in some of the new code in 4.x (fix for this was pulled six months ago and still not merged). The build against PHPCS 4.x should be re-enabled closer to the PHPCS 4.x release. Note: PHPCSUtils will continue to test against PHPCS 4.x and will update the provided utilities ahead of time, so with a bit of luck, by the time the build against PHPCS 4.x is re-enabled, the build should largely pass thanks to the compatibility layers in PHPCSUtils. --- .github/workflows/unit-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index d147612118..9526b9c4b9 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -40,9 +40,9 @@ jobs: phpcs_version: '3.5.7' allowed_failure: false # Add extra build to test against PHPCS 4. - - php: '7.4' - phpcs_version: '4.0.x-dev as 3.9.99' - allowed_failure: true + #- php: '7.4' + # phpcs_version: '4.0.x-dev as 3.9.99' + # allowed_failure: true - php: '8.1' phpcs_version: 'dev-master' allowed_failure: true From 880af82fd499d462f59904d3b3e64318addbb1de Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 7 Apr 2021 16:44:29 +0200 Subject: [PATCH 092/822] PHP 8.1 compatibility: fix deprecation notice [1] PHP 8.1 deprecates passing `null` to PHP native functions where the parameter(s) is not explicitly nullable. While in PHP 8.1 this is only a deprecation, it should, of course, still be fixed. This commit contains a fix for the one of the two issues in WordPressCS found related to this so far (based on the unit tests). Passing `null` to `trim()` is now deprecated, so more defensive coding or explicit type casting is needed. This comes into play for the `MinimumWPVersionTrait::get_wp_version_from_cli()` method where the `Helper::getCommandLineData()` method can return either string or `null`. Ref: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html#method_getCommandLineData --- WordPress/Helpers/MinimumWPVersionTrait.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/WordPress/Helpers/MinimumWPVersionTrait.php b/WordPress/Helpers/MinimumWPVersionTrait.php index 3afcd5208e..bf5c65f1f9 100644 --- a/WordPress/Helpers/MinimumWPVersionTrait.php +++ b/WordPress/Helpers/MinimumWPVersionTrait.php @@ -86,8 +86,13 @@ trait MinimumWPVersionTrait { * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. */ protected function get_wp_version_from_cli( File $phpcsFile ) { - $cli_supported_version = trim( Helper::getCommandLineData( $phpcsFile, 'minimum_supported_wp_version' ) ); + $cli_supported_version = Helper::getCommandLineData( $phpcsFile, 'minimum_supported_wp_version' ); + if ( empty( $cli_supported_version ) ) { + return; + } + + $cli_supported_version = trim( $cli_supported_version ); if ( ! empty( $cli_supported_version ) && filter_var( $cli_supported_version, \FILTER_VALIDATE_FLOAT ) !== false ) { From e9c4858f46775e1477639d471894891f64ac92f6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 7 Apr 2021 16:54:52 +0200 Subject: [PATCH 093/822] PHP 8.1 compatibility: fix deprecation notice [2] PHP 8.1 deprecates passing `null` to PHP native functions where the parameter(s) is not explicitly nullable. While in PHP 8.1 this is only a deprecation, it should, of course, still be fixed. This commit contains a fix for the second of the two issues in WordPressCS found related to this so far (based on the unit tests). Passing `null` to `trim()` is now deprecated, so more defensive coding or explicit type casting is needed. This comes into play for the `I18nSniff::process_token()` and the `PrefixAllGlobalsSniff::process_token()` methods where the `Helper::getConfigData()` method can return either string or `null`. Ref: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html#method_getConfigData --- .../Sniffs/NamingConventions/PrefixAllGlobalsSniff.php | 7 +++++-- WordPress/Sniffs/WP/I18nSniff.php | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index 60bab3d5b1..1d0eceb444 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -272,9 +272,12 @@ public function getGroups() { public function process_token( $stackPtr ) { // Allow overruling the prefixes set in a ruleset via the command line. - $cl_prefixes = trim( Helper::getConfigData( 'prefixes' ) ); + $cl_prefixes = Helper::getConfigData( 'prefixes' ); if ( ! empty( $cl_prefixes ) ) { - $this->prefixes = array_filter( array_map( 'trim', explode( ',', $cl_prefixes ) ) ); + $cl_prefixes = trim( $cl_prefixes ); + if ( '' !== $cl_prefixes ) { + $this->prefixes = array_filter( array_map( 'trim', explode( ',', $cl_prefixes ) ) ); + } } $this->prefixes = $this->merge_custom_array( $this->prefixes, array(), false ); diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 62ddd6342e..41f02661d8 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -192,9 +192,12 @@ public function process_token( $stack_ptr ) { $this->text_domain_is_default = false; // Allow overruling the text_domain set in a ruleset via the command line. - $cl_text_domain = trim( Helper::getConfigData( 'text_domain' ) ); + $cl_text_domain = Helper::getConfigData( 'text_domain' ); if ( ! empty( $cl_text_domain ) ) { - $this->text_domain = array_filter( array_map( 'trim', explode( ',', $cl_text_domain ) ) ); + $cl_text_domain = trim( $cl_text_domain ); + if ( '' !== $cl_text_domain ) { + $this->text_domain = array_filter( array_map( 'trim', explode( ',', $cl_text_domain ) ) ); + } } $this->text_domain = $this->merge_custom_array( $this->text_domain, array(), false ); From 96271f6a26973697de4876bfb945df24988daa72 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 28 Feb 2021 07:43:39 +0100 Subject: [PATCH 094/822] GH Actions: get the tests running on PHP 8.1 (nightly) Letting PHPUnit read the config file causes an error on PHP 8.1 in combination with PHPUnit 7. For now, special case the test run on PHP 8.1 and pass the only necessary config from the configuration file on via CLI arguments. --- .github/workflows/unit-tests.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 9526b9c4b9..40e7511785 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -94,5 +94,10 @@ jobs: if: ${{ matrix.phpcs_version == 'dev-master' }} run: composer lint-ci | cs2pr - - name: Run unit tests + - name: Run the unit tests - PHP 5.4 - 8.0 + if: ${{ matrix.php != '8.1' }} run: composer run-tests + + - name: Run the unit tests - PHP 8.1 + if: ${{ matrix.php == '8.1' }} + run: composer run-tests -- --no-configuration --bootstrap=./Tests/bootstrap.php --dont-report-useless-tests From d710432bae4d43015963dfa2bdaa63fce43c5834 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 28 Feb 2021 07:33:39 +0100 Subject: [PATCH 095/822] GH Actions: report CS violations in the PR The cs2pr tool will allow to display the results from an action run in checkstyle format in-line in the PR code view, which should improve usability of the workflow results. Ref: https://github.com/staabm/annotate-pull-request-from-checkstyle --- .github/workflows/ruleset-checks-sniffs.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index 5462db8384..dd8a108f79 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -38,6 +38,7 @@ jobs: with: php-version: '7.4' coverage: none + tools: cs2pr # Using PHPCS `master` as an early detection system for bugs upstream. - name: Set PHPCS version @@ -57,7 +58,11 @@ jobs: # @link https://github.com/WordPress/WordPress-Coding-Standards # @link http://pear.php.net/package/PHP_CodeSniffer/ - name: Run PHPCS ignoring warnings - run: vendor/bin/phpcs --runtime-set ignore_warnings_on_exit 1 + continue-on-error: true + run: vendor/bin/phpcs --runtime-set ignore_warnings_on_exit 1 --report-full --report-checkstyle=./phpcs-report.xml + + - name: Show PHPCS results in PR + run: cs2pr ./phpcs-report.xml --graceful-warnings # Validate the XML files. # @link http://xmlsoft.org/xmllint.html From d4731efaf5322c66e72769c46ad4bdb12afe62fc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 7 Apr 2021 16:31:59 +0200 Subject: [PATCH 096/822] GH Actions: don't use cs2pr in quicktest ... as the `quicktest` workflow is run on `push` events, not on PRs, so displaying results in a PR is not relevant (and is done via the `test` workflow which _is_ run on `pull` events anyhow). --- .github/workflows/quicktest.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 7085ec8d31..76e09e8bd3 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -55,7 +55,6 @@ jobs: php-version: ${{ matrix.php }} ini-values: ${{ steps.set_ini.outputs.PHP_INI }} coverage: none - tools: cs2pr - name: Set PHPCS version run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts @@ -65,7 +64,7 @@ jobs: - name: Lint PHP files against parse errors if: ${{ matrix.phpcs_version == 'dev-master' }} - run: composer lint-ci | cs2pr + run: composer lint-ci - name: Run unit tests run: composer run-tests From 88c56085b987ea5a0d6b0d1ca85e42db6af1d680 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 22 Sep 2019 19:58:33 +0200 Subject: [PATCH 097/822] OneObjectStructurePerFile: move from `Extra` to `Core` Per the discussion had on Slack about this initiated by GaryJones. WP Core currently has 27 violations against this rule. In `Extra` the error message was changed and downgraded to a `warning`. Now the sniff will be added to `Core`, per this PR, the: * Message text will still be changed a little to be clearer, but will be stricter. * The message will be an `error` and not be downgraded to a `warning`. To do: - [ ] Add a rule to this effect to the handbook. --- WordPress-Core/ruleset.xml | 6 ++++++ WordPress-Extra/ruleset.xml | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index e3b77923c2..89752c350f 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -517,6 +517,12 @@ 0 + + + Best practices: Declare only one class/interface/trait in a file. + + - - - warning - Best practice suggestion: Declare only one class/interface/trait in a file. - - From 4dc9ac66f7f82fc766ba74de294b1458b91df21b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 15 Jun 2021 00:40:30 +0200 Subject: [PATCH 098/822] CS: get rid of "commented out code" warnings ... which show through in PRs, even when the code in those files has not been adjusted in the PR. There's only one such warning remaining now, which is _actual_ commented out code. --- ...bstractArrayAssignmentRestrictionsSniff.php | 8 ++++---- WordPress/AbstractClassRestrictionsSniff.php | 2 +- WordPress/Sniff.php | 2 +- .../ControlStructureSpacingSniff.php | 18 +++++++++--------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/WordPress/AbstractArrayAssignmentRestrictionsSniff.php b/WordPress/AbstractArrayAssignmentRestrictionsSniff.php index d235862f89..df9932bb7d 100644 --- a/WordPress/AbstractArrayAssignmentRestrictionsSniff.php +++ b/WordPress/AbstractArrayAssignmentRestrictionsSniff.php @@ -153,9 +153,9 @@ public function process_token( $stackPtr ) { $inst = array(); /* - * Covers: - * $foo = array( 'bar' => 'taz' ); - * $foo['bar'] = $taz; + * Covers array assignments: + * `$foo = array( 'bar' => 'taz' );` + * `$foo['bar'] = $taz;` */ if ( \in_array( $token['code'], array( \T_CLOSE_SQUARE_BRACKET, \T_DOUBLE_ARROW ), true ) ) { $operator = $stackPtr; // T_DOUBLE_ARROW. @@ -173,7 +173,7 @@ public function process_token( $stackPtr ) { $inst[ $key ][] = array( $val, $token['line'] ); } } elseif ( \in_array( $token['code'], array( \T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING ), true ) ) { - // $foo = 'bar=taz&other=thing'; + // Covers assignments via query parameters: `$foo = 'bar=taz&other=thing';`. if ( preg_match_all( '#(?:^|&)([a-z_]+)=([^&]*)#i', TextStrings::stripQuotes( $token['content'] ), $matches ) <= 0 ) { return; // No assignments here, nothing to check. } diff --git a/WordPress/AbstractClassRestrictionsSniff.php b/WordPress/AbstractClassRestrictionsSniff.php index 882587edf8..612737d91c 100644 --- a/WordPress/AbstractClassRestrictionsSniff.php +++ b/WordPress/AbstractClassRestrictionsSniff.php @@ -150,7 +150,7 @@ public function is_targetted_token( $stackPtr ) { return false; } - // Nothing to do if 'parent', 'self' or 'static'. + // Nothing to do if one of the hierarchy keywords - 'parent', 'self' or 'static' - is used. if ( \in_array( $classname, array( 'parent', 'self', 'static' ), true ) ) { return false; } diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 9413b0fbf9..7b41a4e446 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -1923,7 +1923,7 @@ protected function is_validated( $stackPtr, $array_keys = array(), $in_condition $prev = $i; do { $prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $prev - 1 ), null, true, null, true ); - // Skip over array keys, like $_GET['key']['subkey']. + // Skip over array keys, like `$_GET['key']['subkey']`. if ( \T_CLOSE_SQUARE_BRACKET === $this->tokens[ $prev ]['code'] ) { $prev = $this->tokens[ $prev ]['bracket_opener']; continue; diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php index cbca5fe47c..0cdaf84396 100644 --- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php +++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php @@ -183,7 +183,7 @@ public function process_token( $stackPtr ) { } elseif ( \T_BITWISE_AND === $this->tokens[ $parenthesisOpener ]['code'] ) { - // This function returns by reference (function &function_name() {}). + // This function returns by reference, i.e. `function &function_name() {}`. $parenthesisOpener = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $parenthesisOpener + 1 ), @@ -201,7 +201,7 @@ public function process_token( $stackPtr ) { true ); - // Checking this: function my_function[*](...) {}. + // Checking space between name and open parentheses, i.e. `function my_function[*](...) {}`. if ( ( $function_name_ptr + 1 ) !== $parenthesisOpener ) { $error = 'Space between function name and opening parenthesis is prohibited.'; @@ -247,7 +247,7 @@ public function process_token( $stackPtr ) { ) { if ( ( $stackPtr + 1 ) !== $parenthesisOpener ) { - // Checking this: function[*](...) {}. + // Checking space between keyword and open parenthesis, i.e. `function[*](...) {}`. $error = 'Space before closure opening parenthesis is prohibited'; $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'SpaceBeforeClosureOpenParenthesis' ); @@ -263,7 +263,7 @@ public function process_token( $stackPtr ) { && ( $stackPtr + 1 ) === $parenthesisOpener ) { - // Checking this: if[*](...) {}. + // Checking space between keyword and open parenthesis, i.e. `if[*](...) {}`. $error = 'No space before opening parenthesis is prohibited'; $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceBeforeOpenParenthesis' ); @@ -276,7 +276,7 @@ public function process_token( $stackPtr ) { if ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code'] && ' ' !== $this->tokens[ ( $stackPtr + 1 ) ]['content'] ) { - // Checking this: if [*](...) {}. + // Checking (too much) space between keyword and open parenthesis, i.e. `if [*](...) {}`. $error = 'Expected exactly one space before opening parenthesis; "%s" found.'; $fix = $this->phpcsFile->addFixableError( $error, @@ -292,7 +292,7 @@ public function process_token( $stackPtr ) { if ( \T_CLOSE_PARENTHESIS !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['code'] ) { if ( \T_WHITESPACE !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['code'] ) { - // Checking this: $value = my_function([*]...). + // Checking space directly after the open parenthesis, i.e. `$value = my_function([*]...)`. $error = 'No space after opening parenthesis is prohibited'; $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceAfterOpenParenthesis' ); @@ -304,7 +304,7 @@ public function process_token( $stackPtr ) { && "\r\n" !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['content'] ) && ! isset( $this->ignore_extra_space_after_open_paren[ $this->tokens[ $stackPtr ]['code'] ] ) ) { - // Checking this: if ([*]...) {}. + // Checking (too much) space directly after the open parenthesis, i.e. `if ([*]...) {}`. $error = 'Expected exactly one space after opening parenthesis; "%s" found.'; $fix = $this->phpcsFile->addFixableError( $error, @@ -325,7 +325,7 @@ public function process_token( $stackPtr ) { if ( \T_CLOSE_PARENTHESIS !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['code'] ) { - // Checking this: if (...[*]) {}. + // Checking space directly before the close parenthesis, i.e. `if (...[*]) {}`. if ( \T_WHITESPACE !== $this->tokens[ ( $parenthesisCloser - 1 ) ]['code'] ) { $error = 'No space before closing parenthesis is prohibited'; $fix = $this->phpcsFile->addFixableError( $error, $parenthesisCloser, 'NoSpaceBeforeCloseParenthesis' ); @@ -393,7 +393,7 @@ public function process_token( $stackPtr ) { && ' ' !== $this->tokens[ ( $parenthesisCloser + 1 ) ]['content'] ) { - // Checking this: if (...) [*]{}. + // Checking space between the close parenthesis and the open brace, i.e. `if (...) [*]{}`. $error = 'Expected exactly one space between closing parenthesis and opening control structure; "%s" found.'; $fix = $this->phpcsFile->addFixableError( $error, From b1a02ac423b516ed0e2faf09013ef3ccaf884b3b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 15 Jun 2021 00:45:36 +0200 Subject: [PATCH 099/822] QA: remove unnecessary assignment --- WordPress/Sniff.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 7b41a4e446..0aa237774c 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -1027,9 +1027,7 @@ protected function get_last_ptr_on_line( $stackPtr ) { // We've made it to the next line, back up one to the last in the previous line. // We do this for micro-optimization of the above loop. - $lastPtr = ( $nextPtr - 1 ); - - return $lastPtr; + return ( $nextPtr - 1 ); } /** From ae6bc021d00e7bf51fd985cde3e1318aa7dcf926 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 15 Jun 2021 00:46:23 +0200 Subject: [PATCH 100/822] QA: use fully qualified global constant references --- WordPress/Sniffs/WP/DeprecatedClassesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php | 2 +- WordPress/Sniffs/WP/EnqueuedResourcesSniff.php | 4 ++-- WordPress/Sniffs/WP/I18nSniff.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php index a1b461aba8..25c6e8cbdd 100644 --- a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php @@ -75,7 +75,7 @@ class DeprecatedClassesSniff extends AbstractClassRestrictionsSniff { */ public function getGroups() { // Make sure all array keys are lowercase. - $this->deprecated_classes = array_change_key_case( $this->deprecated_classes, CASE_LOWER ); + $this->deprecated_classes = array_change_key_case( $this->deprecated_classes, \CASE_LOWER ); return array( 'deprecated_classes' => array( diff --git a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php index c33c512b99..2676c82dcb 100644 --- a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php @@ -1377,7 +1377,7 @@ class DeprecatedFunctionsSniff extends AbstractFunctionRestrictionsSniff { */ public function getGroups() { // Make sure all array keys are lowercase. - $this->deprecated_functions = array_change_key_case( $this->deprecated_functions, CASE_LOWER ); + $this->deprecated_functions = array_change_key_case( $this->deprecated_functions, \CASE_LOWER ); return array( 'deprecated_functions' => array( diff --git a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php index e4c34e037a..b462e20c3c 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php @@ -61,7 +61,7 @@ public function process_token( $stackPtr ) { } } - if ( preg_match_all( '# rel=\\\\?[\'"]?stylesheet\\\\?[\'"]?#', $content, $matches, PREG_OFFSET_CAPTURE ) > 0 ) { + if ( preg_match_all( '# rel=\\\\?[\'"]?stylesheet\\\\?[\'"]?#', $content, $matches, \PREG_OFFSET_CAPTURE ) > 0 ) { foreach ( $matches[0] as $match ) { $this->phpcsFile->addError( 'Stylesheets must be registered/enqueued via wp_enqueue_style', @@ -71,7 +71,7 @@ public function process_token( $stackPtr ) { } } - if ( preg_match_all( '#]*(?<=src=)#', $content, $matches, PREG_OFFSET_CAPTURE ) > 0 ) { + if ( preg_match_all( '#]*(?<=src=)#', $content, $matches, \PREG_OFFSET_CAPTURE ) > 0 ) { foreach ( $matches[0] as $match ) { $this->phpcsFile->addError( 'Scripts must be registered/enqueued via wp_enqueue_script', diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 41f02661d8..6c3814bf97 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -648,7 +648,7 @@ protected function check_text( $context ) { * Strip surrounding quotes. */ $reader = new \XMLReader(); - $reader->XML( $content_without_quotes, 'UTF-8', LIBXML_NOERROR | LIBXML_ERR_NONE | LIBXML_NOWARNING ); + $reader->XML( $content_without_quotes, 'UTF-8', \LIBXML_NOERROR | \LIBXML_ERR_NONE | \LIBXML_NOWARNING ); // Is the first node an HTML element? if ( ! $reader->read() || \XMLReader::ELEMENT !== $reader->nodeType ) { From 69caed7f2045e99c3fe36f6d3185073a7030c7c3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 15 Jun 2021 00:46:34 +0200 Subject: [PATCH 101/822] QA: import all used classes --- WordPress/Sniffs/WP/I18nSniff.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 6c3814bf97..d2bfe32bad 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -9,10 +9,11 @@ namespace WordPressCS\WordPress\Sniffs\WP; -use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Utils\TextStrings; +use XMLReader; +use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; /** * Makes sure WP internationalization functions are used properly. @@ -647,11 +648,11 @@ protected function check_text( $context ) { * * Strip surrounding quotes. */ - $reader = new \XMLReader(); + $reader = new XMLReader(); $reader->XML( $content_without_quotes, 'UTF-8', \LIBXML_NOERROR | \LIBXML_ERR_NONE | \LIBXML_NOWARNING ); // Is the first node an HTML element? - if ( ! $reader->read() || \XMLReader::ELEMENT !== $reader->nodeType ) { + if ( ! $reader->read() || XMLReader::ELEMENT !== $reader->nodeType ) { return; } From 75ec4e2dffa93d0099e085f7dc03bf33ca45fe02 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 14 Jun 2021 21:59:52 +0200 Subject: [PATCH 102/822] Bug report template: various improvements After the umpteenth time of getting a non-reproducible bug report (not just in this repo, mind you), I figured it may help to add some more guidance to the bug report template. More important changes: * Ask for the actual CLI command people have used. * Ask for the custom ruleset used (if used). * Give some guidance on how to find out the version numbers of the tooling used. --- .github/ISSUE_TEMPLATE/bug_report.md | 46 ++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5fec9e2c30..6804dffcc7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,6 +4,11 @@ about: Create a report to help us improve --- + + ## Bug Description ## Minimal Code Snippet - + + +The issue happens when running this command: +```bash +phpcs ... +``` + +... over a file containing this code: +```php +// Place your code sample here. +``` + + +The file was auto-fixed via `phpcbf` to: ```php // Place your code sample here. ``` -For bugs with fixers: How was the code fixed? How did you expect the code to be fixed? +... while I expected the code to be fixed to: +```php +// Place your code sample here. +``` ## Error Code +## Custom ruleset + + +```xml + + + ... + +``` + ## Environment + | Question | Answer | ------------------------| ------- -| PHP version | x.y.z +| PHP version | x.y.z | PHP_CodeSniffer version | x.y.z | WPCS version | x.y.z | WPCS install type | e.g. Composer global, Composer project local, git clone, other (please expand) From a844b50f8a833467cf7a7db6b72c0fed0bd8bc57 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 22 Jun 2021 03:23:17 +0200 Subject: [PATCH 103/822] GH Actions: turn display_errors on Turns out the default setting for `error_reporting` used by the SetupPHP action is `error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT` and `display_errors` is set to `Off`. For the purposes of CI, I'd recommend running with `E_ALL` and `display_errors=On` to ensure **all** PHP notices are shown. In this script, error_reporting was already enabled, but the error display was not yet fixed. Sorted now. --- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/unit-tests.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 76e09e8bd3..734a365152 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -44,9 +44,9 @@ jobs: id: set_ini run: | if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then - echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED' + echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' else - echo '::set-output name=PHP_INI::error_reporting=E_ALL' + echo '::set-output name=PHP_INI::error_reporting=E_ALL, display_errors=On' fi - name: Set up PHP diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 40e7511785..9472dd8a5e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -57,9 +57,9 @@ jobs: id: set_ini run: | if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then - echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED' + echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' else - echo '::set-output name=PHP_INI::error_reporting=E_ALL' + echo '::set-output name=PHP_INI::error_reporting=E_ALL, display_errors=On' fi - name: Set up PHP From 2f7d1ebef834f77d57e83491e98a034006ab0884 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 1 Mar 2021 13:13:50 +0100 Subject: [PATCH 104/822] PHP/NoSilencedErrors: add libxml_disable_entity_loader() ... to the default "ignore" list. The `libxml_disable_entity_loader()` function is deprecated in PHP 8.0, but a call to the function is still needed in select circumstances, in which case silencing the deprecation warning is perfectly acceptable. --- .../Sniffs/PHP/NoSilencedErrorsSniff.php | 93 ++++++++++--------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index ee3b3b3a51..6a16803275 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -81,61 +81,64 @@ class NoSilencedErrorsSniff extends Sniff { */ protected $function_whitelist = array( // Directory extension. - 'chdir' => true, - 'opendir' => true, - 'scandir' => true, + 'chdir' => true, + 'opendir' => true, + 'scandir' => true, // File extension. - 'file_exists' => true, - 'file_get_contents' => true, - 'file' => true, - 'fileatime' => true, - 'filectime' => true, - 'filegroup' => true, - 'fileinode' => true, - 'filemtime' => true, - 'fileowner' => true, - 'fileperms' => true, - 'filesize' => true, - 'filetype' => true, - 'fopen' => true, - 'is_dir' => true, - 'is_executable' => true, - 'is_file' => true, - 'is_link' => true, - 'is_readable' => true, - 'is_writable' => true, - 'is_writeable' => true, - 'lstat' => true, - 'mkdir' => true, - 'move_uploaded_file' => true, - 'readfile' => true, - 'readlink' => true, - 'rename' => true, - 'rmdir' => true, - 'stat' => true, - 'unlink' => true, + 'file_exists' => true, + 'file_get_contents' => true, + 'file' => true, + 'fileatime' => true, + 'filectime' => true, + 'filegroup' => true, + 'fileinode' => true, + 'filemtime' => true, + 'fileowner' => true, + 'fileperms' => true, + 'filesize' => true, + 'filetype' => true, + 'fopen' => true, + 'is_dir' => true, + 'is_executable' => true, + 'is_file' => true, + 'is_link' => true, + 'is_readable' => true, + 'is_writable' => true, + 'is_writeable' => true, + 'lstat' => true, + 'mkdir' => true, + 'move_uploaded_file' => true, + 'readfile' => true, + 'readlink' => true, + 'rename' => true, + 'rmdir' => true, + 'stat' => true, + 'unlink' => true, // FTP extension. - 'ftp_chdir' => true, - 'ftp_login' => true, - 'ftp_rename' => true, + 'ftp_chdir' => true, + 'ftp_login' => true, + 'ftp_rename' => true, // Stream extension. - 'stream_select' => true, - 'stream_set_chunk_size' => true, + 'stream_select' => true, + 'stream_set_chunk_size' => true, // Zlib extension. - 'deflate_add' => true, - 'deflate_init' => true, - 'inflate_add' => true, - 'inflate_init' => true, - 'readgzfile' => true, + 'deflate_add' => true, + 'deflate_init' => true, + 'inflate_add' => true, + 'inflate_init' => true, + 'readgzfile' => true, + + // LibXML extension. + 'libxml_disable_entity_loader' => true, // PHP 8.0 deprecation warning, but function call still needed in select cases. // Miscellaneous other functions. - 'imagecreatefromstring' => true, - 'parse_url' => true, // Pre-PHP 5.3.3 an E_WARNING was thrown when URL parsing failed. - 'unserialize' => true, + 'imagecreatefromstring' => true, + 'parse_url' => true, // Pre-PHP 5.3.3 an E_WARNING was thrown when URL parsing failed. + 'unserialize' => true, ); /** From 92c2528e827b18269dd6420b226cf4200b9b2241 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 20 Jul 2021 16:17:48 +0200 Subject: [PATCH 105/822] PHP/NoSilencedErrors: add `imagecreatefromwebp` ... as WP now includes WebP support. --- WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index 6a16803275..95dd4132a8 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -137,6 +137,7 @@ class NoSilencedErrorsSniff extends Sniff { // Miscellaneous other functions. 'imagecreatefromstring' => true, + 'imagecreatefromwebp' => true, 'parse_url' => true, // Pre-PHP 5.3.3 an E_WARNING was thrown when URL parsing failed. 'unserialize' => true, ); From 6a7b8e3857b94cd962541d6176452d91fc095f6e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 23 Dec 2021 05:05:41 +0100 Subject: [PATCH 106/822] Composer: allow the PHPCS plugin The `dealerdirect/phpcodesniffer-composer-installer` Composer plugin is used to register external PHPCS standards with PHPCS. As of Composer 2.2.0, Composer plugins need to be explicitly allowed to run. This adds the necessary configuration for that. Refs: * https://blog.packagist.com/composer-2-2/#more-secure-plugin-execution --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index addfdf45e6..88e057fa11 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,11 @@ "php-parallel-lint/php-parallel-lint": "^1.0", "php-parallel-lint/php-console-highlighter": "^0.5" }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, "minimum-stability": "dev", "prefer-stable": true, "scripts": { From 94a7102d3e09b507ad6c88d770200522439c756c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 23 Dec 2021 05:06:02 +0100 Subject: [PATCH 107/822] GH Actions: auto-cancel previous builds for same branch Previously, in Travis, when the same branch was pushed again and the "Auto cancellation" option on the "Settings" page had been turned on (as it was for most repos), any still running builds for the same branch would be stopped in favour of starting the build for the newly pushed version of the branch. To enable this behaviour in GH Actions, a `concurrency` configuration needs to be added to each workflow for which this should applied to. More than anything, this is a way to be kind to GitHub by not wasting resources which they so kindly provide to us for free. Refs: * https://github.blog/changelog/2021-04-19-github-actions-limit-workflow-run-or-job-concurrency/ * https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#concurrency --- .github/workflows/quicktest.yml | 6 ++++++ .github/workflows/ruleset-checks-sniffs.yml | 6 ++++++ .github/workflows/unit-tests.yml | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 734a365152..72b7f8a564 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -9,6 +9,12 @@ on: # Allow manually triggering the workflow. workflow_dispatch: +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # Performs some quick tests. # This is a much quicker test suite which only runs the unit tests and linting diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index dd8a108f79..67a5e5aa2c 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -6,6 +6,12 @@ on: # Allow manually triggering the workflow. workflow_dispatch: +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # Performs some code-style related checks. # diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 9472dd8a5e..4bd6df487f 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -8,6 +8,12 @@ on: # Allow manually triggering the workflow. workflow_dispatch: +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # Runs the test suite against all supported branches and combinations. # From 814d1015b651e5dae3f02ac5f606187fd0235962 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 23 Dec 2021 05:07:10 +0100 Subject: [PATCH 108/822] GH Actions: use `error_reporting=-1` ... as `E_ALL` does not always contain _all_ errors across PHP versions. --- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 72b7f8a564..2d83f8d29e 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -52,7 +52,7 @@ jobs: if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' else - echo '::set-output name=PHP_INI::error_reporting=E_ALL, display_errors=On' + echo '::set-output name=PHP_INI::error_reporting=-1, display_errors=On' fi - name: Set up PHP diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 4bd6df487f..a588b95dfd 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -65,7 +65,7 @@ jobs: if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' else - echo '::set-output name=PHP_INI::error_reporting=E_ALL, display_errors=On' + echo '::set-output name=PHP_INI::error_reporting=-1, display_errors=On' fi - name: Set up PHP From 3d682988342354bb96626c01b995e1ea7f8651b5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 23 Dec 2021 05:09:03 +0100 Subject: [PATCH 109/822] GH Actions: update for the release of PHP 8.1 This commit makes the necessary adjustments to the test matrix to account for that. Note: the protected branch settings should be adjusted after this change to include the two new PHP 8.1 builds. --- .github/workflows/unit-tests.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index a588b95dfd..ba8d8c7b07 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -38,6 +38,13 @@ jobs: phpcs_version: [ 'dev-master', '3.5.0' ] allowed_failure: [ false ] include: + - php: '8.1' + phpcs_version: 'dev-master' + allowed_failure: false + # PHPCS is only compatible with PHP 8.1 as of version 3.6.1. + - php: '8.1' + phpcs_version: '3.6.1' + allowed_failure: false - php: '8.0' phpcs_version: 'dev-master' allowed_failure: false @@ -49,7 +56,7 @@ jobs: #- php: '7.4' # phpcs_version: '4.0.x-dev as 3.9.99' # allowed_failure: true - - php: '8.1' + - php: '8.2' phpcs_version: 'dev-master' allowed_failure: true @@ -101,9 +108,9 @@ jobs: run: composer lint-ci | cs2pr - name: Run the unit tests - PHP 5.4 - 8.0 - if: ${{ matrix.php != '8.1' }} + if: ${{ matrix.php < '8.1' }} run: composer run-tests - name: Run the unit tests - PHP 8.1 - if: ${{ matrix.php == '8.1' }} + if: ${{ matrix.php >= '8.1' }} run: composer run-tests -- --no-configuration --bootstrap=./Tests/bootstrap.php --dont-report-useless-tests From 17380017de5a51dc1301411634fff1d41fd32821 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 24 Dec 2021 05:45:02 +0100 Subject: [PATCH 110/822] GH Actions: version update for `ramsey/composer-install` The action used to install Composer packages and handle the caching has released a new major (and some follow-up patch releases), which means, the action reference needs to be updated to benefit from it. Includes adding `--no-interaction` to "plain" Composer commands to potentially prevent CI hanging if, for whatever reason, interaction would be needed in the future. Refs: * https://github.com/ramsey/composer-install/releases/tag/2.0.0 * https://github.com/ramsey/composer-install/releases/tag/2.0.1 * https://github.com/ramsey/composer-install/releases/tag/2.0.2 --- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/ruleset-checks-sniffs.yml | 8 ++++---- .github/workflows/unit-tests.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 2d83f8d29e..19b201b737 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -63,10 +63,10 @@ jobs: coverage: none - name: Set PHPCS version - run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts + run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction - name: Install Composer dependencies - uses: ramsey/composer-install@v1 + uses: ramsey/composer-install@v2 - name: Lint PHP files against parse errors if: ${{ matrix.phpcs_version == 'dev-master' }} diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index 67a5e5aa2c..b618c6ff8d 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -48,10 +48,10 @@ jobs: # Using PHPCS `master` as an early detection system for bugs upstream. - name: Set PHPCS version - run: composer require squizlabs/php_codesniffer:"dev-master" --no-update --no-scripts + run: composer require squizlabs/php_codesniffer:"dev-master" --no-update --no-scripts --no-interaction - name: Install Composer dependencies - uses: ramsey/composer-install@v1 + uses: ramsey/composer-install@v2 - name: Install xmllint run: sudo apt-get install libxml2-utils @@ -128,10 +128,10 @@ jobs: coverage: none - name: Set PHPCS version - run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts + run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction - name: Install Composer dependencies - uses: ramsey/composer-install@v1 + uses: ramsey/composer-install@v2 - name: Test the WordPress-Core ruleset run: $(pwd)/vendor/bin/phpcs -ps ./Tests/RulesetCheck/class-ruleset-test.inc --standard=WordPress-Core diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index ba8d8c7b07..494fc0d9c7 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -91,15 +91,15 @@ jobs: run: composer config preferred-install.squizlabs/php_codesniffer source - name: Set PHPCS version - run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts + run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction - name: Install Composer dependencies (PHP < 8.0 ) if: ${{ matrix.php < 8.0 }} - uses: ramsey/composer-install@v1 + uses: ramsey/composer-install@v2 - name: Install Composer dependencies (PHP >= 8.0) if: ${{ matrix.php >= 8.0 }} - uses: ramsey/composer-install@v1 + uses: ramsey/composer-install@v2 with: composer-options: --ignore-platform-reqs From 0052562dee5e0c2229913e371d05cd925bba523d Mon Sep 17 00:00:00 2001 From: Slava Abakumov Date: Thu, 30 Dec 2021 16:39:36 +0200 Subject: [PATCH 111/822] Update the min support PHP version --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bcacabee25..d61fb239be 100644 --- a/README.md +++ b/README.md @@ -155,13 +155,13 @@ The [PHPCompatibilityWP](https://github.com/PHPCompatibility/PHPCompatibilityWP) Install either as a separate ruleset and run it separately against your code or add it to your custom ruleset, like so: ```xml - + *\.php$ ``` -Whichever way you run it, do make sure you set the `testVersion` to run the sniffs against. The `testVersion` determines for which PHP versions you will receive compatibility information. The recommended setting for this at this moment is `5.2-` to support the same PHP versions as WordPress Core supports. +Whichever way you run it, do make sure you set the `testVersion` to run the sniffs against. The `testVersion` determines for which PHP versions you will receive compatibility information. The recommended setting for this at this moment is `5.6-` to support the same PHP versions as WordPress Core supports. For more information about setting the `testVersion`, see: * [PHPCompatibility: Sniffing your code for compatibility with specific PHP version(s)](https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions) From dd26f30297ebfe6ecd4d699bf733b65a078c3faa Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 4 Feb 2022 12:12:27 +0100 Subject: [PATCH 112/822] WP/CronInterval: bug fix for parentheses This allows for a time calculation to be wrapped in parentheses. Fixes 2025 --- Note: just looking at the code, I can see multiple additional improvements which could/should be made: * Only search for close parenthesis as a "valueEnd" if the `$valueStart` token is an open parenthesis. * Allow for more assignment operators - the new schedule could be build up bit by bit and only assigned to the array later. These additional things are not addressed here. This just addresses the immediate issue. --- WordPress/Sniffs/WP/CronIntervalSniff.php | 11 ++++++++--- WordPress/Tests/WP/CronIntervalUnitTest.inc | 16 ++++++++++++++++ WordPress/Tests/WP/CronIntervalUnitTest.php | 2 +- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/WP/CronIntervalSniff.php b/WordPress/Sniffs/WP/CronIntervalSniff.php index 5a3595a925..65badaa90a 100644 --- a/WordPress/Sniffs/WP/CronIntervalSniff.php +++ b/WordPress/Sniffs/WP/CronIntervalSniff.php @@ -177,10 +177,15 @@ public function process_token( $stackPtr ) { $valueStart = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $operator + 1 ), null, true, null, true ); $valueEnd = $this->phpcsFile->findNext( array( \T_COMMA, \T_CLOSE_PARENTHESIS ), ( $valueStart + 1 ) ); $value = ''; - for ( $j = $valueStart; $j < $valueEnd; $j++ ) { + for ( $j = $valueStart; $j <= $valueEnd; $j++ ) { if ( isset( Tokens::$emptyTokens[ $this->tokens[ $j ]['code'] ] ) ) { continue; } + + if ( $j === $valueEnd && \T_COMMA === $this->tokens[ $j ]['code'] ) { + break; + } + $value .= $this->tokens[ $j ]['content']; } @@ -192,8 +197,8 @@ public function process_token( $stackPtr ) { // Deal correctly with WP time constants. $value = str_replace( array_keys( $this->wp_time_constants ), array_values( $this->wp_time_constants ), $value ); - // If all digits and operators, eval! - if ( preg_match( '#^[\s\d+*/-]+$#', $value ) > 0 ) { + // If all parentheses, digits and operators, eval! + if ( preg_match( '#^[\s\d()+*/-]+$#', $value ) > 0 ) { $interval = eval( "return ( $value );" ); // phpcs:ignore Squiz.PHP.Eval -- No harm here. break; } diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.inc b/WordPress/Tests/WP/CronIntervalUnitTest.inc index 19b061fe34..330084676c 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.inc +++ b/WordPress/Tests/WP/CronIntervalUnitTest.inc @@ -144,3 +144,19 @@ Custom::add_filter( 'cron_schedules', array( $class, $method ) ); // OK, not the add_filter( 'some_hook', array( $place, 'cron_schedules' ) ); // OK, not the hook we're looking for. add_filter( function() { return get_hook_name('cron_schedules'); }(), array( $class, $method ) ); // OK, nested in another function call. +// Deal correctly with the time calculations within parentheses. +add_filter( 'cron_schedules', function ( $schedules ) { + $schedules['every_2_days_and_a_bit'] = [ + 'interval' => ( 2 * DAY_IN_SECONDS + 2 * HOUR_IN_SECONDS ), + 'display' => __( 'Once every 2 days and a bit' ) + ]; + return $schedules; +} ); // Ok: > 15 min. + +add_filter( 'cron_schedules', function ( $schedules ) { + $schedules['every_8_minutes'] = [ + 'interval' => (8 * MINUTE_IN_SECONDS), + 'display' => __( 'Once every 8 minutes' ) + ]; + return $schedules; +} ); // Error: 8 min. diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.php b/WordPress/Tests/WP/CronIntervalUnitTest.php index afbf6a6b69..522e45211f 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.php +++ b/WordPress/Tests/WP/CronIntervalUnitTest.php @@ -51,7 +51,7 @@ public function getWarningList() { 108 => 1, 115 => 1, 133 => 1, + 156 => 1, ); } - } From 186f90eca43ceddbb61172f820c84439854afca1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 5 Mar 2022 18:51:19 +0100 Subject: [PATCH 113/822] GH Actions: version update for various predefined actions A number of predefined actions have had major release, which warrant an update the workflow(s). These updates don't actually contain any changed functionality, they are mostly just a change of the Node version used by the action itself (from Node 14 to Node 16). Refs: * https://github.com/actions/checkout/releases --- .github/workflows/quicktest.yml | 2 +- .github/workflows/ruleset-checks-sniffs.yml | 4 ++-- .github/workflows/unit-tests.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 19b201b737..d060662cdc 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -42,7 +42,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # On stable PHPCS versions, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index b618c6ff8d..71495e9731 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -37,7 +37,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -117,7 +117,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 494fc0d9c7..ce7d35c60e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -62,7 +62,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # On stable PHPCS versions, allow for PHP deprecation notices. # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. From abc2d8540dfeb1399c83fa3ed9ab751aff5a9a1d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 19 Mar 2022 09:46:38 +0100 Subject: [PATCH 114/822] GH Actions/CS: fix build failure Fix failing installation of the xmllint tooling. --- .github/workflows/ruleset-checks-sniffs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index 71495e9731..9d6aef3e99 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -54,7 +54,9 @@ jobs: uses: ramsey/composer-install@v2 - name: Install xmllint - run: sudo apt-get install libxml2-utils + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y libxml2-utils # Show XML violations inline in the file diff. # @link https://github.com/marketplace/actions/xmllint-problem-matcher From 664adf643a5da563087e5f7ba4ebc49d1e141c26 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 11 Apr 2020 09:57:09 +0200 Subject: [PATCH 115/822] Core: add the `Generic.VersionControl.GitMergeConflict` sniff Fixes 1500 --- WordPress-Core/ruleset.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 89752c350f..e9f604805e 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -523,6 +523,9 @@ Best practices: Declare only one class/interface/trait in a file. + + + + ## Rationale diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index d060662cdc..1267203d40 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -36,9 +36,9 @@ jobs: phpcs_version: [ 'dev-master' ] include: - php: '7.3' - phpcs_version: '3.5.0' + phpcs_version: '3.6.2' - php: '5.4' - phpcs_version: '3.5.0' + phpcs_version: '3.6.2' steps: - name: Checkout repository diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index 9d6aef3e99..616ab0e200 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -115,7 +115,7 @@ jobs: strategy: matrix: php: [ '7.4' ] - phpcs_version: [ 'dev-master', '3.5.0' ] + phpcs_version: [ 'dev-master', '3.6.2' ] steps: - name: Checkout repository diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index ce7d35c60e..f2052d3028 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -34,24 +34,10 @@ jobs: continue-on-error: ${{ matrix.allowed_failure }} strategy: matrix: - php: [ '7.4', '7.3', '7.2', '7.1', '7.0', '5.6', '5.5', '5.4' ] - phpcs_version: [ 'dev-master', '3.5.0' ] + php: [ '8.1', '8.0', '7.4', '7.3', '7.2', '7.1', '7.0', '5.6', '5.5', '5.4' ] + phpcs_version: [ 'dev-master', '3.6.2' ] allowed_failure: [ false ] include: - - php: '8.1' - phpcs_version: 'dev-master' - allowed_failure: false - # PHPCS is only compatible with PHP 8.1 as of version 3.6.1. - - php: '8.1' - phpcs_version: '3.6.1' - allowed_failure: false - - php: '8.0' - phpcs_version: 'dev-master' - allowed_failure: false - # PHPCS is only compatible with PHP 8.0 as of version 3.5.7. - - php: '8.0' - phpcs_version: '3.5.7' - allowed_failure: false # Add extra build to test against PHPCS 4. #- php: '7.4' # phpcs_version: '4.0.x-dev as 3.9.99' diff --git a/README.md b/README.md index d61fb239be..0523a09cc7 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ This project is a collection of [PHP_CodeSniffer](https://github.com/squizlabs/P ### Requirements -The WordPress Coding Standards require PHP 5.4 or higher and [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version **3.3.1** or higher. +The WordPress Coding Standards require PHP 5.4 or higher and [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version **3.6.2** or higher. ### Composer diff --git a/composer.json b/composer.json index c9354dd1f8..2ca4eaea60 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ ], "require": { "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.5.0", + "squizlabs/php_codesniffer": "^3.6.2", "phpcsstandards/phpcsutils": "^1.0", "phpcsstandards/phpcsextra": "^1.0" }, From 76f3376730fb0fd220f313dabb630fcf186d0b5d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 14 May 2022 18:43:28 +0200 Subject: [PATCH 119/822] Move "interpolated variable" related utilities to dedicated `TextStringHelper` The "interpolated variable" related utilities are only used by a small set of sniffs, so are better placed in a dedicated class. This commit moves the `REGEX_COMPLEX_VARS` constant, the `get_interpolated_variables()` method and the `strip_interpolated_variables()` method to a new `WordPressCS\WordPress\Helpers\TextStringHelper` and starts using that class in the relevant sniffs. In contrast to some of the other "move methods out of the Sniff class" PRs, these methods have been moved to a class and made `static` - instead of moved to a `trait`. The reason for this difference is that the methods in other "moves" are setting properties which the sniff classes would need access to, while these methods are 100% stand-alone. **Note**: It is expected for PHPCSUtils to have dedicated methods for the same at some point in the future. If/when those methods become available, it is recommended for the sniffs to start using the PHPCSUtils methods and for this class to be deprecated and removed in the next major release. Also note that PHP 8.2 will be making changes to the kind of interpolation supported by PHP. This will need further investigation at a future point in time (probably in PHPCSUtils rather than here), if nothing else to ensure that what was supported in PHP prior to PHP 8.2 is fully supported by these methods (which is probably not the case at this moment). Ref: https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation Related to 1465 --- WordPress/Helpers/TextStringHelper.php | 79 +++++++++++++++++++ WordPress/Sniff.php | 51 ------------ .../DB/PreparedSQLPlaceholdersSniff.php | 7 +- WordPress/Sniffs/DB/PreparedSQLSniff.php | 5 +- .../ValidPostTypeSlugSniff.php | 5 +- .../Security/ValidatedSanitizedInputSniff.php | 5 +- WordPress/Sniffs/WP/I18nSniff.php | 3 +- 7 files changed, 94 insertions(+), 61 deletions(-) create mode 100644 WordPress/Helpers/TextStringHelper.php diff --git a/WordPress/Helpers/TextStringHelper.php b/WordPress/Helpers/TextStringHelper.php new file mode 100644 index 0000000000..13b63aa022 --- /dev/null +++ b/WordPress/Helpers/TextStringHelper.php @@ -0,0 +1,79 @@ +[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(?:->\$?(?P>varname)|\[[^\]]+\]|::\$?(?P>varname)|\([^\)]*\))*(?(3)\}|)(?(2)\}|)(?(1)\}|)`'; + + /** + * Get the interpolated variable names from a string. + * + * Check if '$' is followed by a valid variable name, and that it is not preceded by an escape sequence. + * + * @since 0.9.0 + * @since 3.0.0 - Moved from the Sniff class to this class. + * - Visibility is now `public` (was `protected`) and the method `static`. + * + * @param string $string The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. + * + * @return array Variable names (without '$' sigil). + */ + public static function get_interpolated_variables( $string ) { + $variables = array(); + if ( preg_match_all( '/(?P\\\\*)\$(?P\w+)/', $string, $match_sets, \PREG_SET_ORDER ) ) { + foreach ( $match_sets as $matches ) { + if ( ! isset( $matches['backslashes'] ) || ( \strlen( $matches['backslashes'] ) % 2 ) === 0 ) { + $variables[] = $matches['symbol']; + } + } + } + return $variables; + } + + /** + * Strip variables from an arbitrary double quoted/heredoc string. + * + * Intended for use with the contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. + * + * @since 0.14.0 + * @since 3.0.0 - Moved from the Sniff class to this class. + * - The method was made `static`. + * + * @param string $string The raw string. + * + * @return string String without variables in it. + */ + public static function strip_interpolated_variables( $string ) { + if ( strpos( $string, '$' ) === false ) { + return $string; + } + + return preg_replace( self::REGEX_COMPLEX_VARS, '', $string ); + } +} diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 0aa237774c..f61931d558 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -38,15 +38,6 @@ */ abstract class Sniff implements PHPCS_Sniff { - /** - * Regex to get complex variables from T_DOUBLE_QUOTED_STRING or T_HEREDOC. - * - * @since 0.14.0 - * - * @var string - */ - const REGEX_COMPLEX_VARS = '`(?:(\{)?(?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(?:->\$?(?P>varname)|\[[^\]]+\]|::\$?(?P>varname)|\([^\)]*\))*(?(3)\}|)(?(2)\}|)(?(1)\}|)`'; - /** * List of the functions which verify nonces. * @@ -2063,48 +2054,6 @@ protected function is_in_array_comparison( $stackPtr ) { return false; } - /** - * Get the interpolated variable names from a string. - * - * Check if '$' is followed by a valid variable name, and that it is not preceded by an escape sequence. - * - * @since 0.9.0 - * - * @param string $string The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. - * - * @return array Variable names (without '$' sigil). - */ - protected function get_interpolated_variables( $string ) { - $variables = array(); - if ( preg_match_all( '/(?P\\\\*)\$(?P\w+)/', $string, $match_sets, \PREG_SET_ORDER ) ) { - foreach ( $match_sets as $matches ) { - if ( ! isset( $matches['backslashes'] ) || ( \strlen( $matches['backslashes'] ) % 2 ) === 0 ) { - $variables[] = $matches['symbol']; - } - } - } - return $variables; - } - - /** - * Strip variables from an arbitrary double quoted/heredoc string. - * - * Intended for use with the contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. - * - * @since 0.14.0 - * - * @param string $string The raw string. - * - * @return string String without variables in it. - */ - public function strip_interpolated_variables( $string ) { - if ( strpos( $string, '$' ) === false ) { - return $string; - } - - return preg_replace( self::REGEX_COMPLEX_VARS, '', $string ); - } - /** * Checks whether this is a call to a $wpdb method that we want to sniff. * diff --git a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php index e6c1f664a7..836b6e51dd 100644 --- a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php @@ -9,10 +9,11 @@ namespace WordPressCS\WordPress\Sniffs\DB; -use WordPressCS\WordPress\Sniff; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\PassedParameters; use PHPCSUtils\Utils\TextStrings; +use WordPressCS\WordPress\Helpers\TextStringHelper; +use WordPressCS\WordPress\Sniff; /** * Check for incorrect use of the $wpdb->prepare method. @@ -278,9 +279,9 @@ public function process_token( $stackPtr ) { || \T_HEREDOC === $this->tokens[ $i ]['code'] ) { // Only interested in actual query text, so strip out variables. - $stripped_content = $this->strip_interpolated_variables( $content ); + $stripped_content = TextStringHelper::strip_interpolated_variables( $content ); if ( $stripped_content !== $content ) { - $interpolated_vars = $this->get_interpolated_variables( $content ); + $interpolated_vars = TextStringHelper::get_interpolated_variables( $content ); $vars_without_wpdb = array_diff( $interpolated_vars, array( 'wpdb' ) ); $content = $stripped_content; diff --git a/WordPress/Sniffs/DB/PreparedSQLSniff.php b/WordPress/Sniffs/DB/PreparedSQLSniff.php index 57781d61af..c15826c14c 100644 --- a/WordPress/Sniffs/DB/PreparedSQLSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLSniff.php @@ -9,8 +9,9 @@ namespace WordPressCS\WordPress\Sniffs\DB; -use WordPressCS\WordPress\Sniff; use PHP_CodeSniffer\Util\Tokens; +use WordPressCS\WordPress\Helpers\TextStringHelper; +use WordPressCS\WordPress\Sniff; /** * Sniff for prepared SQL. @@ -138,7 +139,7 @@ public function process_token( $stackPtr ) { ) { $bad_variables = array_filter( - $this->get_interpolated_variables( $this->tokens[ $this->i ]['content'] ), + TextStringHelper::get_interpolated_variables( $this->tokens[ $this->i ]['content'] ), function ( $symbol ) { return ( 'wpdb' !== $symbol ); } diff --git a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php index 9edcff7792..673557efae 100644 --- a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php @@ -9,9 +9,10 @@ namespace WordPressCS\WordPress\Sniffs\NamingConventions; -use WordPressCS\WordPress\AbstractFunctionParameterSniff; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\TextStrings; +use WordPressCS\WordPress\AbstractFunctionParameterSniff; +use WordPressCS\WordPress\Helpers\TextStringHelper; /** * Validates post type names. @@ -161,7 +162,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p 'PartiallyDynamic', $data ); - $post_type = $this->strip_interpolated_variables( $post_type ); + $post_type = TextStringHelper::strip_interpolated_variables( $post_type ); } if ( preg_match( self::POST_TYPE_CHARACTER_WHITELIST, $post_type ) === 0 ) { diff --git a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php index 54b43184e7..00289b07bd 100644 --- a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php +++ b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php @@ -9,8 +9,9 @@ namespace WordPressCS\WordPress\Sniffs\Security; -use WordPressCS\WordPress\Sniff; use PHP_CodeSniffer\Util\Tokens; +use WordPressCS\WordPress\Helpers\TextStringHelper; +use WordPressCS\WordPress\Sniff; /** * Flag any non-validated/sanitized input ( _GET / _POST / etc. ). @@ -100,7 +101,7 @@ public function process_token( $stackPtr ) { function ( $symbol ) { return '$' . $symbol; }, - $this->get_interpolated_variables( $this->tokens[ $stackPtr ]['content'] ) + TextStringHelper::get_interpolated_variables( $this->tokens[ $stackPtr ]['content'] ) ); foreach ( array_intersect( $interpolated_variables, $superglobals ) as $bad_variable ) { $this->phpcsFile->addError( 'Detected usage of a non-sanitized, non-validated input variable %s: %s', $stackPtr, 'InputNotValidatedNotSanitized', array( $bad_variable, $this->tokens[ $stackPtr ]['content'] ) ); diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index d2bfe32bad..8dd700ae0d 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -14,6 +14,7 @@ use PHPCSUtils\Utils\TextStrings; use XMLReader; use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; +use WordPressCS\WordPress\Helpers\TextStringHelper; /** * Makes sure WP internationalization functions are used properly. @@ -470,7 +471,7 @@ protected function check_argument_tokens( $context ) { } if ( \T_DOUBLE_QUOTED_STRING === $tokens[0]['code'] || \T_HEREDOC === $tokens[0]['code'] ) { - $interpolated_variables = $this->get_interpolated_variables( $content ); + $interpolated_variables = TextStringHelper::get_interpolated_variables( $content ); foreach ( $interpolated_variables as $interpolated_variable ) { $code = $this->string_to_errorcode( 'InterpolatedVariable' . ucfirst( $arg_name ) ); $this->addMessage( 'The $%s arg must not contain interpolated variables. Found "$%s".', $stack_ptr, $is_error, $code, array( $arg_name, $interpolated_variable ) ); From 20d906d01bc974a3eb08da0937eba79843af690c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 20 Jul 2021 16:20:47 +0200 Subject: [PATCH 120/822] IsUnitTestTrait: update test class list Update the test class list based on changes in WP Core: * The `Block_Supported_Styles_Test` was never a `TestCase`, but was a concrete test placed in the wrong directory. * The `PHPUnit_Adapter_TestCase` class was added to allow for PHPUnit cross-version support. Other than that, the list is now alphabetized within each category and the categories are annotated with comments. --- WordPress/Helpers/IsUnitTestTrait.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/WordPress/Helpers/IsUnitTestTrait.php b/WordPress/Helpers/IsUnitTestTrait.php index 801c1e5a5b..b3712da57c 100644 --- a/WordPress/Helpers/IsUnitTestTrait.php +++ b/WordPress/Helpers/IsUnitTestTrait.php @@ -79,16 +79,21 @@ trait IsUnitTestTrait { * @var string[] */ protected $known_test_classes = array( - 'WP_UnitTestCase_Base' => true, + // Base test cases. 'WP_UnitTestCase' => true, + 'WP_UnitTestCase_Base' => true, + 'PHPUnit_Adapter_TestCase' => true, + + // Domain specific base test cases. 'WP_Ajax_UnitTestCase' => true, - 'Block_Supported_Styles_Test' => true, 'WP_Canonical_UnitTestCase' => true, - 'WP_Test_REST_TestCase' => true, 'WP_Test_REST_Controller_Testcase' => true, 'WP_Test_REST_Post_Type_Controller_Testcase' => true, + 'WP_Test_REST_TestCase' => true, 'WP_Test_XML_TestCase' => true, 'WP_XMLRPC_UnitTestCase' => true, + + // PHPUnit native test cases. 'PHPUnit_Framework_TestCase' => true, 'PHPUnit\Framework\TestCase' => true, // PHPUnit native TestCase class when imported via use statement. From 43a2cbd5968ea7e69b5aa99ba6d5d377750bb0d7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 14 May 2022 19:45:45 +0200 Subject: [PATCH 121/822] Move "deprecation" related utilities to dedicated `DeprecationHelper` The "deprecation" related utilities are only used by a small set of sniffs, so are better placed in a dedicated class. This commit moves the `is_function_deprecated()` method to a new `WordPressCS\WordPress\Helpers\DeprecationHelper` and starts using that class in the relevant sniffs. **Note**: It is expected for PHPCSUtils to have dedicated methods for the same at some point in the future. If/when those methods become available, it is recommended for the sniffs to start using the PHPCSUtils methods and for this class to be deprecated and removed in the next major release. Related to 1465 --- WordPress/Helpers/DeprecationHelper.php | 60 +++++++++++++++++++ WordPress/Sniff.php | 35 ----------- .../PrefixAllGlobalsSniff.php | 3 +- .../ValidFunctionNameSniff.php | 5 +- 4 files changed, 65 insertions(+), 38 deletions(-) create mode 100644 WordPress/Helpers/DeprecationHelper.php diff --git a/WordPress/Helpers/DeprecationHelper.php b/WordPress/Helpers/DeprecationHelper.php new file mode 100644 index 0000000000..3363a75efe --- /dev/null +++ b/WordPress/Helpers/DeprecationHelper.php @@ -0,0 +1,60 @@ +getTokens(); + $find = Tokens::$methodPrefixes; + $find[] = \T_WHITESPACE; + + $comment_end = $phpcsFile->findPrevious( $find, ( $stackPtr - 1 ), null, true ); + if ( \T_DOC_COMMENT_CLOSE_TAG !== $tokens[ $comment_end ]['code'] ) { + // Function doesn't have a doc comment or is using the wrong type of comment. + return false; + } + + $comment_start = $tokens[ $comment_end ]['comment_opener']; + foreach ( $tokens[ $comment_start ]['comment_tags'] as $tag ) { + if ( '@deprecated' === $tokens[ $tag ]['content'] ) { + return true; + } + } + + return false; + } +} diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 0aa237774c..4937753711 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -2396,39 +2396,4 @@ protected function get_list_variables( $stackPtr, $list_open_close = array() ) { return $var_pointers; } - - /** - * Check whether a function has been marked as deprecated via a @deprecated tag - * in the function docblock. - * - * {@internal This method is static to allow the ValidFunctionName class to use it.}} - * - * @since 2.2.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of a T_FUNCTION - * token in the stack. - * - * @return bool - */ - public static function is_function_deprecated( File $phpcsFile, $stackPtr ) { - $tokens = $phpcsFile->getTokens(); - $find = Tokens::$methodPrefixes; - $find[] = \T_WHITESPACE; - - $comment_end = $phpcsFile->findPrevious( $find, ( $stackPtr - 1 ), null, true ); - if ( \T_DOC_COMMENT_CLOSE_TAG !== $tokens[ $comment_end ]['code'] ) { - // Function doesn't have a doc comment or is using the wrong type of comment. - return false; - } - - $comment_start = $tokens[ $comment_end ]['comment_opener']; - foreach ( $tokens[ $comment_start ]['comment_tags'] as $tag ) { - if ( '@deprecated' === $tokens[ $tag ]['content'] ) { - return true; - } - } - - return false; - } } diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index 1d0eceb444..d2817ede48 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -16,6 +16,7 @@ use PHPCSUtils\Utils\Scopes; use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\AbstractFunctionParameterSniff; +use WordPressCS\WordPress\Helpers\DeprecationHelper; use WordPressCS\WordPress\Helpers\IsUnitTestTrait; /** @@ -386,7 +387,7 @@ public function process_token( $stackPtr ) { return; } - if ( $this->is_function_deprecated( $this->phpcsFile, $stackPtr ) === true ) { + if ( DeprecationHelper::is_function_deprecated( $this->phpcsFile, $stackPtr ) === true ) { /* * Deprecated functions don't have to comply with the naming conventions, * otherwise functions deprecated in favour of a function with a compliant diff --git a/WordPress/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/WordPress/Sniffs/NamingConventions/ValidFunctionNameSniff.php index 84a3267718..034613b72a 100644 --- a/WordPress/Sniffs/NamingConventions/ValidFunctionNameSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidFunctionNameSniff.php @@ -9,11 +9,12 @@ namespace WordPressCS\WordPress\Sniffs\NamingConventions; -use WordPressCS\WordPress\Sniff; use PHPCSUtils\BackCompat\BCTokens; use PHPCSUtils\Utils\FunctionDeclarations; use PHPCSUtils\Utils\ObjectDeclarations; use PHPCSUtils\Utils\Scopes; +use WordPressCS\WordPress\Helpers\DeprecationHelper; +use WordPressCS\WordPress\Sniff; /** * Enforces WordPress function name and method name format, based upon Squiz code. @@ -55,7 +56,7 @@ public function register() { */ public function process_token( $stackPtr ) { - if ( Sniff::is_function_deprecated( $this->phpcsFile, $stackPtr ) === true ) { + if ( DeprecationHelper::is_function_deprecated( $this->phpcsFile, $stackPtr ) === true ) { /* * Deprecated functions don't have to comply with the naming conventions, * otherwise functions deprecated in favour of a function with a compliant From ac80e89232de2520a69a953ef406df0803a0db9e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 14 May 2022 20:01:36 +0200 Subject: [PATCH 122/822] PHP 8.0 | DeprecationHelper: allow for attributes between function declaration and docblock PHP 8.0 introduced attributes, which can be placed - and commonly are placed - between a function declaration and its docblock. Ref: https://www.php.net/manual/en/language.attributes.php This commit updates the `is_function_deprecated()` method to skip over attributes. This prevents false positives when a function is deprecated, but also has an attribute. Tested via both sniffs using the helper class. Includes renaming a local variable to be more descriptive (`$ignore` instead of `$find`). --- WordPress/Helpers/DeprecationHelper.php | 22 +++++++++++++++---- .../PrefixAllGlobalsUnitTest.1.inc | 14 ++++++++++++ .../ValidFunctionNameUnitTest.inc | 14 ++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/WordPress/Helpers/DeprecationHelper.php b/WordPress/Helpers/DeprecationHelper.php index 3363a75efe..dc6a992755 100644 --- a/WordPress/Helpers/DeprecationHelper.php +++ b/WordPress/Helpers/DeprecationHelper.php @@ -38,11 +38,25 @@ final class DeprecationHelper { * @return bool */ public static function is_function_deprecated( File $phpcsFile, $stackPtr ) { - $tokens = $phpcsFile->getTokens(); - $find = Tokens::$methodPrefixes; - $find[] = \T_WHITESPACE; + $tokens = $phpcsFile->getTokens(); + $ignore = Tokens::$methodPrefixes; + $ignore[ \T_WHITESPACE ] = \T_WHITESPACE; + + for ( $comment_end = ( $stackPtr - 1 ); $comment_end >= 0; $comment_end-- ) { + if ( isset( $ignore[ $tokens[ $comment_end ]['code'] ] ) === true ) { + continue; + } + + if ( \T_ATTRIBUTE_END === $tokens[ $comment_end ]['code'] + && isset( $tokens[ $comment_end ]['attribute_opener'] ) === true + ) { + $comment_end = $tokens[ $comment_end ]['attribute_opener']; + continue; + } + + break; + } - $comment_end = $phpcsFile->findPrevious( $find, ( $stackPtr - 1 ), null, true ); if ( \T_DOC_COMMENT_CLOSE_TAG !== $tokens[ $comment_end ]['code'] ) { // Function doesn't have a doc comment or is using the wrong type of comment. return false; diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index d2bbe40147..2c1242788e 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -482,6 +482,20 @@ function acronym_lists_in_function_scope() { */ function deprecated_function() {} +/** + * Function description. + * + * @since 1.2.3 + * @deprecated 2.3.4 + * + * @return void + */ +#[MyAttribute([ + 'something', + 'something else', +])] +function deprecated_function_with_attribute() {} + /* * Bad: Issue https://github.com/WordPress/WordPress-Coding-Standards/issues/1733. * diff --git a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.inc b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.inc index e40fdde8d6..e7f2da4e56 100644 --- a/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.inc +++ b/WordPress/Tests/NamingConventions/ValidFunctionNameUnitTest.inc @@ -163,3 +163,17 @@ function ___triple_underscore() {} // OK. class Triple { function ___triple_underscore() {} // OK. } + +class DeprecatedWithAttribute { + /** + * Function description. + * + * @since 1.2.3 + * @deprecated 2.3.4 + * + * @return void + */ + #[SomeAttribute] + #[AnotherAttribute] + public static function __deprecatedMethod() {} +} From 5b3cde7f0c78bff55de2ff8183e62c2f0018dead Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Mon, 16 May 2022 14:16:40 +0200 Subject: [PATCH 123/822] Add Code of Conduct Based on the [Contributor Covenant](https://www.contributor-covenant.org) version 2.0. As there is no email address available for the project, I'm proposing to use the WP Core Slack channel #core-coding-standards as the official channel to report violations. Depending on the violation, details can shared in private via DMs if needed to protect the privacy of the parties involved. --- CODE_OF_CONDUCT.md | 128 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..c0a53dc110 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement in +the [WordPress Slack](https://make.wordpress.org/chat/) in the [#core-coding-standards channel](https://wordpress.slack.com/archives/C5VCTJGH3). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. From 222251d7a9ffba0cf0348b14d5454705ec910142 Mon Sep 17 00:00:00 2001 From: "Ipstenu (Mika Epstein)" Date: Mon, 16 May 2022 07:14:45 -0700 Subject: [PATCH 124/822] Document YodaConditionals you must (#1724) * Document YodaConditionals you must Co-authored-by: jrfnl --- WordPress/Docs/PHP/YodaConditionsStandard.xml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 WordPress/Docs/PHP/YodaConditionsStandard.xml diff --git a/WordPress/Docs/PHP/YodaConditionsStandard.xml b/WordPress/Docs/PHP/YodaConditionsStandard.xml new file mode 100644 index 0000000000..169cbcc368 --- /dev/null +++ b/WordPress/Docs/PHP/YodaConditionsStandard.xml @@ -0,0 +1,26 @@ + + + + + + + true === $the_force ) { + $victorious = you_will( $be ); +} + ]]> + + + $the_force === false ) { + $victorious = you_will_not( $be ); +} + ]]> + + + From 7d8c9fe9c6126a52379c39bfce70d234ae7b1493 Mon Sep 17 00:00:00 2001 From: Christopher Kanitz Date: Tue, 17 May 2022 10:52:17 +0200 Subject: [PATCH 125/822] Docs/WordPress.WhiteSpace.OperatorSpacing (#1727) * Create OperatorSpacingStandard.xml Co-Authored-By: Juliette <663378+jrfnl@users.noreply.github.com> --- .../WhiteSpace/OperatorSpacingStandard.xml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 WordPress/Docs/WhiteSpace/OperatorSpacingStandard.xml diff --git a/WordPress/Docs/WhiteSpace/OperatorSpacingStandard.xml b/WordPress/Docs/WhiteSpace/OperatorSpacingStandard.xml new file mode 100644 index 0000000000..ca17e57ff5 --- /dev/null +++ b/WordPress/Docs/WhiteSpace/OperatorSpacingStandard.xml @@ -0,0 +1,57 @@ + + + + + + + === $b && $b === $c ) {} +if ( ! $var ) {} + ]]> + + + && $b === $c ) {} +if ( ! $var ) {} + +// Too little space. +if ( $a===$b &&$b ===$c ) {} +if ( !$var ) {} + ]]> + + + + + + && $b === $c +) {} + ]]> + + + + && $b === $c +) {} + ]]> + + + + + = 'foo'; +$all = 'foobar'; + ]]> + + + = 'foo'; +$all ='foobar'; + ]]> + + + From 8df97123737e448c62a8952a9c23a6ee5d629c67 Mon Sep 17 00:00:00 2001 From: Marco Martins Date: Tue, 17 May 2022 11:52:54 +0300 Subject: [PATCH 126/822] Add PHP.StrictInArray XML documentation (#1740) * Add PHP.StrictInArray XML documentation Co-authored-by: jrfnl --- WordPress/Docs/PHP/StrictInArrayStandard.xml | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 WordPress/Docs/PHP/StrictInArrayStandard.xml diff --git a/WordPress/Docs/PHP/StrictInArrayStandard.xml b/WordPress/Docs/PHP/StrictInArrayStandard.xml new file mode 100644 index 0000000000..ccd8a0f752 --- /dev/null +++ b/WordPress/Docs/PHP/StrictInArrayStandard.xml @@ -0,0 +1,49 @@ + + + + + + + true ) ) {} + ]]> + + + ) ) {} + ]]> + + + + + + true ); + ]]> + + + ); + ]]> + + + + + + true ); + ]]> + + + ); + ]]> + + + From 11c354d83c8016443325243bcc9d76e0157fcf0d Mon Sep 17 00:00:00 2001 From: Marco Martins Date: Tue, 17 May 2022 11:54:35 +0300 Subject: [PATCH 127/822] Add the documentation for WordPress.Arrays.CommaAfterArrayItem (#1734) * Add the documentation for WordPress.Arrays.CommaAfterArrayItem Co-authored-by: jrfnl --- .../Arrays/CommaAfterArrayItemStandard.xml | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 WordPress/Docs/Arrays/CommaAfterArrayItemStandard.xml diff --git a/WordPress/Docs/Arrays/CommaAfterArrayItemStandard.xml b/WordPress/Docs/Arrays/CommaAfterArrayItemStandard.xml new file mode 100644 index 0000000000..a42d39771c --- /dev/null +++ b/WordPress/Docs/Arrays/CommaAfterArrayItemStandard.xml @@ -0,0 +1,94 @@ + + + + + + + 'value', + 'values' => array( 1 ), + 'extra' => 'c', /* Comment. */ +); + ]]> + + + 'value' , + 'values' => array( 1 ), + 'extra' => 'c' , /* Comment. */ +); + ]]> + + + + + + , 'b', 'c' ); + ]]> + + + ,'b', 'c' ); + ]]> + + + + + + + + + 'c' ); + ]]> + + + 'c', ); + ]]> + + + + + + + + + 'c', +); + +$assoc = array( + 'type' => 'value', + 'key' => 'c', +); + ]]> + + + + 'c' +); + +$assoc = array( + 'type' => 'value', + 'key' => 'c' +); + ]]> + + + From cfdb6d15818ce1ce4c6db0841d688c0d03ee8607 Mon Sep 17 00:00:00 2001 From: "Ipstenu (Mika Epstein)" Date: Thu, 2 Jun 2022 09:44:05 -0700 Subject: [PATCH 128/822] Prefix Your Globals (#1726) * Prefix Your Globals documentation * Use consistent indentation in the file. * Expand the base explanation. * Improve the valid/invalid descriptions. * Use `` tags to mark valid/invalid code. * Expand the code samples. * Add a code comparison demonstrating how namespaces affect the prefixes. * Remove the unclear sentence regarding reserved prefixes. * Clarify the three character minimum length rule. Co-authored-by: jrfnl --- .../PrefixAllGlobalsStandard.xml | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 WordPress/Docs/NamingConventions/PrefixAllGlobalsStandard.xml diff --git a/WordPress/Docs/NamingConventions/PrefixAllGlobalsStandard.xml b/WordPress/Docs/NamingConventions/PrefixAllGlobalsStandard.xml new file mode 100644 index 0000000000..855dba8e6c --- /dev/null +++ b/WordPress/Docs/NamingConventions/PrefixAllGlobalsStandard.xml @@ -0,0 +1,115 @@ + + + + + + + 'ECPT_VERSION', '1.0' ); + +$ecpt_admin = new ECPT_Admin_Page(); + +class ECPT_Admin_Page {} + +apply_filter( + 'ecpt_modify_content', + $ecpt_content +); + ]]> + + + 'PLUGIN_VERSION', '1.0' ); + +$admin = new Admin_Page(); + +class Admin_Page {} + +apply_filter( + 'modify_content', + $content +); + ]]> + + + + + ECPT_Plugin\Admin; + +// Constants declared using `const` will +// be namespaced and therefore prefixed. +const VERSION = 1.0; + +// A class declared in a (prefixed) namespace +// is automatically prefixed. +class Admin_Page {} + +// Variables in a namespaced file are not +// namespaced, so still need prefixing. +$ecpt_admin = new Admin_Page(); + +// Hook names are not subject to namespacing. +apply_filter( + 'ecpt_modify_content', + $ecpt_content +); + ]]> + + + Admin; + +// As the namespace is not prefixed, this +// is still bad. +const VERSION = 1.0; + +// As the namespace is not prefixed, this +// is still bad. +class Admin_Page {} + ]]> + + + + + + + + mycoolplugin_save_post() {} + ]]> + + + wp_save_post() {} + ]]> + + + + + + + + MyPluginIsCool {} + ]]> + + + My {} + ]]> + + + From 4d803981d9e55dd686ccd90e2b3dd95ba7058699 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 3 Jun 2022 16:15:29 +0200 Subject: [PATCH 129/822] NamingConventions/ValidHookName: bug fix - ignore parameters passed to function calls This commit changes the sniff to ignore parameters passed to function calls by skipping over the tokens containing within parentheses, but only if those parentheses appear to be for a literal function call (last non-empty token before the open parenthesis is a `T_STRING`). Text string tokens within _arbitrary_ parentheses will still be examined. Note: this does not take variable function calls into account, but as, generally speaking, the hook name shouldn't be generated via a function call anyway, I don't think that's an issue we need to worry about (unless someone submits a bug report for it). Includes unit tests. Fixes 2055 --- .../NamingConventions/ValidHookNameSniff.php | 24 ++++- .../ValidHookNameUnitTest.1.inc | 14 +++ .../ValidHookNameUnitTest.php | 92 ++++++++++--------- 3 files changed, 80 insertions(+), 50 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php b/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php index f0d3558ca8..7ce5f8f916 100644 --- a/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidHookNameSniff.php @@ -100,10 +100,11 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $regex = $this->prepare_regex(); - $case_errors = 0; - $underscores = 0; - $content = array(); - $expected = array(); + $case_errors = 0; + $underscores = 0; + $content = array(); + $expected = array(); + $last_non_empty = null; for ( $i = $parameters[1]['start']; $i <= $parameters[1]['end']; $i++ ) { // Skip past comment tokens. @@ -129,15 +130,28 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p } while ( isset( $this->tokens[ $i ] ) && $i <= $parameters[1]['end'] ); + $last_non_empty = $i; + continue; + } + + // Skip over parameters passed to function calls. + if ( \T_OPEN_PARENTHESIS === $this->tokens[ $i ]['code'] + && \T_STRING === $this->tokens[ $last_non_empty ]['code'] + && isset( $this->tokens[ $i ]['parenthesis_closer'] ) + ) { + $i = $this->tokens[ $i ]['parenthesis_closer']; + $last_non_empty = $i; continue; } // Skip past non-string tokens. if ( isset( Tokens::$stringTokens[ $this->tokens[ $i ]['code'] ] ) === false ) { + $last_non_empty = $i; continue; } - $string = TextStrings::stripQuotes( $this->tokens[ $i ]['content'] ); + $last_non_empty = $i; + $string = TextStrings::stripQuotes( $this->tokens[ $i ]['content'] ); /* * Here be dragons - a double quoted string can contain extrapolated variables diff --git a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc index 039ca6484e..2c03bfe5fa 100644 --- a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc @@ -94,3 +94,17 @@ do_action( // phpcs:ignore Stnd.Cat.Sniff -- For reasons. 'prefix_hook-name' /* comment */ ); + +// Ignore text strings when passed as parameters to a function call. WPCS #2055. +$value = apply_filters( + get_filter_name( 'UPPERCASE', 'wrong-delimiter' ), + $value, + $attributes +); + +// ... but do not ignore text strings in arbitrary parentheses. +$value = apply_filters( + ( $name ? 'UPPERCASE' : 'wrong-delimiter' ), + $value, + $attributes +); diff --git a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php index c55be6b044..b01a626282 100644 --- a/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidHookNameUnitTest.php @@ -32,43 +32,44 @@ public function getErrorList( $testFile = 'ValidHookNameUnitTest.1.inc' ) { switch ( $testFile ) { case 'ValidHookNameUnitTest.1.inc': return array( - 14 => 1, - 15 => 1, - 16 => 1, - 17 => 1, - 28 => 1, - 29 => 1, - 30 => 1, - 33 => 1, - 53 => 1, - 54 => 1, - 55 => 1, - 56 => 1, - 57 => 1, - 58 => 1, - 59 => 1, - 60 => 1, - 61 => 1, - 62 => 1, - 63 => 1, - 64 => 1, - 65 => 1, - 66 => 1, - 68 => 1, - 69 => 1, - 70 => 1, - 71 => 1, - 72 => 1, - 73 => 1, - 74 => 1, - 75 => 1, - 76 => 1, - 77 => 1, - 78 => 1, - 79 => 1, - 80 => 1, - 81 => 1, - 89 => 1, + 14 => 1, + 15 => 1, + 16 => 1, + 17 => 1, + 28 => 1, + 29 => 1, + 30 => 1, + 33 => 1, + 53 => 1, + 54 => 1, + 55 => 1, + 56 => 1, + 57 => 1, + 58 => 1, + 59 => 1, + 60 => 1, + 61 => 1, + 62 => 1, + 63 => 1, + 64 => 1, + 65 => 1, + 66 => 1, + 68 => 1, + 69 => 1, + 70 => 1, + 71 => 1, + 72 => 1, + 73 => 1, + 74 => 1, + 75 => 1, + 76 => 1, + 77 => 1, + 78 => 1, + 79 => 1, + 80 => 1, + 81 => 1, + 89 => 1, + 107 => 1, ); case 'ValidHookNameUnitTest.2.inc': @@ -89,14 +90,15 @@ public function getWarningList( $testFile = 'ValidHookNameUnitTest.1.inc' ) { switch ( $testFile ) { case 'ValidHookNameUnitTest.1.inc': return array( - 8 => 1, - 9 => 1, - 10 => 1, - 11 => 1, - 68 => 1, - 72 => 1, - 77 => 1, - 95 => 1, + 8 => 1, + 9 => 1, + 10 => 1, + 11 => 1, + 68 => 1, + 72 => 1, + 77 => 1, + 95 => 1, + 107 => 1, ); case 'ValidHookNameUnitTest.2.inc': From 750cb11d78c42564708e3f16920557ad94fb841b Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Sat, 4 Jun 2022 11:11:49 +0100 Subject: [PATCH 130/822] Docs: Add TimezoneChange XML doc (#1731) * Docs: Add TimezoneChange XML doc --- .../DateTime/RestrictedFunctionsStandard.xml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 WordPress/Docs/DateTime/RestrictedFunctionsStandard.xml diff --git a/WordPress/Docs/DateTime/RestrictedFunctionsStandard.xml b/WordPress/Docs/DateTime/RestrictedFunctionsStandard.xml new file mode 100644 index 0000000000..c8cc932cc9 --- /dev/null +++ b/WordPress/Docs/DateTime/RestrictedFunctionsStandard.xml @@ -0,0 +1,50 @@ + + + + + + + + + + DateTime(); +$date->setTimezone( + new DateTimeZone( 'Europe/Amsterdam' ) +); + ]]> + + + date_default_timezone_set( 'Europe/Amsterdam' ); + ]]> + + + + + + + + gmdate( + 'Y-m-d\TH:i:s', + strtotime( $plugin['last_updated'] ) +); + ]]> + + + date( + 'Y-m-d\TH:i:s', + strtotime( $plugin['last_updated'] ) +); + ]]> + + + From def118b099db14c2fbfea6a488f660c49e1d917c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 15 May 2022 16:30:03 +0200 Subject: [PATCH 131/822] Composer: up the minimum PHPCS version to 3.7.0 As discussed in issue 2048 and PR 2049, to add support for PHP 8.1 features to WPCS and prevent false positives related to PHP 8.1 features, this commit ups the minimum supported PHPCS version to PHPCS 3.7.0. Includes updating the GH Actions matrixes for this change. Fixes 2048 --- .github/CONTRIBUTING.md | 2 +- .github/ISSUE_TEMPLATE/dependency-change.md | 2 +- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/ruleset-checks-sniffs.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- README.md | 2 +- composer.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7fd8c23149..4acbf78a09 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -36,7 +36,7 @@ When you introduce new `public` sniff properties, or your sniff extends a class ## Pre-requisites * WordPress-Coding-Standards -* PHP_CodeSniffer 3.6.2 or higher +* PHP_CodeSniffer 3.7.0 or higher * PHPUnit 4.x, 5.x, 6.x or 7.x The WordPress Coding Standards use the `PHP_CodeSniffer` native unit test suite for unit testing the sniffs. diff --git a/.github/ISSUE_TEMPLATE/dependency-change.md b/.github/ISSUE_TEMPLATE/dependency-change.md index d6de56e870..a8ce13adbe 100644 --- a/.github/ISSUE_TEMPLATE/dependency-change.md +++ b/.github/ISSUE_TEMPLATE/dependency-change.md @@ -4,7 +4,7 @@ about: A reminder to take action when a WPCS dependency changes --- - + ## Rationale diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 1267203d40..f7998e2909 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -36,9 +36,9 @@ jobs: phpcs_version: [ 'dev-master' ] include: - php: '7.3' - phpcs_version: '3.6.2' + phpcs_version: '3.7.0' - php: '5.4' - phpcs_version: '3.6.2' + phpcs_version: '3.7.0' steps: - name: Checkout repository diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index 616ab0e200..fddc940360 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -115,7 +115,7 @@ jobs: strategy: matrix: php: [ '7.4' ] - phpcs_version: [ 'dev-master', '3.6.2' ] + phpcs_version: [ 'dev-master', '3.7.0' ] steps: - name: Checkout repository diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index f2052d3028..5020375e05 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -35,7 +35,7 @@ jobs: strategy: matrix: php: [ '8.1', '8.0', '7.4', '7.3', '7.2', '7.1', '7.0', '5.6', '5.5', '5.4' ] - phpcs_version: [ 'dev-master', '3.6.2' ] + phpcs_version: [ 'dev-master', '3.7.0' ] allowed_failure: [ false ] include: # Add extra build to test against PHPCS 4. diff --git a/README.md b/README.md index 0523a09cc7..1b1a859456 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ This project is a collection of [PHP_CodeSniffer](https://github.com/squizlabs/P ### Requirements -The WordPress Coding Standards require PHP 5.4 or higher and [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version **3.6.2** or higher. +The WordPress Coding Standards require PHP 5.4 or higher and [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version **3.7.0** or higher. ### Composer diff --git a/composer.json b/composer.json index 2ca4eaea60..74b01ea39b 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ ], "require": { "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.6.2", + "squizlabs/php_codesniffer": "^3.7.0", "phpcsstandards/phpcsutils": "^1.0", "phpcsstandards/phpcsextra": "^1.0" }, From ae49dcf5d83e496a24090b94dc464e74b0e89265 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 12:22:10 +0200 Subject: [PATCH 132/822] Helper classes: explicitly state there is no BC promise For the `Helper` classes which do not contain WordPress specific code and for which it is likely that PHPCSUtils may at some point replace the functionality, make it very clear that those classes are not covered by a promise of backward-compatibility. By doing this, we buy ourselves the freedom to remove methods from these classes/the classes completely if/when PHPCSUtils would offer similar functionality, without the need to create a new major release of WPCS when we do. --- WordPress/Helpers/DeprecationHelper.php | 5 +++++ WordPress/Helpers/TextStringHelper.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/WordPress/Helpers/DeprecationHelper.php b/WordPress/Helpers/DeprecationHelper.php index dc6a992755..fa55b143a1 100644 --- a/WordPress/Helpers/DeprecationHelper.php +++ b/WordPress/Helpers/DeprecationHelper.php @@ -15,6 +15,11 @@ /** * Helper utilities for checking whether something has been marked as deprecated. * + * --------------------------------------------------------------------------------------------- + * This class is only intended for internal use by WordPressCS and is not part of the public API. + * This also means that it has no promise of backward compatibility. Use at your own risk. + * --------------------------------------------------------------------------------------------- + * * {@internal The functionality in this class will likely be replaced at some point in * the future by functions from PHPCSUtils.} * diff --git a/WordPress/Helpers/TextStringHelper.php b/WordPress/Helpers/TextStringHelper.php index 13b63aa022..9246835280 100644 --- a/WordPress/Helpers/TextStringHelper.php +++ b/WordPress/Helpers/TextStringHelper.php @@ -12,6 +12,11 @@ /** * Helper utilities for handling text strings. * + * --------------------------------------------------------------------------------------------- + * This class is only intended for internal use by WordPressCS and is not part of the public API. + * This also means that it has no promise of backward compatibility. Use at your own risk. + * --------------------------------------------------------------------------------------------- + * * {@internal The functionality in this class will likely be replaced at some point in * the future by functions from PHPCSUtils.} * From 0db0767092aa865aef299bcb5cacb42373570969 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 15 May 2022 13:16:05 +0200 Subject: [PATCH 133/822] Move "array access keys" related utilities to dedicated `VariableHelper` The "array access keys" related utilities are only used by a small set of sniffs, so are better placed in a dedicated class. This commit moves the `get_array_access_keys()` method and the `get_array_access_key()` method to a new `WordPressCS\WordPress\Helpers\VariableHelper` and starts using that class in the relevant sniffs. In contrast to some of the other "move methods out of the Sniff class" PRs, these methods have been moved to a class and made `static` - instead of moved to a `trait`. The reason for this difference is that the methods in other "moves" are setting properties which the sniff classes would need access to, while these methods are 100% stand-alone. **Note**: It is expected for PHPCSUtils to have dedicated methods for the same at some point in the future. If/when those methods become available, it is recommended for the sniffs to start using the PHPCSUtils methods. With this in mind, this class has been marked as "internal" without BC promise. Related to 1465 --- WordPress/Helpers/VariableHelper.php | 113 ++++++++++++++++++ WordPress/Sniff.php | 83 +------------ .../Sniffs/Security/EscapeOutputSniff.php | 5 +- .../Security/ValidatedSanitizedInputSniff.php | 3 +- .../WP/GlobalVariablesOverrideSniff.php | 5 +- 5 files changed, 125 insertions(+), 84 deletions(-) create mode 100644 WordPress/Helpers/VariableHelper.php diff --git a/WordPress/Helpers/VariableHelper.php b/WordPress/Helpers/VariableHelper.php new file mode 100644 index 0000000000..60f7ffa422 --- /dev/null +++ b/WordPress/Helpers/VariableHelper.php @@ -0,0 +1,113 @@ +getTokens(); + $keys = array(); + + if ( \T_VARIABLE !== $tokens[ $stackPtr ]['code'] ) { + return $keys; + } + + $current = $stackPtr; + + do { + // Find the next non-empty token. + $open_bracket = $phpcsFile->findNext( + Tokens::$emptyTokens, + ( $current + 1 ), + null, + true + ); + + // If it isn't a bracket, this isn't an array-access. + if ( false === $open_bracket + || \T_OPEN_SQUARE_BRACKET !== $tokens[ $open_bracket ]['code'] + || ! isset( $tokens[ $open_bracket ]['bracket_closer'] ) + ) { + break; + } + + $key = $phpcsFile->getTokensAsString( + ( $open_bracket + 1 ), + ( $tokens[ $open_bracket ]['bracket_closer'] - $open_bracket - 1 ) + ); + + $keys[] = trim( $key ); + $current = $tokens[ $open_bracket ]['bracket_closer']; + } while ( isset( $tokens[ $current ] ) && true === $all ); + + return $keys; + } + + /** + * Get the index key of an array variable. + * + * E.g., "bar" in $foo['bar']. + * + * @since 0.5.0 + * @since 2.1.0 Now uses get_array_access_keys() under the hood. + * @since 3.0.0 - Moved from the Sniff class to this class. + * - Visibility is now `public` (was `protected`) and the method `static`. + * - The $phpcsFile parameter was added. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The index of the token in the stack. + * + * @return string|false The array index key whose value is being accessed. + */ + public static function get_array_access_key( File $phpcsFile, $stackPtr ) { + $keys = self::get_array_access_keys( $phpcsFile, $stackPtr, false ); + if ( isset( $keys[0] ) ) { + return $keys[0]; + } + + return false; + } +} diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 0e38885671..fa5dfd4720 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -16,6 +16,7 @@ use PHPCSUtils\Utils\PassedParameters; use PHPCSUtils\Utils\Scopes; use PHPCSUtils\Utils\TextStrings; +use WordPressCS\WordPress\Helpers\VariableHelper; /** * Represents a PHP_CodeSniffer sniff for sniffing WordPress coding standards. @@ -1613,82 +1614,6 @@ public function add_unslash_error( $stackPtr ) { ); } - /** - * Get the index keys of an array variable. - * - * E.g., "bar" and "baz" in $foo['bar']['baz']. - * - * @since 2.1.0 - * - * @param int $stackPtr The index of the variable token in the stack. - * @param bool $all Whether to get all keys or only the first. - * Defaults to `true`(= all). - * - * @return array An array of index keys whose value is being accessed. - * or an empty array if this is not array access. - */ - protected function get_array_access_keys( $stackPtr, $all = true ) { - - $keys = array(); - - if ( \T_VARIABLE !== $this->tokens[ $stackPtr ]['code'] ) { - return $keys; - } - - $current = $stackPtr; - - do { - // Find the next non-empty token. - $open_bracket = $this->phpcsFile->findNext( - Tokens::$emptyTokens, - ( $current + 1 ), - null, - true - ); - - // If it isn't a bracket, this isn't an array-access. - if ( false === $open_bracket - || \T_OPEN_SQUARE_BRACKET !== $this->tokens[ $open_bracket ]['code'] - || ! isset( $this->tokens[ $open_bracket ]['bracket_closer'] ) - ) { - break; - } - - $key = $this->phpcsFile->getTokensAsString( - ( $open_bracket + 1 ), - ( $this->tokens[ $open_bracket ]['bracket_closer'] - $open_bracket - 1 ) - ); - - $keys[] = trim( $key ); - $current = $this->tokens[ $open_bracket ]['bracket_closer']; - } while ( isset( $this->tokens[ $current ] ) && true === $all ); - - return $keys; - } - - /** - * Get the index key of an array variable. - * - * E.g., "bar" in $foo['bar']. - * - * @since 0.5.0 - * @since 2.1.0 Now uses get_array_access_keys() under the hood. - * - * @param int $stackPtr The index of the token in the stack. - * - * @return string|false The array index key whose value is being accessed. - */ - protected function get_array_access_key( $stackPtr ) { - - $keys = $this->get_array_access_keys( $stackPtr, false ); - - if ( isset( $keys[0] ) ) { - return $keys[0]; - } - - return false; - } - /** * Check if the existence of a variable is validated with isset(), empty(), array_key_exists() * or key_exists(). @@ -1826,7 +1751,7 @@ protected function is_validated( $stackPtr, $array_keys = array(), $in_condition // If we're checking for specific array keys (ex: 'hello' in // $_POST['hello']), that must match too. Quote-style, however, doesn't matter. if ( ! empty( $bare_array_keys ) ) { - $found_keys = $this->get_array_access_keys( $i ); + $found_keys = VariableHelper::get_array_access_keys( $this->phpcsFile, $i ); $found_keys = array_map( array( 'PHPCSUtils\Utils\TextStrings', 'stripQuotes' ), $found_keys ); $diff = array_diff_assoc( $bare_array_keys, $found_keys ); if ( ! empty( $diff ) ) { @@ -1887,7 +1812,7 @@ protected function is_validated( $stackPtr, $array_keys = array(), $in_condition * parameter, so we need to check both options. */ - $found_keys = $this->get_array_access_keys( $param2_first_token ); + $found_keys = VariableHelper::get_array_access_keys( $this->phpcsFile, $param2_first_token ); $found_keys = array_map( array( 'PHPCSUtils\Utils\TextStrings', 'stripQuotes' ), $found_keys ); // First try matching the complete set against the second parameter. @@ -1931,7 +1856,7 @@ protected function is_validated( $stackPtr, $array_keys = array(), $in_condition } if ( ! empty( $bare_array_keys ) ) { - $found_keys = $this->get_array_access_keys( $prev ); + $found_keys = VariableHelper::get_array_access_keys( $this->phpcsFile, $prev ); $found_keys = array_map( array( 'PHPCSUtils\Utils\TextStrings', 'stripQuotes' ), $found_keys ); $diff = array_diff_assoc( $bare_array_keys, $found_keys ); if ( ! empty( $diff ) ) { diff --git a/WordPress/Sniffs/Security/EscapeOutputSniff.php b/WordPress/Sniffs/Security/EscapeOutputSniff.php index 09cd206ff3..ce686ac05d 100644 --- a/WordPress/Sniffs/Security/EscapeOutputSniff.php +++ b/WordPress/Sniffs/Security/EscapeOutputSniff.php @@ -9,10 +9,11 @@ namespace WordPressCS\WordPress\Sniffs\Security; -use WordPressCS\WordPress\Sniff; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\PassedParameters; use PHPCSUtils\Utils\TextStrings; +use WordPressCS\WordPress\Helpers\VariableHelper; +use WordPressCS\WordPress\Sniff; /** * Verifies that all outputted strings are escaped. @@ -452,7 +453,7 @@ public function process_token( $stackPtr ) { // Make the error message a little more informative for array access variables. if ( \T_VARIABLE === $this->tokens[ $ptr ]['code'] ) { - $array_keys = $this->get_array_access_keys( $ptr ); + $array_keys = VariableHelper::get_array_access_keys( $this->phpcsFile, $ptr ); if ( ! empty( $array_keys ) ) { $content .= '[' . implode( '][', $array_keys ) . ']'; diff --git a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php index 00289b07bd..1e1847fbb5 100644 --- a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php +++ b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Util\Tokens; use WordPressCS\WordPress\Helpers\TextStringHelper; +use WordPressCS\WordPress\Helpers\VariableHelper; use WordPressCS\WordPress\Sniff; /** @@ -125,7 +126,7 @@ function ( $symbol ) { return; } - $array_keys = $this->get_array_access_keys( $stackPtr ); + $array_keys = VariableHelper::get_array_access_keys( $this->phpcsFile, $stackPtr ); if ( empty( $array_keys ) ) { return; diff --git a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php index d07064c489..0ab1bcd1d5 100644 --- a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php +++ b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php @@ -13,8 +13,9 @@ use PHPCSUtils\Utils\Lists; use PHPCSUtils\Utils\Scopes; use PHPCSUtils\Utils\TextStrings; -use WordPressCS\WordPress\Sniff; use WordPressCS\WordPress\Helpers\IsUnitTestTrait; +use WordPressCS\WordPress\Helpers\VariableHelper; +use WordPressCS\WordPress\Sniff; /** * Warns about overwriting WordPress native global variables. @@ -384,7 +385,7 @@ protected function process_global_statement( $stackPtr, $in_function_scope ) { foreach ( $var_pointers as $ptr ) { $var_name = $this->tokens[ $ptr ]['content']; if ( '$GLOBALS' === $var_name ) { - $var_name = '$' . TextStrings::stripQuotes( $this->get_array_access_key( $ptr ) ); + $var_name = '$' . TextStrings::stripQuotes( VariableHelper::get_array_access_key( $this->phpcsFile, $ptr ) ); } if ( \in_array( $var_name, $search, true ) ) { From 8d3bb6fd44d6db98d6e80923371659c9ae353bc4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 15 May 2022 13:30:23 +0200 Subject: [PATCH 134/822] VariableHelper::get_array_access_keys() use PHPCSUtils Use the PHPCSUtils `GetTokensAsString::compact()` method to retrieve array access keys without extraneous whitespace or comments. --- WordPress/Helpers/VariableHelper.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/WordPress/Helpers/VariableHelper.php b/WordPress/Helpers/VariableHelper.php index 60f7ffa422..de12ac98f2 100644 --- a/WordPress/Helpers/VariableHelper.php +++ b/WordPress/Helpers/VariableHelper.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Utils\GetTokensAsString; /** * Helper utilities for working with variables representing arrays. @@ -74,9 +75,11 @@ public static function get_array_access_keys( File $phpcsFile, $stackPtr, $all = break; } - $key = $phpcsFile->getTokensAsString( + $key = GetTokensAsString::compact( + $phpcsFile, ( $open_bracket + 1 ), - ( $tokens[ $open_bracket ]['bracket_closer'] - $open_bracket - 1 ) + ( $tokens[ $open_bracket ]['bracket_closer'] - 1 ), + true ); $keys[] = trim( $key ); From bb5822a1866506eb7959f9e3d635bfa7872c09a3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 15 May 2022 13:43:19 +0200 Subject: [PATCH 135/822] Move "is comparison" related utility to dedicated `VariableHelper` The "is comparison" related utility method is only used by a small set of sniffs, so is better placed in a dedicated class. As this method also expects a `T_VARIABLE` token as input, the `VariableHelper` class seems appropriate. This commit moves the `is_comparison()` method to the new `WordPressCS\WordPress\Helpers\VariableHelper` and starts using that class in the relevant sniffs. **Note**: It is expected for PHPCSUtils to have dedicated methods for the same at some point in the future. If/when those methods become available, it is recommended for the sniffs to start using the PHPCSUtils methods. Related to 1465 --- WordPress/Helpers/VariableHelper.php | 75 ++++++++++++++++- WordPress/Sniff.php | 81 +------------------ .../Security/ValidatedSanitizedInputSniff.php | 2 +- 3 files changed, 76 insertions(+), 82 deletions(-) diff --git a/WordPress/Helpers/VariableHelper.php b/WordPress/Helpers/VariableHelper.php index de12ac98f2..4714b066b9 100644 --- a/WordPress/Helpers/VariableHelper.php +++ b/WordPress/Helpers/VariableHelper.php @@ -14,7 +14,7 @@ use PHPCSUtils\Utils\GetTokensAsString; /** - * Helper utilities for working with variables representing arrays. + * Helper utilities for working with variables. * * --------------------------------------------------------------------------------------------- * This class is only intended for internal use by WordPressCS and is not part of the public API. @@ -113,4 +113,77 @@ public static function get_array_access_key( File $phpcsFile, $stackPtr ) { return false; } + + /** + * Check whether a variable is being compared to another value. + * + * E.g., $var === 'foo', 1 <= $var, etc. + * + * Also recognizes `switch ( $var )`. + * + * @since 0.5.0 + * @since 2.1.0 Added the $include_coalesce parameter. + * @since 3.0.0 - Moved from the Sniff class to this class. + * - Visibility is now `public` (was `protected`) and the method `static`. + * - The $phpcsFile parameter was added. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The index of this token in the stack. + * @param bool $include_coalesce Optional. Whether or not to regard the null + * coalesce operator - ?? - as a comparison operator. + * Defaults to true. + * Null coalesce is a special comparison operator in this + * sense as it doesn't compare a variable to whatever is + * on the other side of the comparison operator. + * + * @return bool Whether this is a comparison. + */ + public static function is_comparison( File $phpcsFile, $stackPtr, $include_coalesce = true ) { + $tokens = $phpcsFile->getTokens(); + $comparisonTokens = Tokens::$comparisonTokens; + if ( false === $include_coalesce ) { + unset( $comparisonTokens[ \T_COALESCE ] ); + } + + // We first check if this is a switch statement (switch ( $var )). + if ( isset( $tokens[ $stackPtr ]['nested_parenthesis'] ) ) { + $nested_parenthesis = $tokens[ $stackPtr ]['nested_parenthesis']; + $close_parenthesis = end( $nested_parenthesis ); + + if ( + isset( $tokens[ $close_parenthesis ]['parenthesis_owner'] ) + && \T_SWITCH === $tokens[ $tokens[ $close_parenthesis ]['parenthesis_owner'] ]['code'] + ) { + return true; + } + } + + // Find the previous non-empty token. We check before the var first because + // yoda conditions are usually expected. + $previous_token = $phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true ); + + if ( isset( $comparisonTokens[ $tokens[ $previous_token ]['code'] ] ) ) { + return true; + } + + // Maybe the comparison operator is after this. + $next_token = $phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); + + // This might be an opening square bracket in the case of arrays ($var['a']). + while ( false !== $next_token && \T_OPEN_SQUARE_BRACKET === $tokens[ $next_token ]['code'] ) { + + $next_token = $phpcsFile->findNext( + Tokens::$emptyTokens, + ( $tokens[ $next_token ]['bracket_closer'] + 1 ), + null, + true + ); + } + + if ( false !== $next_token && isset( $comparisonTokens[ $tokens[ $next_token ]['code'] ] ) ) { + return true; + } + + return false; + } } diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index fa5dfd4720..c54d6c23c4 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -1124,7 +1124,7 @@ protected function has_nonce_check( $stackPtr ) { $allow_nonce_after = false; if ( $this->is_in_isset_or_empty( $stackPtr ) || $this->is_in_type_test( $stackPtr ) - || $this->is_comparison( $stackPtr ) + || VariableHelper::is_comparison( $this->phpcsFile, $stackPtr ) || $this->is_in_array_comparison( $stackPtr ) || $this->is_in_function_call( $stackPtr, $this->unslashingFunctions ) !== false || $this->is_only_sanitized( $stackPtr ) @@ -1872,85 +1872,6 @@ protected function is_validated( $stackPtr, $array_keys = array(), $in_condition return false; } - /** - * Check whether a variable is being compared to another value. - * - * E.g., $var === 'foo', 1 <= $var, etc. - * - * Also recognizes `switch ( $var )`. - * - * @since 0.5.0 - * @since 2.1.0 Added the $include_coalesce parameter. - * - * @param int $stackPtr The index of this token in the stack. - * @param bool $include_coalesce Optional. Whether or not to regard the null - * coalesce operator - ?? - as a comparison operator. - * Defaults to true. - * Null coalesce is a special comparison operator in this - * sense as it doesn't compare a variable to whatever is - * on the other side of the comparison operator. - * - * @return bool Whether this is a comparison. - */ - protected function is_comparison( $stackPtr, $include_coalesce = true ) { - - $comparisonTokens = Tokens::$comparisonTokens; - if ( false === $include_coalesce ) { - unset( $comparisonTokens[ \T_COALESCE ] ); - } - - // We first check if this is a switch statement (switch ( $var )). - if ( isset( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) { - $nested_parenthesis = $this->tokens[ $stackPtr ]['nested_parenthesis']; - $close_parenthesis = end( $nested_parenthesis ); - - if ( - isset( $this->tokens[ $close_parenthesis ]['parenthesis_owner'] ) - && \T_SWITCH === $this->tokens[ $this->tokens[ $close_parenthesis ]['parenthesis_owner'] ]['code'] - ) { - return true; - } - } - - // Find the previous non-empty token. We check before the var first because - // yoda conditions are usually expected. - $previous_token = $this->phpcsFile->findPrevious( - Tokens::$emptyTokens, - ( $stackPtr - 1 ), - null, - true - ); - - if ( isset( $comparisonTokens[ $this->tokens[ $previous_token ]['code'] ] ) ) { - return true; - } - - // Maybe the comparison operator is after this. - $next_token = $this->phpcsFile->findNext( - Tokens::$emptyTokens, - ( $stackPtr + 1 ), - null, - true - ); - - // This might be an opening square bracket in the case of arrays ($var['a']). - while ( false !== $next_token && \T_OPEN_SQUARE_BRACKET === $this->tokens[ $next_token ]['code'] ) { - - $next_token = $this->phpcsFile->findNext( - Tokens::$emptyTokens, - ( $this->tokens[ $next_token ]['bracket_closer'] + 1 ), - null, - true - ); - } - - if ( false !== $next_token && isset( $comparisonTokens[ $this->tokens[ $next_token ]['code'] ] ) ) { - return true; - } - - return false; - } - /** * Check if a token is inside of an array-value comparison function. * diff --git a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php index 1e1847fbb5..d3810ff68e 100644 --- a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php +++ b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php @@ -179,7 +179,7 @@ function ( $symbol ) { } // If this is a comparison ('a' == $_POST['foo']), sanitization isn't needed. - if ( $this->is_comparison( $stackPtr, false ) ) { + if ( VariableHelper::is_comparison( $this->phpcsFile, $stackPtr, false ) ) { return; } From 54d6474045145a1678c529f4e31233c4f11d2ea5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 15 May 2022 13:54:00 +0200 Subject: [PATCH 136/822] VariableHelper::is_comparison(): use PHPCSUtils ... to get the potential parentheses opener. --- WordPress/Helpers/VariableHelper.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/WordPress/Helpers/VariableHelper.php b/WordPress/Helpers/VariableHelper.php index 4714b066b9..7c47660d69 100644 --- a/WordPress/Helpers/VariableHelper.php +++ b/WordPress/Helpers/VariableHelper.php @@ -12,6 +12,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\GetTokensAsString; +use PHPCSUtils\Utils\Parentheses; /** * Helper utilities for working with variables. @@ -146,16 +147,8 @@ public static function is_comparison( File $phpcsFile, $stackPtr, $include_coale } // We first check if this is a switch statement (switch ( $var )). - if ( isset( $tokens[ $stackPtr ]['nested_parenthesis'] ) ) { - $nested_parenthesis = $tokens[ $stackPtr ]['nested_parenthesis']; - $close_parenthesis = end( $nested_parenthesis ); - - if ( - isset( $tokens[ $close_parenthesis ]['parenthesis_owner'] ) - && \T_SWITCH === $tokens[ $tokens[ $close_parenthesis ]['parenthesis_owner'] ]['code'] - ) { - return true; - } + if ( Parentheses::lastOwnerIn( $phpcsFile, $stackPtr, array( \T_SWITCH ) ) !== false ) { + return true; } // Find the previous non-empty token. We check before the var first because From c592999c8dbf8ae25f47c9314fdef90ab653bdd6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 15 May 2022 14:03:29 +0200 Subject: [PATCH 137/822] PHP 8.0 | VariableHelper::is_comparison(): add support for variables being compared in a `match` expression PHP 8.0 introduced `match` expressions, which do a (strict) comparison on the value in the condition against the options in the `match` body. Ref: https://www.php.net/manual/en/control-structures.match.php This commit updates the `is_comparison()` method to allow for variables in the "condition" part of a `match` expression to be considered part of a comparison. Tested via the `ValidatedSanitizedInput` sniff. --- WordPress/Helpers/VariableHelper.php | 6 +++--- .../Tests/Security/ValidatedSanitizedInputUnitTest.inc | 3 +++ .../Tests/Security/ValidatedSanitizedInputUnitTest.php | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/WordPress/Helpers/VariableHelper.php b/WordPress/Helpers/VariableHelper.php index 7c47660d69..a1a5e46362 100644 --- a/WordPress/Helpers/VariableHelper.php +++ b/WordPress/Helpers/VariableHelper.php @@ -120,7 +120,7 @@ public static function get_array_access_key( File $phpcsFile, $stackPtr ) { * * E.g., $var === 'foo', 1 <= $var, etc. * - * Also recognizes `switch ( $var )`. + * Also recognizes `switch ( $var )` and `match ( $var )`. * * @since 0.5.0 * @since 2.1.0 Added the $include_coalesce parameter. @@ -146,8 +146,8 @@ public static function is_comparison( File $phpcsFile, $stackPtr, $include_coale unset( $comparisonTokens[ \T_COALESCE ] ); } - // We first check if this is a switch statement (switch ( $var )). - if ( Parentheses::lastOwnerIn( $phpcsFile, $stackPtr, array( \T_SWITCH ) ) !== false ) { + // We first check if this is a switch or match statement (switch ( $var )). + if ( Parentheses::lastOwnerIn( $phpcsFile, $stackPtr, array( \T_SWITCH, \T_MATCH ) ) !== false ) { return true; } diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc index 12f9f65309..f5d5dd6e07 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc @@ -333,3 +333,6 @@ function test_using_different_unslashing_functions() { } echo wp_sanitize_redirect( wp_unslash( $_GET['test'] ) ); // OK. + +$result = match ( $_POST['foo'] ) {}; // Ok. +$result = match ( do_something( wp_unslash( $_POST['foo'] ) ) ) {}; // Bad. diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php index 8643c2a78d..ac41f98ad2 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php @@ -80,6 +80,7 @@ public function getErrorList() { 315 => 2, 317 => 1, 323 => 1, + 338 => 1, ); } From df1b997912e3377590d20bc7edd0452ea323cd44 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 13:53:02 +0200 Subject: [PATCH 138/822] DB/DirectDatabaseQuery: remove custom ignore annotation support Follow up on 1583 / PR 1908 which removed the `Sniff::has_whitelist_comment()`. The `WordPress.DB.DirectDatabaseQuery` had its own - even more custom - ignore annotation mechanism. This commit removes that mechanism and updates (and cleans up) the unit tests. --- .../Sniffs/DB/DirectDatabaseQuerySniff.php | 23 +--- .../Tests/DB/DirectDatabaseQueryUnitTest.inc | 117 +++++++----------- .../Tests/DB/DirectDatabaseQueryUnitTest.php | 59 ++++++--- 3 files changed, 96 insertions(+), 103 deletions(-) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index 583e9d9c50..6f65eac360 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -24,6 +24,7 @@ * @since 0.11.0 This class now extends the WordPressCS native `Sniff` class. * @since 0.13.0 Class name changed: this class is now namespaced. * @since 1.0.0 This sniff has been moved from the `VIP` category to the `DB` category. + * @since 3.0.0 Support for the very sniff specific WPCS native ignore comment syntax has been removed. */ class DirectDatabaseQuerySniff extends Sniff { @@ -146,11 +147,6 @@ public function process_token( $stackPtr ) { } } - $whitelisted_db_call = false; - if ( preg_match( '/db call\W*(?:ok|pass|clear|whitelist)/i', $endOfLineComment ) ) { - $whitelisted_db_call = true; - } - // Check for Database Schema Changes. for ( $_pos = ( $stackPtr + 1 ); $_pos < $endOfStatement; $_pos++ ) { $_pos = $this->phpcsFile->findNext( Tokens::$textStringTokens, $_pos, $endOfStatement, false, null, true ); @@ -163,22 +159,15 @@ public function process_token( $stackPtr ) { } } - // Flag instance if not whitelisted. - if ( ! $whitelisted_db_call ) { - $this->phpcsFile->addWarning( 'Usage of a direct database call is discouraged.', $stackPtr, 'DirectQuery' ); - } + $this->phpcsFile->addWarning( 'Usage of a direct database call is discouraged.', $stackPtr, 'DirectQuery' ); if ( ! isset( $this->methods['cachable'][ $method ] ) ) { return $endOfStatement; } - $whitelisted_cache = false; - $cached = false; - $wp_cache_get = false; - if ( preg_match( '/cache\s+(?:ok|pass|clear|whitelist)/i', $endOfLineComment ) ) { - $whitelisted_cache = true; - } - if ( ! $whitelisted_cache && ! empty( $this->tokens[ $stackPtr ]['conditions'] ) ) { + $cached = false; + $wp_cache_get = false; + if ( ! empty( $this->tokens[ $stackPtr ]['conditions'] ) ) { $scope_function = $this->phpcsFile->getCondition( $stackPtr, \T_FUNCTION ); if ( false === $scope_function ) { @@ -214,7 +203,7 @@ public function process_token( $stackPtr ) { } } - if ( ! $cached && ! $whitelisted_cache ) { + if ( ! $cached ) { $message = 'Direct database call without caching detected. Consider using wp_cache_get() / wp_cache_set() or wp_cache_delete().'; $this->phpcsFile->addWarning( $message, $stackPtr, 'NoCaching' ); } diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc index 2f735dd7f5..88f1fba18d 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc @@ -2,19 +2,14 @@ function foo() { global $wpdb; - - $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Error + Warning. - - $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // DB call okay ( No Warning, but Error for not caching! ). - - return $listofthings; + return $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning x 2. } function bar() { global $wpdb; if ( ! ( $listofthings = wp_cache_get( $foo ) ) ) { - $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning. + $listofthings = $wpdb->get_col( 'SELECT something FROM somewhere WHERE someotherthing = 1' ); // Warning direct DB call. wp_cache_set( 'foo', $listofthings ); } @@ -28,33 +23,25 @@ function baz() { global $wpdb; $baz = wp_cache_get( 'baz' ); if ( false !== $baz ) { - - $wpdb->query( 'ALTER TABLE TO ADD SOME FIELDS' ); // DB call okay (but not really because ALTER TABLE!). - - $wpdb->query( $wpdb->prepare( 'CREATE TABLE ' ) ); // DB call okay (but not really because CREATE TABLE!). - - $wpdb->query( 'SELECT QUERY' ); // DB call okay. - - $baz = $wpdb->get_results( $wpdb->prepare( 'SELECT X FROM Y ' ) ); - + $wpdb->query( 'ALTER TABLE TO ADD SOME FIELDS' ); // Warning x 2. + $wpdb->query( $wpdb->prepare( 'CREATE TABLE ' ) ); // Warning x 2. + $wpdb->query( 'SELECT QUERY' ); // Warning. + $baz = $wpdb->get_results( $wpdb->prepare( 'SELECT X FROM Y ' ) ); // Warning. wp_cache_set( 'baz', $baz ); } - - } function quux() { global $wpdb; $quux = wp_cache_get( 'quux' ); if ( false !== $quux ) { - $quux = $wpdb->get_results( $wpdb->prepare( 'SELECT X FROM Y ' ) ); // Bad, no wp_cache_set, results in Error + Warning. + $quux = $wpdb->get_results( $wpdb->prepare( 'SELECT X FROM Y ' ) ); // Bad, no wp_cache_set, results in Warning x 2. } - } function barzd() { global $wpdb; - $autoload = $wpdb->get_var( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // DB call ok; no-cache ok. + $autoload = $wpdb->get_var( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // Warning x 2. } function taz() { @@ -70,35 +57,33 @@ function cache_delete_only() { $data = $where = array(); // These methods are allowed to be used with just wp_cache_delete(). - $wpdb->update( $wpdb->users, $data, $where ); // DB call ok; OK. - $wpdb->replace( $wpdb->users, $data, $where ); // DB call ok; OK. - $wpdb->delete( $wpdb->users, $data, $where ); // DB call ok; OK. - $wpdb->query( 'SELECT X FROM Y' ); // DB call ok; OK. + $wpdb->update( $wpdb->users, $data, $where ); // Warning direct DB call. + $wpdb->replace( $wpdb->users, $data, $where ); // Warning direct DB call. + $wpdb->delete( $wpdb->users, $data, $where ); // Warning direct DB call. + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. - $wpdb->get_results( 'SELECT X FROM Y' ); // DB call ok; Bad. - $wpdb->get_row( 'SELECT X FROM Y' ); // DB call ok; Bad. - $wpdb->get_col( 'SELECT X FROM Y' ); // DB call ok; Bad. + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning x 2. + $wpdb->get_row( 'SELECT X FROM Y' ); // Warning x 2. + $wpdb->get_col( 'SELECT X FROM Y' ); // Warning x 2. wp_cache_delete( 'key', 'group' ); } -// It is OK to use the wp_cache_add() function in place of wp_cache_set(). +// It is OK to use the wp_cache_add() function instead of wp_cache_set(). function cache_add_instead_of_set() { global $wpdb; $baz = wp_cache_get( 'baz' ); - if ( false !== $baz ) { - $data = $where = array(); - $wpdb->update( $wpdb->users, $data, $where ); // DB call ok; OK. - $wpdb->replace( $wpdb->users, $data, $where ); // DB call ok; OK. - $wpdb->delete( $wpdb->users, $data, $where ); // DB call ok; OK. - $wpdb->query( 'SELECT X FROM Y' ); // DB call ok; OK. - $wpdb->get_row( 'SELECT X FROM Y' ); // DB call ok; OK. - $wpdb->get_col( 'SELECT X FROM Y' ); // DB call ok; OK. - $baz = $wpdb->get_results( $wpdb->prepare( 'SELECT X FROM Y ' ) ); // DB call ok; OK. + $wpdb->update( $wpdb->users, $data, $where ); // Warning direct DB call. + $wpdb->replace( $wpdb->users, $data, $where ); // Warning direct DB call. + $wpdb->delete( $wpdb->users, $data, $where ); // Warning direct DB call. + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + $wpdb->get_row( 'SELECT X FROM Y' ); // Warning direct DB call. + $wpdb->get_col( 'SELECT X FROM Y' ); // Warning direct DB call. + $baz = $wpdb->get_results( $wpdb->prepare( 'SELECT X FROM Y ' ) ); // Warning direct DB call. wp_cache_add( 'baz', $baz ); } @@ -124,28 +109,25 @@ $b = function () { // phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] my_cachedel function cache_customA() { global $wpdb; - $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { - $wpdb->get_results( 'SELECT X FROM Y' ); // DB call ok; OK. + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. my_cacheset( 'key', 'group' ); } } function cache_customB() { global $wpdb; - $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { - $wpdb->get_results( 'SELECT X FROM Y' ); // DB call ok; OK. + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. my_other_cacheset( 'key', 'group' ); } } function cache_customC() { global $wpdb; - - $wpdb->query( 'SELECT X FROM Y' ); // DB call ok; OK. + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. my_cachedel( 'key', 'group' ); } @@ -154,28 +136,25 @@ function cache_customC() { function cache_customD() { global $wpdb; - $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { - $wpdb->get_results( 'SELECT X FROM Y' ); // DB call ok; OK. + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. my_cacheset( 'key', 'group' ); } } function cache_customE() { global $wpdb; - $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { - $wpdb->get_results( 'SELECT X FROM Y' ); // DB call ok; Bad. + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning x 2. my_other_cacheset( 'key', 'group' ); } } function cache_customF() { global $wpdb; - - $wpdb->query( 'SELECT X FROM Y' ); // DB call ok; Bad. + $wpdb->query( 'SELECT X FROM Y' ); // Warning x 2. my_cachedel( 'key', 'group' ); } @@ -184,62 +163,61 @@ function cache_customF() { function cache_customG() { global $wpdb; - $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { - $quux = $wpdb->get_results( 'SELECT X FROM Y' ); // DB call ok; Bad. + $quux = $wpdb->get_results( 'SELECT X FROM Y' ); // Warning x 2. my_cacheset( 'key', 'group' ); } } function custom_modify_attachment() { global $wpdb; - $wpdb->update( $wpdb->posts, array( 'post_title' => 'Hello' ), array( 'ID' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->posts, array( 'post_title' => 'Hello' ), array( 'ID' => 1 ) ); // Warning direct DB call. clean_attachment_cache( 1 ); } function custom_modify_post() { global $wpdb; - $wpdb->update( $wpdb->posts, array( 'post_title' => 'Hello' ), array( 'ID' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->posts, array( 'post_title' => 'Hello' ), array( 'ID' => 1 ) ); // Warning direct DB call. clean_post_cache( 1 ); } function custom_modify_term() { global $wpdb; - $wpdb->update( $wpdb->terms, array( 'slug' => 'test' ), array( 'term_id' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->terms, array( 'slug' => 'test' ), array( 'term_id' => 1 ) ); // Warning direct DB call. clean_term_cache( 1 ); } function custom_clean_category_cache() { global $wpdb; - $wpdb->update( $wpdb->terms, array( 'slug' => 'test' ), array( 'term_id' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->terms, array( 'slug' => 'test' ), array( 'term_id' => 1 ) ); // Warning direct DB call. clean_category_cache( 1 ); } function custom_modify_links() { global $wpdb; - $wpdb->update( $wpdb->links, array( 'link_name' => 'Test' ), array( 'link_id' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->links, array( 'link_name' => 'Test' ), array( 'link_id' => 1 ) ); // Warning direct DB call. clean_bookmark_cache( 1 ); } function custom_modify_comments() { global $wpdb; - $wpdb->update( $wpdb->comments, array( 'comment_content' => 'Test' ), array( 'comment_ID' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->comments, array( 'comment_content' => 'Test' ), array( 'comment_ID' => 1 ) ); // Warning direct DB call. clean_comment_cache( 1 ); } function custom_modify_users() { global $wpdb; - $wpdb->update( $wpdb->users, array( 'user_email' => 'Test' ), array( 'ID' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->users, array( 'user_email' => 'Test' ), array( 'ID' => 1 ) ); // Warning direct DB call. clean_user_cache( 1 ); } function custom_modify_blogs() { global $wpdb; - $wpdb->update( $wpdb->blogs, array( 'domain' => 'example.com' ), array( 'blog_id' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->blogs, array( 'domain' => 'example.com' ), array( 'blog_id' => 1 ) ); // Warning direct DB call. clean_blog_cache( 1 ); } function custom_modify_sites() { global $wpdb; - $wpdb->update( $wpdb->sites, array( 'domain' => 'example.com' ), array( 'id' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->sites, array( 'domain' => 'example.com' ), array( 'id' => 1 ) ); // Warning direct DB call. clean_network_cache( 1 ); } function custom_modify_term_relationship() { global $wpdb; - $wpdb->update( $wpdb->term_relationships, array( 'term_order' => 1 ), array( 'object_id' => 1 ) ); // DB call ok; OK. + $wpdb->update( $wpdb->term_relationships, array( 'term_order' => 1 ), array( 'object_id' => 1 ) ); // Warning direct DB call. clean_object_term_cache( 1 ); } @@ -252,14 +230,14 @@ function foofoo() { FROM somewhere WHERE someotherthing = 1 EOD - ); // Error + Warning. + ); // Warning x 2. $listofthings = $wpdb->get_col( <<query( <<<'EOD' ALTER TABLE TO ADD SOME FIELDS EOD - ); // DB call okay (but not really because ALTER TABLE!). + ); // Warning on line 273 + 274. wp_cache_set( 'baz', $baz ); } } @@ -282,20 +260,17 @@ function cache_add_instead_of_setter() { global $wpdb; $baz = wp_cache_get( 'baz' ); - if ( false !== $baz ) { - $data = $where = array(); - $wpdb->query( <<get_row( <<<'EOD' SELECT X FROM Y EOD - ); // DB call ok; OK. + );// Warning direct DB call. wp_cache_add( 'baz', $baz ); } -} \ No newline at end of file +} diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php index cf15554f92..02117429f3 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php @@ -38,23 +38,52 @@ public function getErrorList() { */ public function getWarningList() { return array( - 6 => 2, - 8 => 1, - 17 => 1, - 32 => 1, - 34 => 1, - 38 => 1, - 50 => 2, - 78 => 1, - 79 => 1, + 5 => 2, + 12 => 1, + 26 => 2, + 27 => 2, + 28 => 1, + 29 => 1, + 38 => 2, + 44 => 2, + 60 => 1, + 61 => 1, + 62 => 1, + 63 => 1, + 65 => 2, + 66 => 2, + 67 => 2, 80 => 1, - 112 => 1, - 170 => 1, - 178 => 1, + 81 => 1, + 82 => 1, + 83 => 1, + 84 => 1, + 85 => 1, + 86 => 1, + 97 => 1, + 114 => 1, + 123 => 1, + 130 => 1, + 141 => 1, + 150 => 2, + 157 => 2, + 168 => 2, + 175 => 1, + 180 => 1, + 185 => 1, 190 => 1, - 250 => 2, - 257 => 1, - 274 => 1, + 195 => 1, + 200 => 1, + 205 => 1, + 210 => 1, + 215 => 1, + 220 => 1, + 228 => 2, + 235 => 2, + 251 => 1, + 252 => 1, + 265 => 1, + 269 => 1, ); } From 117b5e9a4570761635bd7d04fb2e55591d43f864 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 18 Jun 2022 12:43:35 +0200 Subject: [PATCH 139/822] DB/DirectDatabaseQuery: minor improvement error message text --- WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index 6f65eac360..9cfeea2d09 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -159,7 +159,7 @@ public function process_token( $stackPtr ) { } } - $this->phpcsFile->addWarning( 'Usage of a direct database call is discouraged.', $stackPtr, 'DirectQuery' ); + $this->phpcsFile->addWarning( 'Use of a direct database call is discouraged.', $stackPtr, 'DirectQuery' ); if ( ! isset( $this->methods['cachable'][ $method ] ) ) { return $endOfStatement; From b2677739b483758688901a26990872a982463966 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 17:20:54 +0200 Subject: [PATCH 140/822] AbstractFunctionRestrictionsSniff: rename array key ... and update sniffs using that array key. --- WordPress/AbstractFunctionRestrictionsSniff.php | 8 ++++---- WordPress/Sniffs/DB/RestrictedFunctionsSniff.php | 2 +- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress/AbstractFunctionRestrictionsSniff.php b/WordPress/AbstractFunctionRestrictionsSniff.php index 53ea9a255e..af8cd10b18 100644 --- a/WordPress/AbstractFunctionRestrictionsSniff.php +++ b/WordPress/AbstractFunctionRestrictionsSniff.php @@ -97,14 +97,14 @@ abstract class AbstractFunctionRestrictionsSniff extends Sniff { * 'message' => 'Use anonymous functions instead please!', * 'functions' => array( 'file_get_contents', 'create_function', 'mysql_*' ), * // Only useful when using wildcards: - * 'whitelist' => array( 'mysql_to_rfc3339' => true, ), + * 'allow' => array( 'mysql_to_rfc3339' => true, ), * ) * ) * * You can use * wildcards to target a group of functions. * When you use * wildcards, you may inadvertently restrict too many - * functions. In that case you can add the `whitelist` key to - * whitelist individual functions to prevent false positives. + * functions. In that case you can add the `allow` key to + * safe list individual functions to prevent false positives. * * @return array */ @@ -280,7 +280,7 @@ public function check_for_matches( $stackPtr ) { continue; } - if ( isset( $group['whitelist'][ $token_content ] ) ) { + if ( isset( $group['allow'][ $token_content ] ) ) { continue; } diff --git a/WordPress/Sniffs/DB/RestrictedFunctionsSniff.php b/WordPress/Sniffs/DB/RestrictedFunctionsSniff.php index dbab49fec9..83d3d92ce6 100644 --- a/WordPress/Sniffs/DB/RestrictedFunctionsSniff.php +++ b/WordPress/Sniffs/DB/RestrictedFunctionsSniff.php @@ -56,7 +56,7 @@ public function getGroups() { 'mysqlnd_memcache_*', 'maxdb_*', ), - 'whitelist' => array( + 'allow' => array( 'mysql_to_rfc3339' => true, ), ), diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index 99f66b8cb0..9a0e17b0d6 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -94,7 +94,7 @@ public function getGroups() { 'functions' => array( 'curl_*', ), - 'whitelist' => array( + 'allow' => array( 'curl_version' => true, ), ), From 63805313685666efa6e57cad89969be2535f6690 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 14:14:33 +0200 Subject: [PATCH 141/822] PrefixAllGlobals: rename property [1] As this is a `protected` property, this is an internal change only (unless an external standard would be extending the sniff). --- WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index d2817ede48..b6091444ff 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -135,10 +135,11 @@ class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { * A list of core hooks that are allowed to be called by plugins and themes. * * @since 0.14.0 + * @since 3.0.0 Renamed from `$whitelisted_core_hooks` to `$allowed_core_hooks`. * * @var array */ - protected $whitelisted_core_hooks = array( + protected $allowed_core_hooks = array( 'widget_title' => true, 'add_meta_boxes' => true, ); @@ -806,7 +807,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $raw_content = TextStrings::stripQuotes( $parameters[1]['raw'] ); if ( ( 'define' !== $matched_content - && isset( $this->whitelisted_core_hooks[ $raw_content ] ) ) + && isset( $this->allowed_core_hooks[ $raw_content ] ) ) || ( 'define' === $matched_content && isset( $this->whitelisted_core_constants[ $raw_content ] ) ) ) { From bd7e1c9ff9546a62098dfc5005f583add9b8c72a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 14:15:28 +0200 Subject: [PATCH 142/822] PrefixAllGlobals: rename property [2] As this is a `protected` property, this is an internal change only (unless an external standard would be extending the sniff). --- .../Sniffs/NamingConventions/PrefixAllGlobalsSniff.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index b6091444ff..6437542311 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -148,6 +148,7 @@ class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { * A list of core constants that are allowed to be defined by plugins and themes. * * @since 1.0.0 + * @since 3.0.0 Renamed from `$whitelisted_core_constants` to `$allowed_core_constants`. * * Source: {@link https://core.trac.wordpress.org/browser/trunk/src/wp-includes/default-constants.php#L0} * The constants are listed in the order they are found in the source file @@ -157,7 +158,7 @@ class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { * * @var array */ - protected $whitelisted_core_constants = array( + protected $allowed_core_constants = array( 'WP_MEMORY_LIMIT' => true, 'WP_MAX_MEMORY_LIMIT' => true, 'WP_CONTENT_DIR' => true, @@ -468,7 +469,7 @@ public function process_token( $stackPtr ) { return; } - if ( isset( $this->whitelisted_core_constants[ $item_name ] ) ) { + if ( isset( $this->allowed_core_constants[ $item_name ] ) ) { // Defining a WP Core constant intended for overruling. return; } @@ -809,7 +810,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p if ( ( 'define' !== $matched_content && isset( $this->allowed_core_hooks[ $raw_content ] ) ) || ( 'define' === $matched_content - && isset( $this->whitelisted_core_constants[ $raw_content ] ) ) + && isset( $this->allowed_core_constants[ $raw_content ] ) ) ) { return; } From b6b15ee668f751cf893512d47d94098ac724dd1f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 17:33:08 +0200 Subject: [PATCH 143/822] PrefixAllGlobals: rename property [3] As this is a `protected` property, this is an internal change only (unless an external standard would be extending the sniff). --- .../Sniffs/NamingConventions/PrefixAllGlobalsSniff.php | 9 +++++---- .../NamingConventions/PrefixAllGlobalsUnitTest.1.inc | 2 +- .../Tests/NamingConventions/PrefixAllGlobalsUnitTest.php | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index 6437542311..c9b7c4f272 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -64,13 +64,14 @@ class PrefixAllGlobalsSniff extends AbstractFunctionParameterSniff { public $prefixes = ''; /** - * Prefix blacklist. + * Prefix blocklist. * * @since 0.12.0 + * @since 3.0.0 Renamed from `$prefix_blacklist` to `$prefix_blocklist`. * * @var string[] */ - protected $prefix_blacklist = array( + protected $prefix_blocklist = array( 'wordpress' => true, 'wp' => true, '_' => true, @@ -949,7 +950,7 @@ private function variable_prefixed_or_whitelisted( $stackPtr, $name ) { * Validate an array of prefixes as passed through a custom property or via the command line. * * Checks that the prefix: - * - is not one of the blacklisted ones. + * - is not one of the blocked ones. * - complies with the PHP rules for valid function, class, variable, constant names. * * @since 0.12.0 @@ -968,7 +969,7 @@ private function validate_prefixes() { foreach ( $this->prefixes as $key => $prefix ) { $prefixLC = strtolower( $prefix ); - if ( isset( $this->prefix_blacklist[ $prefixLC ] ) ) { + if ( isset( $this->prefix_blocklist[ $prefixLC ] ) ) { $this->phpcsFile->addError( 'The "%s" prefix is not allowed.', 0, diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index 2c1242788e..8c9c3e2e2b 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -399,7 +399,7 @@ class Some_Test_Class extends NonTestClass { // Bad. } // phpcs:set WordPress.NamingConventions.PrefixAllGlobals prefixes[] wordpress,somethingelse -// The above line adds an issue to line 1 about a blacklisted prefix. +// The above line adds an issue to line 1 about a blocked prefix. function wordpress_do_something() {} // Bad. function somethingelse_do_something() {} // OK. diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php index b6ace2e4e0..c2008776b3 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php @@ -32,7 +32,7 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) { switch ( $testFile ) { case 'PrefixAllGlobalsUnitTest.1.inc': return array( - 1 => 8, // 2 x error for blacklisted prefix passed. 4 x error for short prefixes. 2 x no prefix. + 1 => 8, // 2 x error for blocked prefix passed. 4 x error for short prefixes. 2 x no prefix. 10 => 1, 18 => 1, 21 => 1, @@ -86,7 +86,7 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) { case 'PrefixAllGlobalsUnitTest.4.inc': return array( - 1 => 1, // 1 x error for blacklisted prefix passed. + 1 => 1, // 1 x error for blocked prefix passed. 18 => 1, ); From d76cf025cbc840ed7fb610b7cb0672dcf5acf8d9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 14:17:13 +0200 Subject: [PATCH 144/822] PrefixAllGlobals: rename (private) method --- .../NamingConventions/PrefixAllGlobalsSniff.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index c9b7c4f272..616f89a723 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -637,7 +637,7 @@ protected function process_variable_assignment( $stackPtr, $in_list = false ) { $variable_name = substr( $this->tokens[ $stackPtr ]['content'], 1 ); // Strip the dollar sign. // Bow out early if we know for certain no prefix is needed. - if ( $this->variable_prefixed_or_whitelisted( $stackPtr, $variable_name ) === true ) { + if ( $this->variable_prefixed_or_allowed( $stackPtr, $variable_name ) === true ) { return; } @@ -659,7 +659,7 @@ protected function process_variable_assignment( $stackPtr, $in_list = false ) { // Check whether a prefix is needed. if ( isset( Tokens::$stringTokens[ $this->tokens[ $array_key ]['code'] ] ) - && $this->variable_prefixed_or_whitelisted( $stackPtr, $variable_name ) === true + && $this->variable_prefixed_or_allowed( $stackPtr, $variable_name ) === true ) { return; } @@ -670,7 +670,7 @@ protected function process_variable_assignment( $stackPtr, $in_list = false ) { $exploded = explode( '$', $variable_name ); $first = rtrim( $exploded[0], '{' ); if ( '' !== $first ) { - if ( $this->variable_prefixed_or_whitelisted( $array_key, $first ) === true ) { + if ( $this->variable_prefixed_or_allowed( $array_key, $first ) === true ) { return; } } else { @@ -930,14 +930,15 @@ private function is_prefixed( $stackPtr, $name ) { * * @since 0.12.0 * @since 1.0.1 Added $stackPtr parameter. + * @since 3.0.0 Renamed from `variable_prefixed_or_whitelisted()` to `variable_prefixed_or_allowed()`. * * @param int $stackPtr The position of the token to record the metric against. * @param string $name Variable name without the dollar sign. * - * @return bool True if the variable name is whitelisted or already prefixed. + * @return bool True if the variable name is allowed or already prefixed. * False otherwise. */ - private function variable_prefixed_or_whitelisted( $stackPtr, $name ) { + private function variable_prefixed_or_allowed( $stackPtr, $name ) { // Ignore superglobals and WP global variables. if ( isset( $this->superglobals[ $name ] ) || isset( $this->wp_globals[ $name ] ) ) { return true; From 6c058ea19bbf5fb6fc2d231b65c9d0a631f49516 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 14:18:10 +0200 Subject: [PATCH 145/822] ValidPostTypeSlug: rename constant --- .../Sniffs/NamingConventions/ValidPostTypeSlugSniff.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php index 673557efae..0d76b5c74b 100644 --- a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php @@ -38,14 +38,15 @@ class ValidPostTypeSlugSniff extends AbstractFunctionParameterSniff { const POST_TYPE_MAX_LENGTH = 20; /** - * Regex that whitelists characters that can be used as the post type slug. + * Regex to validate the characters that can be used as the post type slug. * * @link https://developer.wordpress.org/reference/functions/register_post_type/ * @since 2.2.0 + * @since 3.0.0 Renamed from `POST_TYPE_CHARACTER_WHITELIST` to `VALID_POST_TYPE_CHARACTERS`. * * @var string */ - const POST_TYPE_CHARACTER_WHITELIST = '/^[a-z0-9_-]+$/'; + const VALID_POST_TYPE_CHARACTERS = '/^[a-z0-9_-]+$/'; /** * Array of functions that must be checked. @@ -165,7 +166,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $post_type = TextStringHelper::strip_interpolated_variables( $post_type ); } - if ( preg_match( self::POST_TYPE_CHARACTER_WHITELIST, $post_type ) === 0 ) { + if ( preg_match( self::VALID_POST_TYPE_CHARACTERS, $post_type ) === 0 ) { // Error for invalid characters. $this->phpcsFile->addError( 'register_post_type() called with invalid post type %s. Post type contains invalid characters. Only lowercase alphanumeric characters, dashes, and underscores are allowed.', From f1469af23acca4899a9a55fd9ce25c54101c3346 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 14:18:38 +0200 Subject: [PATCH 146/822] ValidVariableName: rename property [1] As this is a `protected` property, this is an internal change only (unless an external standard would be extending the sniff). --- .../NamingConventions/ValidVariableNameSniff.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php index 34314ff186..2832e37c85 100644 --- a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -59,10 +59,11 @@ class ValidVariableNameSniff extends PHPCS_AbstractVariableSniff { * * @since 0.9.0 * @since 0.11.0 Changed from public to protected. + * @since 3.0.0 Renamed from `$whitelisted_mixed_case_member_var_names` to `$allowed_mixed_case_member_var_names`. * * @var array */ - protected $whitelisted_mixed_case_member_var_names = array( + protected $allowed_mixed_case_member_var_names = array( 'ID' => true, 'comment_ID' => true, 'comment_post_ID' => true, @@ -139,7 +140,7 @@ protected function processVariable( File $phpcs_file, $stack_ptr ) { $obj_var_name = substr( $obj_var_name, 1 ); } - if ( ! isset( $this->whitelisted_mixed_case_member_var_names[ $obj_var_name ] ) && self::isSnakeCase( $obj_var_name ) === false ) { + if ( ! isset( $this->allowed_mixed_case_member_var_names[ $obj_var_name ] ) && self::isSnakeCase( $obj_var_name ) === false ) { $error = 'Object property "$%s" is not in valid snake_case format, try "$%s"'; $data = array( $original_var_name, @@ -168,7 +169,7 @@ protected function processVariable( File $phpcs_file, $stack_ptr ) { } if ( self::isSnakeCase( $var_name ) === false ) { - if ( $in_class && ! isset( $this->whitelisted_mixed_case_member_var_names[ $var_name ] ) ) { + if ( $in_class && ! isset( $this->allowed_mixed_case_member_var_names[ $var_name ] ) ) { $error = 'Object property "$%s" is not in valid snake_case format, try "$%s"'; $error_name = 'UsedPropertyNotSnakeCase'; } elseif ( ! $in_class ) { @@ -212,7 +213,7 @@ protected function processMemberVar( File $phpcs_file, $stack_ptr ) { // Merge any custom variables with the defaults. $this->mergeWhiteList(); - if ( ! isset( $this->whitelisted_mixed_case_member_var_names[ $var_name ] ) && false === self::isSnakeCase( $var_name ) ) { + if ( ! isset( $this->allowed_mixed_case_member_var_names[ $var_name ] ) && false === self::isSnakeCase( $var_name ) ) { $error = 'Member variable "$%s" is not in valid snake_case format, try "$%s"'; $data = array( $var_name, @@ -287,9 +288,9 @@ protected function mergeWhiteList() { // Fix property potentially passed as comma-delimited string. $customProperties = Sniff::merge_custom_array( $this->customPropertiesWhitelist, array(), false ); - $this->whitelisted_mixed_case_member_var_names = Sniff::merge_custom_array( + $this->allowed_mixed_case_member_var_names = Sniff::merge_custom_array( $customProperties, - $this->whitelisted_mixed_case_member_var_names + $this->allowed_mixed_case_member_var_names ); $this->addedCustomProperties['properties'] = $this->customPropertiesWhitelist; From cc9eb4c0e07c427109a0237786ac01821826cc02 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 14:36:05 +0200 Subject: [PATCH 147/822] ValidVariableName: rename property [2] As this is a `public` property, this is a BC-break and should be annotated as such in the upgrade guide/changelog. --- .../NamingConventions/ValidVariableNameSniff.php | 9 +++++---- .../NamingConventions/ValidVariableNameUnitTest.inc | 12 ++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php index 2832e37c85..0b94fa3285 100644 --- a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -76,10 +76,11 @@ class ValidVariableNameSniff extends PHPCS_AbstractVariableSniff { * Custom list of properties which can have mixed case. * * @since 0.11.0 + * @since 3.0.0 Renamed from `$customPropertiesWhitelist` to `$allowed_custom_properties`. * * @var string|string[] */ - public $customPropertiesWhitelist = array(); + public $allowed_custom_properties = array(); /** * Cache of previously added custom functions. @@ -284,16 +285,16 @@ public static function isSnakeCase( $var_name ) { * @return void */ protected function mergeWhiteList() { - if ( $this->customPropertiesWhitelist !== $this->addedCustomProperties['properties'] ) { + if ( $this->allowed_custom_properties !== $this->addedCustomProperties['properties'] ) { // Fix property potentially passed as comma-delimited string. - $customProperties = Sniff::merge_custom_array( $this->customPropertiesWhitelist, array(), false ); + $customProperties = Sniff::merge_custom_array( $this->allowed_custom_properties, array(), false ); $this->allowed_mixed_case_member_var_names = Sniff::merge_custom_array( $customProperties, $this->allowed_mixed_case_member_var_names ); - $this->addedCustomProperties['properties'] = $this->customPropertiesWhitelist; + $this->addedCustomProperties['properties'] = $this->allowed_custom_properties; } } diff --git a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc index 0186491d75..16221b7dd8 100644 --- a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc +++ b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc @@ -129,13 +129,13 @@ echo "This is $PHP_SELF with $HTTP_RAW_POST_DATA"; // Ok. /* * Unit test whitelisting. */ -// phpcs:set WordPress.NamingConventions.ValidVariableName customPropertiesWhitelist[] varName,DOMProperty -echo MyClass::$varName; // Ok, whitelisted. -echo $this->DOMProperty; // Ok, whitelisted. -echo $object->varName; // Ok, whitelisted. -// phpcs:set WordPress.NamingConventions.ValidVariableName customPropertiesWhitelist[] +// phpcs:set WordPress.NamingConventions.ValidVariableName allowed_custom_properties[] varName,DOMProperty +echo MyClass::$varName; // Ok, allowed. +echo $this->DOMProperty; // Ok, allowed. +echo $object->varName; // Ok, allowed. +// phpcs:set WordPress.NamingConventions.ValidVariableName allowed_custom_properties[] -echo $object->varName; // Bad, no longer whitelisted. +echo $object->varName; // Bad, no longer allowed. // Code style independent token checking. echo $object From 80995e988c19338ff648b57f3a8a6ef41ffb33d3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 14:42:09 +0200 Subject: [PATCH 148/822] ValidVariableNameSniff: rename method --- .../NamingConventions/ValidVariableNameSniff.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php index 0b94fa3285..91aeec617c 100644 --- a/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -117,7 +117,7 @@ protected function processVariable( File $phpcs_file, $stack_ptr ) { } // Merge any custom variables with the defaults. - $this->mergeWhiteList(); + $this->merge_allow_lists(); // Likewise if it is a mixed-case var used by WordPress core. if ( isset( $this->wordpress_mixed_case_vars[ $var_name ] ) ) { @@ -212,7 +212,7 @@ protected function processMemberVar( File $phpcs_file, $stack_ptr ) { } // Merge any custom variables with the defaults. - $this->mergeWhiteList(); + $this->merge_allow_lists(); if ( ! isset( $this->allowed_mixed_case_member_var_names[ $var_name ] ) && false === self::isSnakeCase( $var_name ) ) { $error = 'Member variable "$%s" is not in valid snake_case format, try "$%s"'; @@ -240,7 +240,7 @@ protected function processVariableInString( File $phpcs_file, $stack_ptr ) { if ( preg_match_all( '|[^\\\]\${?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[ $stack_ptr ]['content'], $matches ) > 0 ) { // Merge any custom variables with the defaults. - $this->mergeWhiteList(); + $this->merge_allow_lists(); foreach ( $matches[1] as $var_name ) { // If it's a php reserved var, then its ok. @@ -276,15 +276,16 @@ public static function isSnakeCase( $var_name ) { } /** - * Merge a custom whitelist provided via a custom ruleset with the predefined whitelist, + * Merge a custom allow list provided via a custom ruleset with the predefined allow list, * if we haven't already. * * @since 0.10.0 * @since 2.0.0 Removed unused $phpcs_file parameter. + * @since 3.0.0 Renamed from `mergeWhiteList()` to `merge_allow_lists()`. * * @return void */ - protected function mergeWhiteList() { + protected function merge_allow_lists() { if ( $this->allowed_custom_properties !== $this->addedCustomProperties['properties'] ) { // Fix property potentially passed as comma-delimited string. $customProperties = Sniff::merge_custom_array( $this->allowed_custom_properties, array(), false ); From 45f543bdd01a4fe76d544c297f34b2832d3597a4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 16:25:51 +0200 Subject: [PATCH 149/822] IniSet: rename property [1] As this is a `protected` property, this is an internal change only (unless an external standard would be extending the sniff). --- WordPress/Sniffs/PHP/IniSetSniff.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/WordPress/Sniffs/PHP/IniSetSniff.php b/WordPress/Sniffs/PHP/IniSetSniff.php index e69f7cfde7..aacc5d97e1 100644 --- a/WordPress/Sniffs/PHP/IniSetSniff.php +++ b/WordPress/Sniffs/PHP/IniSetSniff.php @@ -15,7 +15,7 @@ /** * Detect use of the `ini_set()` function. * - * - Won't throw notices for "safe" ini directives as listed in the whitelist. + * - Won't throw notices for "safe" ini directives as listed in the safe-list. * - Throws errors for ini directives listed in the blacklist. * - A warning will be thrown in all other cases. * @@ -44,15 +44,16 @@ class IniSetSniff extends AbstractFunctionParameterSniff { * Array of PHP configuration options that are allowed to be manipulated. * * @since 2.1.0 + * @since 3.0.0 Renamed from `$whitelisted_options` to `$safe_options`. * * @var array Multidimensional array with parameter details. - * $whitelisted_options = array( + * $safe_options = array( * (string) option name. = array( * (string[]) 'valid_values' = array() * ) * ); */ - protected $whitelisted_options = array( + protected $safe_options = array( 'auto_detect_line_endings' => array(), 'highlight.bg' => array(), 'highlight.comment' => array(), @@ -125,7 +126,7 @@ class IniSetSniff extends AbstractFunctionParameterSniff { * Process the parameter of a matched function. * * Errors if an option is found in the blacklist. Warns as - * 'risky' when the option is not found in the whitelist. + * 'risky' when the option is not found in the safe-list. * * @since 2.1.0 * @@ -139,8 +140,8 @@ class IniSetSniff extends AbstractFunctionParameterSniff { public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { $option_name = TextStrings::stripQuotes( $parameters[1]['raw'] ); $option_value = TextStrings::stripQuotes( $parameters[2]['raw'] ); - if ( isset( $this->whitelisted_options[ $option_name ] ) ) { - $whitelisted_option = $this->whitelisted_options[ $option_name ]; + if ( isset( $this->safe_options[ $option_name ] ) ) { + $whitelisted_option = $this->safe_options[ $option_name ]; if ( ! isset( $whitelisted_option['valid_values'] ) || in_array( strtolower( $option_value ), $whitelisted_option['valid_values'], true ) ) { return; } From 0f47dbe9c5615530bdaddf88e5d3c2cb2445a1b9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 16:27:31 +0200 Subject: [PATCH 150/822] IniSet: rename property [2] As this is a `protected` property, this is an internal change only (unless an external standard would be extending the sniff). --- WordPress/Sniffs/PHP/IniSetSniff.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/WordPress/Sniffs/PHP/IniSetSniff.php b/WordPress/Sniffs/PHP/IniSetSniff.php index aacc5d97e1..a0580af5bd 100644 --- a/WordPress/Sniffs/PHP/IniSetSniff.php +++ b/WordPress/Sniffs/PHP/IniSetSniff.php @@ -16,7 +16,7 @@ * Detect use of the `ini_set()` function. * * - Won't throw notices for "safe" ini directives as listed in the safe-list. - * - Throws errors for ini directives listed in the blacklist. + * - Throws errors for ini directives listed in the disallow-list. * - A warning will be thrown in all other cases. * * @package WPCS\WordPressCodingStandards @@ -70,16 +70,17 @@ class IniSetSniff extends AbstractFunctionParameterSniff { * Array of PHP configuration options that are not allowed to be manipulated. * * @since 2.1.0 + * @since 3.0.0 Renamed from `$blacklisted_options` to `$disallowed_options`. * * @var array Multidimensional array with parameter details. - * $blacklisted_options = array( + * $disallowed_options = array( * (string) option name. = array( * (string[]) 'invalid_values' = array() * (string) 'message' * ) * ); */ - protected $blacklisted_options = array( + protected $disallowed_options = array( 'bcmath.scale' => array( 'message' => 'Use `bcscale()` instead.', ), @@ -125,7 +126,7 @@ class IniSetSniff extends AbstractFunctionParameterSniff { /** * Process the parameter of a matched function. * - * Errors if an option is found in the blacklist. Warns as + * Errors if an option is found in the disallow-list. Warns as * 'risky' when the option is not found in the safe-list. * * @since 2.1.0 @@ -147,8 +148,8 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p } } - if ( isset( $this->blacklisted_options[ $option_name ] ) ) { - $blacklisted_option = $this->blacklisted_options[ $option_name ]; + if ( isset( $this->disallowed_options[ $option_name ] ) ) { + $blacklisted_option = $this->disallowed_options[ $option_name ]; if ( ! isset( $blacklisted_option['invalid_values'] ) || in_array( strtolower( $option_value ), $blacklisted_option['invalid_values'], true ) ) { $this->phpcsFile->addError( '%s(%s, %s) found. %s', From 250f665369c4470ffdc25cfea19cff67606245a2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 16:31:21 +0200 Subject: [PATCH 151/822] IniSet: rename local variable [1] --- WordPress/Sniffs/PHP/IniSetSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/PHP/IniSetSniff.php b/WordPress/Sniffs/PHP/IniSetSniff.php index a0580af5bd..7d11bc01a4 100644 --- a/WordPress/Sniffs/PHP/IniSetSniff.php +++ b/WordPress/Sniffs/PHP/IniSetSniff.php @@ -142,8 +142,8 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $option_name = TextStrings::stripQuotes( $parameters[1]['raw'] ); $option_value = TextStrings::stripQuotes( $parameters[2]['raw'] ); if ( isset( $this->safe_options[ $option_name ] ) ) { - $whitelisted_option = $this->safe_options[ $option_name ]; - if ( ! isset( $whitelisted_option['valid_values'] ) || in_array( strtolower( $option_value ), $whitelisted_option['valid_values'], true ) ) { + $safe_option = $this->safe_options[ $option_name ]; + if ( ! isset( $safe_option['valid_values'] ) || in_array( strtolower( $option_value ), $safe_option['valid_values'], true ) ) { return; } } From 56b97fae0574cc8c2289ac92a788d43aeb06c78d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 16:35:13 +0200 Subject: [PATCH 152/822] IniSet: rename local variable [2] --- WordPress/Sniffs/PHP/IniSetSniff.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/PHP/IniSetSniff.php b/WordPress/Sniffs/PHP/IniSetSniff.php index 7d11bc01a4..b321953808 100644 --- a/WordPress/Sniffs/PHP/IniSetSniff.php +++ b/WordPress/Sniffs/PHP/IniSetSniff.php @@ -149,8 +149,8 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p } if ( isset( $this->disallowed_options[ $option_name ] ) ) { - $blacklisted_option = $this->disallowed_options[ $option_name ]; - if ( ! isset( $blacklisted_option['invalid_values'] ) || in_array( strtolower( $option_value ), $blacklisted_option['invalid_values'], true ) ) { + $disallowed_option = $this->disallowed_options[ $option_name ]; + if ( ! isset( $disallowed_option['invalid_values'] ) || in_array( strtolower( $option_value ), $disallowed_option['invalid_values'], true ) ) { $this->phpcsFile->addError( '%s(%s, %s) found. %s', $stackPtr, @@ -159,7 +159,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $matched_content, $parameters[1]['raw'], $parameters[2]['raw'], - $blacklisted_option['message'], + $disallowed_option['message'], ) ); return; From ce4c6a681c33889b4fe9df86ba6f04184870d34f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 17:30:20 +0200 Subject: [PATCH 153/822] IniSet: rename error code --- WordPress/Sniffs/PHP/IniSetSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/PHP/IniSetSniff.php b/WordPress/Sniffs/PHP/IniSetSniff.php index b321953808..08ab6a7bf8 100644 --- a/WordPress/Sniffs/PHP/IniSetSniff.php +++ b/WordPress/Sniffs/PHP/IniSetSniff.php @@ -154,7 +154,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $this->phpcsFile->addError( '%s(%s, %s) found. %s', $stackPtr, - $this->string_to_errorcode( $option_name . '_Blacklisted' ), + $this->string_to_errorcode( $option_name . '_Disallowed' ), array( $matched_content, $parameters[1]['raw'], From be76478f0d283e6349e2cbde737c9d29e8d044e6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 21 Jun 2022 07:33:05 +0200 Subject: [PATCH 154/822] IniSet: update the documentation for two properties --- WordPress/Sniffs/PHP/IniSetSniff.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/PHP/IniSetSniff.php b/WordPress/Sniffs/PHP/IniSetSniff.php index 08ab6a7bf8..62ff297460 100644 --- a/WordPress/Sniffs/PHP/IniSetSniff.php +++ b/WordPress/Sniffs/PHP/IniSetSniff.php @@ -41,7 +41,8 @@ class IniSetSniff extends AbstractFunctionParameterSniff { ); /** - * Array of PHP configuration options that are allowed to be manipulated. + * Array of PHP configuration options that are safe to be manipulated, as changing + * the value of these, won't cause interoperability issues between WP/plugins/themes. * * @since 2.1.0 * @since 3.0.0 Renamed from `$whitelisted_options` to `$safe_options`. @@ -67,7 +68,8 @@ class IniSetSniff extends AbstractFunctionParameterSniff { ); /** - * Array of PHP configuration options that are not allowed to be manipulated. + * Array of PHP configuration options that are not allowed to be manipulated, as changing + * the value of these, will be problematic for interoperability between WP/plugins/themes. * * @since 2.1.0 * @since 3.0.0 Renamed from `$blacklisted_options` to `$disallowed_options`. From ba985a059b5d65743fd9eb4904ec1de617edd032 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 16:50:07 +0200 Subject: [PATCH 155/822] NoSilencedErrors: rename property [1] As this is a `public` property, this is a BC-break and should be annotated as such in the upgrade guide/changelog. Also note that the new name is in line with the name for the same property in an upcoming replacement sniff in PHPCSExtra. This should make the switch over to the replacement sniff more straight-forward (if and when). --- WordPress-Extra/ruleset.xml | 4 ++-- WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php | 9 +++++---- WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index c493f65e29..3c33ad3111 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -147,11 +147,11 @@ https://github.com/WordPress/WordPress-Coding-Standards/issues/1371 --> - - + diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index 95dd4132a8..f41f64dad5 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -16,7 +16,7 @@ * Discourage the use of the PHP error silencing operator. * * This sniff allows the error operator to be used with a select list - * of whitelisted functions, as no amount of error checking can prevent + * of functions, as no amount of error checking can prevent * PHP from throwing errors when those functions are used. * * @package WPCS\WordPressCodingStandards @@ -40,14 +40,15 @@ class NoSilencedErrorsSniff extends Sniff { * * Defaults to true. * - * This property only affects whether the standard function whitelist is + * This property only affects whether the standard function list is * used. The custom whitelist, if set, will always be respected. * * @since 1.1.0 + * @since 3.0.0 Renamed from `$use_default_whitelist` to `$usePHPFunctionsList`. * * @var bool */ - public $use_default_whitelist = true; + public $usePHPFunctionsList = true; /** * User defined whitelist. @@ -194,7 +195,7 @@ public function process_token( $stackPtr ) { $has_parenthesis = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next_non_empty + 1 ), null, true, null, true ); if ( false !== $has_parenthesis && \T_OPEN_PARENTHESIS === $this->tokens[ $has_parenthesis ]['code'] ) { $function_name = strtolower( $this->tokens[ $next_non_empty ]['content'] ); - if ( ( true === $this->use_default_whitelist + if ( ( true === $this->usePHPFunctionsList && isset( $this->function_whitelist[ $function_name ] ) === true ) || ( ! empty( $this->custom_whitelist ) && in_array( $function_name, $this->custom_whitelist, true ) === true ) diff --git a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc index 3e52794bc9..01a2be9cb6 100644 --- a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc +++ b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc @@ -52,7 +52,7 @@ $unserialized = @unserialize( $str ); /* * ... and test the same principle again, but now without using the whitelist. */ -// phpcs:set WordPress.PHP.NoSilencedErrors use_default_whitelist false +// phpcs:set WordPress.PHP.NoSilencedErrors usePHPFunctionsList false // File extension. if ( @&file_exists( $filename ) && @ /*comment*/ is_readable( $filename ) ) { // Bad x2. @@ -71,7 +71,7 @@ if (@is_dir($dir)) { // Bad. $files1 = @ & scandir($dir); // Bad. /* - * Custom whitelist will be respected even when `use_default_whitelist` is set to false. + * Custom whitelist will be respected even when `usePHPFunctionsList` is set to false. */ // phpcs:set WordPress.PHP.NoSilencedErrors custom_whitelist[] fgetcsv,hex2bin while ( ( $csvdata = @fgetcsv( $handle, 2000, $separator ) ) !== false ) {} @@ -79,4 +79,4 @@ echo @some_userland_function( $param ); // Bad. $decoded = @hex2bin( $data ); // phpcs:set WordPress.PHP.NoSilencedErrors custom_whitelist[] -// phpcs:set WordPress.PHP.NoSilencedErrors use_default_whitelist true +// phpcs:set WordPress.PHP.NoSilencedErrors usePHPFunctionsList true From b7928b7a2748f70289cd9b53d9be74bd296bb705 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 16:54:24 +0200 Subject: [PATCH 156/822] NoSilencedErrors: rename property [2] As this is a `public` property, this is a BC-break and should be annotated as such in the upgrade guide/changelog. Also note that the new name is in line with the name for the same property in an upcoming replacement sniff in PHPCSExtra. This should make the switch over to the replacement sniff more straight-forward (if and when). --- .../Sniffs/PHP/NoSilencedErrorsSniff.php | 23 ++++++++++--------- .../Tests/PHP/NoSilencedErrorsUnitTest.inc | 10 ++++---- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index f41f64dad5..026a8fb94e 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -40,8 +40,8 @@ class NoSilencedErrorsSniff extends Sniff { * * Defaults to true. * - * This property only affects whether the standard function list is - * used. The custom whitelist, if set, will always be respected. + * This property only affects whether the standard function list is used. + * The custom allowed functions list, if set, will always be respected. * * @since 1.1.0 * @since 3.0.0 Renamed from `$use_default_whitelist` to `$usePHPFunctionsList`. @@ -51,16 +51,17 @@ class NoSilencedErrorsSniff extends Sniff { public $usePHPFunctionsList = true; /** - * User defined whitelist. + * User defined function list. * - * Allows users to pass a list of additional functions to whitelist - * from their custom ruleset. + * Allows users to pass a list of additional functions for which to allow + * the use of the silence operator. This list can be set in a custom ruleset. * * @since 1.1.0 + * @since 3.0.0 Renamed from `$custom_whitelist` to `$customAllowedFunctionsList`. * * @var array */ - public $custom_whitelist = array(); + public $customAllowedFunctionsList = array(); /** * PHP native function whitelist. @@ -180,9 +181,9 @@ public function register() { * @param int $stackPtr The position of the current token in the stack. */ public function process_token( $stackPtr ) { - // Handle the user-defined custom function whitelist. - $this->custom_whitelist = $this->merge_custom_array( $this->custom_whitelist, array(), false ); - $this->custom_whitelist = array_map( 'strtolower', $this->custom_whitelist ); + // Handle the user-defined custom function list. + $this->customAllowedFunctionsList = $this->merge_custom_array( $this->customAllowedFunctionsList, array(), false ); + $this->customAllowedFunctionsList = array_map( 'strtolower', $this->customAllowedFunctionsList ); /* * Check if the error silencing is done for one of the whitelisted functions. @@ -197,8 +198,8 @@ public function process_token( $stackPtr ) { $function_name = strtolower( $this->tokens[ $next_non_empty ]['content'] ); if ( ( true === $this->usePHPFunctionsList && isset( $this->function_whitelist[ $function_name ] ) === true ) - || ( ! empty( $this->custom_whitelist ) - && in_array( $function_name, $this->custom_whitelist, true ) === true ) + || ( ! empty( $this->customAllowedFunctionsList ) + && in_array( $function_name, $this->customAllowedFunctionsList, true ) === true ) ) { $this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', 'whitelisted function call: ' . $function_name ); return; diff --git a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc index 01a2be9cb6..d5e777e17a 100644 --- a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc +++ b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc @@ -39,11 +39,11 @@ if ( @ftp_fget($conn_id, $handle, $remote_file, FTP_ASCII, 0 ) ) { // Bad. } @ftp_close($conn_id); // Bad. -// phpcs:set WordPress.PHP.NoSilencedErrors custom_whitelist[] fgetcsv,hex2bin +// phpcs:set WordPress.PHP.NoSilencedErrors customAllowedFunctionsList[] fgetcsv,hex2bin while ( ( $csvdata = @fgetcsv( $handle, 2000, $separator ) ) !== false ) {} echo @some_userland_function( $param ); // Bad. $decoded = @hex2bin( $data ); -// phpcs:set WordPress.PHP.NoSilencedErrors custom_whitelist[] +// phpcs:set WordPress.PHP.NoSilencedErrors customAllowedFunctionsList[] $decoded = @hex2bin( $data ); // Bad. @@ -71,12 +71,12 @@ if (@is_dir($dir)) { // Bad. $files1 = @ & scandir($dir); // Bad. /* - * Custom whitelist will be respected even when `usePHPFunctionsList` is set to false. + * The custom allowed functions list will be respected even when `usePHPFunctionsList` is set to false. */ -// phpcs:set WordPress.PHP.NoSilencedErrors custom_whitelist[] fgetcsv,hex2bin +// phpcs:set WordPress.PHP.NoSilencedErrors customAllowedFunctionsList[] fgetcsv,hex2bin while ( ( $csvdata = @fgetcsv( $handle, 2000, $separator ) ) !== false ) {} echo @some_userland_function( $param ); // Bad. $decoded = @hex2bin( $data ); -// phpcs:set WordPress.PHP.NoSilencedErrors custom_whitelist[] +// phpcs:set WordPress.PHP.NoSilencedErrors customAllowedFunctionsList[] // phpcs:set WordPress.PHP.NoSilencedErrors usePHPFunctionsList true From 5527d30d75a527f9d3d7b461c8440302a91d1afb Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 16:59:44 +0200 Subject: [PATCH 157/822] NoSilencedErrors: rename property [3] As this is a `protected` property, this is an internal change only (unless an external standard would be extending the sniff). Also note that the new name is in line with the name for the same property in an upcoming replacement sniff in PHPCSExtra. This should make the switch over to the replacement sniff more straight-forward (if and when). --- WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php | 9 +++++---- WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index 026a8fb94e..c6b64afdf5 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -36,7 +36,7 @@ class NoSilencedErrorsSniff extends Sniff { public $context_length = 6; /** - * Whether or not the `$function_whitelist` should be used. + * Whether or not the `$allowedFunctionsList` should be used. * * Defaults to true. * @@ -64,7 +64,7 @@ class NoSilencedErrorsSniff extends Sniff { public $customAllowedFunctionsList = array(); /** - * PHP native function whitelist. + * PHP native functions allow list. * * Errors caused by calls to any of these native PHP functions * are allowed to be silenced as file system permissions and such @@ -78,10 +78,11 @@ class NoSilencedErrorsSniff extends Sniff { * error will be thrown on failure are accepted into this list. * * @since 1.1.0 + * @since 3.0.0 Renamed from `$function_whitelist` to `$allowedFunctionsList`. * * @var array => */ - protected $function_whitelist = array( + protected $allowedFunctionsList = array( // Directory extension. 'chdir' => true, 'opendir' => true, @@ -197,7 +198,7 @@ public function process_token( $stackPtr ) { if ( false !== $has_parenthesis && \T_OPEN_PARENTHESIS === $this->tokens[ $has_parenthesis ]['code'] ) { $function_name = strtolower( $this->tokens[ $next_non_empty ]['content'] ); if ( ( true === $this->usePHPFunctionsList - && isset( $this->function_whitelist[ $function_name ] ) === true ) + && isset( $this->allowedFunctionsList[ $function_name ] ) === true ) || ( ! empty( $this->customAllowedFunctionsList ) && in_array( $function_name, $this->customAllowedFunctionsList, true ) === true ) ) { diff --git a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc index d5e777e17a..cc846d2dec 100644 --- a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc +++ b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc @@ -50,7 +50,7 @@ $decoded = @hex2bin( $data ); // Bad. $unserialized = @unserialize( $str ); /* - * ... and test the same principle again, but now without using the whitelist. + * ... and test the same principle again, but now without using the PHP function allow list. */ // phpcs:set WordPress.PHP.NoSilencedErrors usePHPFunctionsList false From a3d993f559d57a289f8c696abdc99754aac3ff74 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 17:03:11 +0200 Subject: [PATCH 158/822] NoSilencedErrors: fix up comments --- WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index c6b64afdf5..70249ee56c 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -187,9 +187,9 @@ public function process_token( $stackPtr ) { $this->customAllowedFunctionsList = array_map( 'strtolower', $this->customAllowedFunctionsList ); /* - * Check if the error silencing is done for one of the whitelisted functions. + * Check if the error silencing is done for one of the allowed functions. * - * @internal The function call name determination is done even when there is no whitelist active + * @internal The function call name determination is done even when there is no allow list active * to allow the metrics to be more informative. */ $next_non_empty = $this->phpcsFile->findNext( $this->empty_tokens, ( $stackPtr + 1 ), null, true, null, true ); From 06dc19491395819329dd510ae1b71902e8462dc8 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 17:24:45 +0200 Subject: [PATCH 159/822] NoSilencedErrors: rename a metric --- WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index 70249ee56c..251805ab7f 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -202,7 +202,7 @@ public function process_token( $stackPtr ) { || ( ! empty( $this->customAllowedFunctionsList ) && in_array( $function_name, $this->customAllowedFunctionsList, true ) === true ) ) { - $this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', 'whitelisted function call: ' . $function_name ); + $this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', 'silencing allowed function call: ' . $function_name ); return; } } From 669fc23d666d51fd89653f14a04b8d48d3bf5ffe Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 17 Jun 2022 17:55:44 +0200 Subject: [PATCH 160/822] Various language usage updates in comments Includes: * Removing a reference to a custom ignore annotation which was already removed in PR 1908. * Removing a changelog entry referring to a custom ignore annotation which doesn't exist anymore. * Use more inclusive language in various other comments. --- WordPress/Helpers/IsUnitTestTrait.php | 4 ++-- WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php | 4 ---- WordPress/Sniffs/DB/SlowDBQuerySniff.php | 3 --- WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php | 2 +- .../NamingConventions/PrefixAllGlobalsUnitTest.1.inc | 4 ++-- .../NamingConventions/ValidVariableNameUnitTest.inc | 2 +- .../Tests/Security/NonceVerificationUnitTest.inc | 2 +- .../Tests/Utils/I18nTextDomainFixerUnitTest.4.inc | 2 +- .../Utils/I18nTextDomainFixerUnitTest.4.inc.fixed | 2 +- .../Tests/WP/GlobalVariablesOverrideUnitTest.1.inc | 2 +- .../WhiteSpace/PrecisionAlignmentUnitTest.2.inc | 12 ++++++------ .../WhiteSpace/PrecisionAlignmentUnitTest.7a.inc | 8 ++++---- .../WhiteSpace/PrecisionAlignmentUnitTest.7b.inc | 8 ++++---- .../WhiteSpace/PrecisionAlignmentUnitTest.7c.inc | 8 ++++---- 14 files changed, 28 insertions(+), 35 deletions(-) diff --git a/WordPress/Helpers/IsUnitTestTrait.php b/WordPress/Helpers/IsUnitTestTrait.php index b3712da57c..00c45c8717 100644 --- a/WordPress/Helpers/IsUnitTestTrait.php +++ b/WordPress/Helpers/IsUnitTestTrait.php @@ -140,7 +140,7 @@ protected function is_test_class( File $phpcsFile, $stackPtr ) { $known_test_classes[ $k ] = ltrim( $v, '\\' ); } - // Is the class/trait one of the whitelisted test classes ? + // Is the class/trait one of the known test classes ? $namespace = Namespaces::determineNamespace( $phpcsFile, $stackPtr ); $className = ObjectDeclarations::getName( $phpcsFile, $stackPtr ); if ( '' !== $namespace ) { @@ -151,7 +151,7 @@ protected function is_test_class( File $phpcsFile, $stackPtr ) { return true; } - // Does the class/trait extend one of the whitelisted test classes ? + // Does the class/trait extend one of the known test classes ? $extendedClassName = ObjectDeclarations::findExtendedClassName( $phpcsFile, $stackPtr ); if ( false === $extendedClassName ) { return false; diff --git a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php index 836b6e51dd..fde54a9ce7 100644 --- a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php @@ -34,10 +34,6 @@ * created using code along the lines of: * `sprintf( 'query .... IN (%s) ...', implode( ',', array_fill( 0, count( $something ), '%s' ) ) )`. * - * A "PreparedSQLPlaceholders replacement count" whitelist comment is supported - * specifically to silence the `ReplacementsWrongNumber` and `UnfinishedPrepare` - * error codes. The other error codes are not affected by it. - * * @link https://developer.wordpress.org/reference/classes/wpdb/prepare/ * @link https://core.trac.wordpress.org/changeset/41496 * @link https://core.trac.wordpress.org/changeset/41471 diff --git a/WordPress/Sniffs/DB/SlowDBQuerySniff.php b/WordPress/Sniffs/DB/SlowDBQuerySniff.php index e6157cb020..714f89454b 100644 --- a/WordPress/Sniffs/DB/SlowDBQuerySniff.php +++ b/WordPress/Sniffs/DB/SlowDBQuerySniff.php @@ -19,9 +19,6 @@ * @package WPCS\WordPressCodingStandards * * @since 0.3.0 - * @since 0.12.0 Introduced new and more intuitively named 'slow query' whitelist - * comment, replacing the 'tax_query' whitelist comment which is now - * deprecated. * @since 0.13.0 Class name changed: this class is now namespaced. * @since 1.0.0 This sniff has been moved from the `VIP` category to the `DB` category. */ diff --git a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php index 0ab1bcd1d5..fb3f05f7d1 100644 --- a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php +++ b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php @@ -54,7 +54,7 @@ class GlobalVariablesOverrideSniff extends Sniff { public $treat_files_as_scoped = false; /** - * Whitelist select variables from the Sniff::$wp_globals array. + * Allow select variables from the Sniff::$wp_globals array to be overwritten. * * A few select variables in WP Core are _intended_ to be overwritten * by themes/plugins. This sniff should not throw an error for those. diff --git a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc index 8c9c3e2e2b..2966bb1a2b 100644 --- a/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc +++ b/WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc @@ -157,7 +157,7 @@ namespace Acronym { /* - * OK - exceptions whitelisted by default. + * OK - exceptions ignored by default. */ $_POST['something'] = 'value'; @@ -319,7 +319,7 @@ namespace TGMPA\Testing { define( 'MY\\' . __NAMESPACE__, __FILE__ ); // OK, even though strangely setup, the constant is in a namespace. } -// OK: whitelisted core hooks. +// OK: ignored core hooks. apply_filters( 'widget_title', $title ); do_action( 'add_meta_boxes' ); diff --git a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc index 16221b7dd8..e5923c3d1d 100644 --- a/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc +++ b/WordPress/Tests/NamingConventions/ValidVariableNameUnitTest.inc @@ -127,7 +127,7 @@ echo "This is a $comment_ID"; // Bad echo "This is $PHP_SELF with $HTTP_RAW_POST_DATA"; // Ok. /* - * Unit test whitelisting. + * Ignoring unit tests. */ // phpcs:set WordPress.NamingConventions.ValidVariableName allowed_custom_properties[] varName,DOMProperty echo MyClass::$varName; // Ok, allowed. diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.inc index 4f60f45aec..e3a12f28e2 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.inc @@ -165,7 +165,7 @@ function foo_8() { * Using a superglobal in a is_...() function is OK as long as a nonce check is done * before the variable is *really* used. */ -function test_whitelisting_use_in_type_test_functions() { +function test_ignoring_use_in_type_test_functions() { if ( ! is_numeric ( $_POST['foo'] ) ) { // OK. return; } diff --git a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc index 87d52fbba5..630639124a 100644 --- a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc +++ b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc @@ -67,7 +67,7 @@ _x( $text, $context, $variableTextdomain ); _ex( $text, $context, CONSTANT_TEXTDOMAIN ); /* - * Text domains *not* in the whitelisted "old" domain list should be ignored. + * Text domains *not* in the "old" domain list should be ignored. */ load_plugin_textdomain( 'tgmpa', false, '/languages/' ); _e( $text, 'default' ); diff --git a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed index 2c0c176ebd..bd50e3a2f9 100644 --- a/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed +++ b/WordPress/Tests/Utils/I18nTextDomainFixerUnitTest.4.inc.fixed @@ -67,7 +67,7 @@ _x( $text, $context, $variableTextdomain ); _ex( $text, $context, CONSTANT_TEXTDOMAIN ); /* - * Text domains *not* in the whitelisted "old" domain list should be ignored. + * Text domains *not* in the "old" domain list should be ignored. */ load_plugin_textdomain( 'tgmpa', false, '/languages/' ); _e( $text, 'default' ); diff --git a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc index b916db85ff..7b97c5743d 100644 --- a/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc +++ b/WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.1.inc @@ -107,7 +107,7 @@ trait My_Class { } } -// Test adding additional test classes to the whitelist. +// Test adding additional test classes to the custom test classes list. // phpcs:set WordPress.WP.GlobalVariablesOverride custom_test_classes[] My_TestClass class Test_Class_D extends My_TestClass { diff --git a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.2.inc b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.2.inc index 8ee264ae22..3997fb51dc 100644 --- a/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.2.inc +++ b/WordPress/Tests/WhiteSpace/PrecisionAlignmentUnitTest.2.inc @@ -19,24 +19,24 @@ phpcs:set WordPress.WhiteSpace.PrecisionAlignment ignoreAlignmentTokens[] T_COMM /** * OK: Doc comments are indented with tabs and one space. * - * @var string <= Bad, but not reported as token type is whitelisted. + * @var string <= Bad, but not reported as token type is ignored. * @access private */ /* * OK: Multi-line comments are indented with tabs and one space. * - * <= Bad, but not reported as token type is whitelisted + * <= Bad, but not reported as token type is ignored */ - function exampleFunctionD() {} // Bad, but not reported as token type is whitelisted. - function exampleFunctionE() {} // Bad, but not reported as token type is whitelisted. - function exampleFunctionF() {} // Bad, but not reported as token type is whitelisted. + function exampleFunctionD() {} // Bad, but not reported as token type is ignored. + function exampleFunctionE() {} // Bad, but not reported as token type is ignored. + function exampleFunctionF() {} // Bad, but not reported as token type is ignored. ?>

- Bad: Some text with precision alignment, but not reported as token type is whitelisted. + Bad: Some text with precision alignment, but not reported as token type is ignored.

Date: Fri, 24 Jun 2022 10:53:24 -0300 Subject: [PATCH 161/822] Add link to "Running in GitHub Actions" doc page See #1976 --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1b1a859456..443a3d1221 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ + [Command line](#command-line) + [Using PHPCS and WPCS from within your IDE](#using-phpcs-and-wpcs-from-within-your-ide) * [Running your code through WPCS automatically using CI tools](#running-your-code-through-wpcs-automatically-using-ci-tools) + + [GitHub Actions](#github-actions) + [Travis CI](#travis-ci) * [Fixing errors or ignoring them](#fixing-errors-or-ignoring-them) + [Tools shipped with WPCS](#tools-shipped-with-wpcs) @@ -225,6 +226,10 @@ Will result in following output: ## Running your code through WPCS automatically using CI tools +### [GitHub Actions](https://github.com/features/actions) + +To run WPCS in GitHub Actions, check this documentation page: [Running in GitHub Actions](https://github.com/WordPress/WordPress-Coding-Standards/wiki/Running-in-GitHub-Actions). + ### [Travis CI](https://travis-ci.com/) To integrate PHPCS with WPCS with Travis CI, you'll need to install both `before_install` and add the run command to the `script`. From e7765de1712833f8e8173e06f603101c0ab13d5a Mon Sep 17 00:00:00 2001 From: Lucas Bustamante Date: Fri, 24 Jun 2022 12:03:45 -0300 Subject: [PATCH 162/822] Update README.md --- README.md | 47 ++--------------------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 443a3d1221..095c814294 100644 --- a/README.md +++ b/README.md @@ -226,51 +226,8 @@ Will result in following output: ## Running your code through WPCS automatically using CI tools -### [GitHub Actions](https://github.com/features/actions) - -To run WPCS in GitHub Actions, check this documentation page: [Running in GitHub Actions](https://github.com/WordPress/WordPress-Coding-Standards/wiki/Running-in-GitHub-Actions). - -### [Travis CI](https://travis-ci.com/) - -To integrate PHPCS with WPCS with Travis CI, you'll need to install both `before_install` and add the run command to the `script`. -If your project uses Composer, the typical instructions might be different. - -If you use a matrix setup in Travis to test your code against different PHP and/or WordPress versions, you don't need to run PHPCS on each variant of the matrix as the results will be same. -You can set an environment variable in the Travis matrix to only run the sniffs against one setup in the matrix. - -#### Travis CI example -```yaml -language: php - -matrix: - include: - # Arbitrary PHP version to run the sniffs against. - - php: '7.0' - env: SNIFF=1 - -before_install: - - if [[ "$SNIFF" == "1" ]]; then export PHPCS_DIR=/tmp/phpcs; fi - - if [[ "$SNIFF" == "1" ]]; then export SNIFFS_DIR=/tmp/sniffs; fi - # Install PHP_CodeSniffer. - - if [[ "$SNIFF" == "1" ]]; then git clone -b master --depth 1 https://github.com/squizlabs/PHP_CodeSniffer.git $PHPCS_DIR; fi - # Install WordPress Coding Standards. - - if [[ "$SNIFF" == "1" ]]; then git clone -b master --depth 1 https://github.com/WordPress/WordPress-Coding-Standards.git $SNIFFS_DIR; fi - # Set install path for WordPress Coding Standards. - - if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/bin/phpcs --config-set installed_paths $SNIFFS_DIR; fi - # After CodeSniffer install you should refresh your path. - - if [[ "$SNIFF" == "1" ]]; then phpenv rehash; fi - -script: - # Run against WordPress Coding Standards. - # If you use a custom ruleset, change `--standard=WordPress` to point to your ruleset file, - # for example: `--standard=wpcs.xml`. - # You can use any of the normal PHPCS command line arguments in the command: - # https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage - - if [[ "$SNIFF" == "1" ]]; then $PHPCS_DIR/bin/phpcs -p . --standard=WordPress; fi -``` - -More examples and advice about integrating PHPCS in your Travis build tests can be found here: https://github.com/jrfnl/make-phpcs-work-for-you/tree/master/travis-examples - +- [Running in GitHub Actions](https://github.com/WordPress/WordPress-Coding-Standards/wiki/Running-in-GitHub-Actions) +- [Running in Travis](https://github.com/WordPress/WordPress-Coding-Standards/wiki/Running-in-Travis) ## Fixing errors or ignoring them From aa3e9ec56d3f97c7005751d178c4d740fc624cd8 Mon Sep 17 00:00:00 2001 From: Lucas Bustamante Date: Fri, 24 Jun 2022 12:06:32 -0300 Subject: [PATCH 163/822] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 095c814294..4043438803 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,6 @@ + [Command line](#command-line) + [Using PHPCS and WPCS from within your IDE](#using-phpcs-and-wpcs-from-within-your-ide) * [Running your code through WPCS automatically using CI tools](#running-your-code-through-wpcs-automatically-using-ci-tools) - + [GitHub Actions](#github-actions) - + [Travis CI](#travis-ci) * [Fixing errors or ignoring them](#fixing-errors-or-ignoring-them) + [Tools shipped with WPCS](#tools-shipped-with-wpcs) * [Contributing](#contributing) From 699466569b6b17d50b46e96df12a056ff60271af Mon Sep 17 00:00:00 2001 From: Juliette <663378+jrfnl@users.noreply.github.com> Date: Tue, 9 Aug 2022 08:25:37 +0200 Subject: [PATCH 164/822] WP/CronInterval: update inline annotations in test case file (#2074) See: https://github.com/WordPress/WordPress-Coding-Standards/pull/2073#discussion_r940007958 Co-authored-by: jrfnl --- WordPress/Tests/WP/CronIntervalUnitTest.inc | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.inc b/WordPress/Tests/WP/CronIntervalUnitTest.inc index 330084676c..bf5ac5fda1 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.inc +++ b/WordPress/Tests/WP/CronIntervalUnitTest.inc @@ -9,12 +9,12 @@ function my_add_weekly( $schedules ) { ); return $schedules; } -add_filter( 'cron_schedules', 'my_add_weekly'); // Error: 6 min. +add_filter( 'cron_schedules', 'my_add_weekly'); // Warning: 6 min. class Foo { public function __construct() { - add_filter( 'cron_schedules', array( $this, 'my_add_quickly' ) ); // Error: 10 min. + add_filter( 'cron_schedules', array( $this, 'my_add_quickly' ) ); // Warning: 10 min. } public function my_add_quickly( $schedules ) { @@ -34,7 +34,7 @@ class Foo { } } -add_filter( 'cron_schedules', array( 'Foo', 'my_add_quicklier' ) ); // Error: 5 min. +add_filter( 'cron_schedules', array( 'Foo', 'my_add_quicklier' ) ); // Warning: 5 min. add_filter( 'cron_schedules', array( $some_other_place, 'some_other_method' ) ); // Warning: time undetermined. @@ -46,11 +46,11 @@ add_filter( 'cron_schedules', function ( $schedules ) { 'display' => __( 'Once every 9 minutes' ) ); return $schedules; -} ); // Error: 9 min. +} ); // Warning: 9 min. add_filter( 'cron_schedules' ); // Ignore, no callback parameter. -add_filter( 'cron_schedules', [ 'Foo', 'my_add_quicklier' ] ); // Error: 5 min. +add_filter( 'cron_schedules', [ 'Foo', 'my_add_quicklier' ] ); // Warning: 5 min. // Ignore, not our function. My_Custom::add_filter( 'cron_schedules', [ 'Foo', 'my_add_quicklier' ] ); @@ -70,7 +70,7 @@ add_filter( 'cron_schedules', function ( $schedules ) { 'display' => __( 'Once every 8 minutes' ) ]; return $schedules; -} ); // Error: 8 min. +} ); // Warning: 8 min. // Deal correctly with the function calls for interval. add_filter( 'cron_schedules', function ( $schedules ) { @@ -88,7 +88,7 @@ add_filter( 'cron_schedules', function ( $schedules ) { 'display' => __( 'Once every 2 minutes' ) ); return $schedules; -} ); // Error: 2 min. +} ); // Warning: 2 min. add_filter( 'cron_schedules', function ( $schedules ) { $schedules['every_10_mins'] = array( 'interval' => 10 * 60, @@ -111,14 +111,14 @@ add_filter( 'cron_schedules', function ( $schedules ) { 'display' => __( 'Once every 2 minutes' ) ); return $schedules; -} ); // Error: 2 min. +} ); // Warning: 2 min. add_filter( 'cron_schedules', function ( $schedules ) { $schedules['every_15_mins'] = array( 'interval' => 15 * 60, 'display' => __( 'Once every 15 minutes' ) ); return $schedules; -} ); // Error: 15 min. +} ); // Warning: 15 min. add_filter( 'cron_schedules', function ( $schedules ) { $schedules['every_hour'] = [ 'interval' => HOUR_IN_SECONDS, @@ -138,7 +138,7 @@ add_filter( 'cron_schedules', function ( $schedules ) { 'display' => __( 'Once every 9 minutes' ) ); return $schedules; -} ); // Error: 9 min. +} ); // Warning: 9 min. Custom::add_filter( 'cron_schedules', array( $class, $method ) ); // OK, not the WP function. add_filter( 'some_hook', array( $place, 'cron_schedules' ) ); // OK, not the hook we're looking for. @@ -159,4 +159,4 @@ add_filter( 'cron_schedules', function ( $schedules ) { 'display' => __( 'Once every 8 minutes' ) ]; return $schedules; -} ); // Error: 8 min. +} ); // Warning: 8 min. From 935257b6dd0d7640e41790fb52afc98da460b81e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 7 Aug 2022 23:02:29 +0200 Subject: [PATCH 165/822] WP/CronInterval: bugfix for fully qualified time constants If the WP time constants would be used in their fully qualified form, as is often encountered in namespaced files, the sniff would no longer be able to correctly determine the interval being scheduled. This commit fixes that. Note: To prevent constants from a different namespace accidentally matching the WP native constants, the namespace separator is replace by a space character rather than just ignored. The regex before running the `eval()` will prevent code with identifier names other than the WP time constants from being passed to the `eval()`, meaning those will still be reported as "interval undetermined". Includes unit tests. --- WordPress/Sniffs/WP/CronIntervalSniff.php | 5 +++ WordPress/Tests/WP/CronIntervalUnitTest.inc | 42 +++++++++++++++++++++ WordPress/Tests/WP/CronIntervalUnitTest.php | 3 ++ 3 files changed, 50 insertions(+) diff --git a/WordPress/Sniffs/WP/CronIntervalSniff.php b/WordPress/Sniffs/WP/CronIntervalSniff.php index 65badaa90a..21ee0e9b87 100644 --- a/WordPress/Sniffs/WP/CronIntervalSniff.php +++ b/WordPress/Sniffs/WP/CronIntervalSniff.php @@ -182,6 +182,11 @@ public function process_token( $stackPtr ) { continue; } + if ( \T_NS_SEPARATOR === $this->tokens[ $j ]['code'] ) { + $value .= ' '; + continue; + } + if ( $j === $valueEnd && \T_COMMA === $this->tokens[ $j ]['code'] ) { break; } diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.inc b/WordPress/Tests/WP/CronIntervalUnitTest.inc index bf5ac5fda1..7293774019 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.inc +++ b/WordPress/Tests/WP/CronIntervalUnitTest.inc @@ -160,3 +160,45 @@ add_filter( 'cron_schedules', function ( $schedules ) { ]; return $schedules; } ); // Warning: 8 min. + +// Correctly handle fully qualified WP time constants. +class FQNConstants { + public function add_schedules() { + add_filter( 'cron_schedules', array( $this, 'add_weekly_schedule' ) ); // Ok: > 15 min. + add_filter( 'cron_schedules', array( $this, 'add_eight_minute_schedule' ) ); // Warning: 8 min. + add_filter( 'cron_schedules', array( $this, 'add_hundred_minute_schedule' ) ); // Warning: time undetermined. + add_filter( 'cron_schedules', array( $this, 'sneaky_fake_wp_constant_schedule' ) ); // Warning: time undetermined. + } + + public function add_weekly_schedule( $schedules ) { + $schedules['weekly'] = [ + 'interval' => \WEEK_IN_SECONDS, + 'display' => \__( 'Once Weekly', 'text-domain' ), + ]; + return $schedules; + } + + public function add_eight_minute_schedule( $schedules ) { + $schedules['every_8_minutes'] = [ + 'interval' => (8 * \MINUTE_IN_SECONDS), + 'display' => __( 'Once every 8 minutes' ) + ]; + return $schedules; + } + + public function add_hundred_minute_schedule( $schedules ) { + $schedules['every_100_minutes'] = [ + 'interval' => (100 * My\Name\MINUTE_IN_SECONDS), + 'display' => __( 'Once every 100 minutes' ) + ]; + return $schedules; + } + + public function sneaky_fake_wp_constant_schedule( $schedules ) { + $schedules['every_100_seconds'] = [ + 'interval' => (100 * MINUTE_\IN_\SECONDS), + 'display' => __( 'Once every 100 minutes' ) + ]; + return $schedules; + } +} diff --git a/WordPress/Tests/WP/CronIntervalUnitTest.php b/WordPress/Tests/WP/CronIntervalUnitTest.php index 522e45211f..db79d38475 100644 --- a/WordPress/Tests/WP/CronIntervalUnitTest.php +++ b/WordPress/Tests/WP/CronIntervalUnitTest.php @@ -52,6 +52,9 @@ public function getWarningList() { 115 => 1, 133 => 1, 156 => 1, + 168 => 1, + 169 => 1, + 170 => 1, ); } } From 128e7e880924dbf8a002b32121ad456fb183f879 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 03:04:09 +0200 Subject: [PATCH 166/822] Arrays/ArrayKeySpacingRestrictions: don't warn on parse error Most sniffs will silently bow out on parse errors. This is the preferred behaviour as sniffs are often run in IDEs during live coding. The `ArrayKeySpacingRestrictions` sniff would, however, throw a warning when a close bracket was missing. This commit removes that warning. This is in line with similar changes (no longer throwing warnings/errors on parse errors) which will be included in PHPCS 4.x upstream. Note: there were no tests covering the warning, so the test files are untouched. Refs: * squizlabs/PHP_CodeSniffer 2455 --- WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php index 6b3203cd62..57559cbe89 100644 --- a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php @@ -49,7 +49,6 @@ public function process_token( $stackPtr ) { $token = $this->tokens[ $stackPtr ]; if ( ! isset( $token['bracket_closer'] ) ) { - $this->phpcsFile->addWarning( 'Missing bracket closer.', $stackPtr, 'MissingBracketCloser' ); return; } From c04858aeb14bf9be438e498e94125df38b0f2634 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 04:34:48 +0200 Subject: [PATCH 167/822] Arrays/ArrayKeySpacingRestrictions: improve handling of brackets for array assignments without key As it was, this was handled correctly, though the error message was unclear as it referred to "array keys", while these assignments don't have an explicit key. To fix this, I'm now special casing array assignments without an explicit key. The original error message in that situation was: "Array keys must NOT be surrounded by spaces if they only contain a string or an integer." The new error message will be: "There should be no space between the square brackets for an array assignment without an explicit key. Found: ..." The new error message will also have a different, new error code: `SpacesBetweenBrackets`. Note: the new error code could be considered a breaking change, though I doubt many people will notice this as this is not typically an error code which would be used in inline ignore annotations. Includes unit tests. Note: the behaviour for array assignments without an explicit key, but with a comment between the brackets, has not been changed. In that case, the original `NoSpacesAroundArrayKeys` error will still be thrown. All the same, tests have been added to verify and safeguard this. --- .../ArrayKeySpacingRestrictionsSniff.php | 24 ++++++++++++++++++- .../ArrayKeySpacingRestrictionsUnitTest.inc | 10 ++++++++ ...ayKeySpacingRestrictionsUnitTest.inc.fixed | 9 +++++++ .../ArrayKeySpacingRestrictionsUnitTest.php | 3 +++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php index 57559cbe89..a2f2a3955f 100644 --- a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php @@ -9,8 +9,9 @@ namespace WordPressCS\WordPress\Sniffs\Arrays; -use WordPressCS\WordPress\Sniff; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Fixers\SpacesFixer; +use WordPressCS\WordPress\Sniff; /** * Check for proper spacing in array key references. @@ -52,6 +53,27 @@ public function process_token( $stackPtr ) { return; } + /* + * Handle square brackets without a key (array assignments) first. + */ + $first_non_ws = $this->phpcsFile->findNext( \T_WHITESPACE, ( $stackPtr + 1 ), null, true ); + if ( $first_non_ws === $token['bracket_closer'] ) { + $error = 'There should be %1$s between the square brackets for an array assignment without an explicit key. Found: %2$s'; + SpacesFixer::checkAndFix( + $this->phpcsFile, + $stackPtr, + $token['bracket_closer'], + 0, + $error, + 'SpacesBetweenBrackets' + ); + + return; + } + + /* + * Handle the spaces around explicit array keys. + */ $need_spaces = $this->phpcsFile->findNext( array( \T_CONSTANT_ENCAPSED_STRING, \T_LNUMBER, \T_WHITESPACE, \T_MINUS ), ( $stackPtr + 1 ), diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc index ceaadfe52e..bf2f6aff8e 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc @@ -44,3 +44,13 @@ $arr[ $a = $arr[ /*comment*/ 'key']; // Bad x 2. $a = $arr[/*comment*/ 'key' ]; // Bad x 2. + +// Verify handling of array assignments without an explicit key. +$bar[] = 10; // Good. +$bar[ ] = 10; // Bad. +$bar[ + ] = 10; // Bad. + +// Verify handling of array assignments without an explicit key, but with a comment. +$bar[ /*comment*/ ] = 10; // Good. +$bar[/*comment*/] = 10; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed index 88fe475feb..a4e29e9de7 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed @@ -37,3 +37,12 @@ $arr[ FooClass::FOO_KEY ]; // Bad x 2. $a = $arr[ /*comment*/ 'key' ]; // Bad x 2. $a = $arr[ /*comment*/ 'key' ]; // Bad x 2. + +// Verify handling of array assignments without an explicit key. +$bar[] = 10; // Good. +$bar[] = 10; // Bad. +$bar[] = 10; // Bad. + +// Verify handling of array assignments without an explicit key, but with a comment. +$bar[ /*comment*/ ] = 10; // Good. +$bar[ /*comment*/ ] = 10; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php index 26b00a36f0..6fec267d61 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php @@ -47,6 +47,9 @@ public function getErrorList() { 40 => 1, 45 => 2, 46 => 2, + 50 => 1, + 51 => 1, + 56 => 1, ); } From d7318591e23af682589c41d2dad3ae66be6b50c0 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 03:45:25 +0200 Subject: [PATCH 168/822] Arrays/ArrayKeySpacingRestrictions: tweak test order ... to more easily allow for additional tests for integer keys to be added. --- .../ArrayKeySpacingRestrictionsUnitTest.inc | 12 +++++++----- ...ArrayKeySpacingRestrictionsUnitTest.inc.fixed | 12 +++++++----- .../ArrayKeySpacingRestrictionsUnitTest.php | 16 ++++++++-------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc index bf2f6aff8e..be7a226fc0 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc @@ -25,11 +25,6 @@ bar( $arr['string'.$var] ); // Bad. // Non-string/int. $arr[FooClass::FOO_KEY]; // Bad. -$arr[0]; // Good. -$arr[ 0 ]; // Bad. -$arr[-1]; // Good. -$arr[ -1 ]; // Bad. - // Space size check. bar( $arr[ 'test' @@ -54,3 +49,10 @@ $bar[ // Verify handling of array assignments without an explicit key, but with a comment. $bar[ /*comment*/ ] = 10; // Good. $bar[/*comment*/] = 10; // Bad. + +// Integer keys. +$arr[0]; // Good. +$arr[-1]; // Good. + +$arr[ 0 ]; // Bad. +$arr[ -1 ]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed index a4e29e9de7..5fad75e99b 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed @@ -25,11 +25,6 @@ bar( $arr[ 'string'.$var ] ); // Bad. // Non-string/int. $arr[ FooClass::FOO_KEY ]; // Bad. -$arr[0]; // Good. -$arr[0]; // Bad. -$arr[-1]; // Good. -$arr[-1]; // Bad. - // Space size check. bar( $arr['test'] ); // Bad. bar( $arr[ $test ] ); // Bad x 2. @@ -46,3 +41,10 @@ $bar[] = 10; // Bad. // Verify handling of array assignments without an explicit key, but with a comment. $bar[ /*comment*/ ] = 10; // Good. $bar[ /*comment*/ ] = 10; // Bad. + +// Integer keys. +$arr[0]; // Good. +$arr[-1]; // Good. + +$arr[0]; // Bad. +$arr[-1]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php index 6fec267d61..83308934ac 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php @@ -40,16 +40,16 @@ public function getErrorList() { 23 => 1, 26 => 1, 29 => 1, - 31 => 1, + 33 => 2, 34 => 1, - 38 => 2, - 39 => 1, - 40 => 1, - 45 => 2, - 46 => 2, - 50 => 1, + 35 => 1, + 40 => 2, + 41 => 2, + 45 => 1, + 46 => 1, 51 => 1, - 56 => 1, + 57 => 1, + 58 => 1, ); } From f773872d09b8ee26f127bc44bdbe3aea401ba0bb Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 03:52:39 +0200 Subject: [PATCH 169/822] Arrays/ArrayKeySpacingRestrictions: rename three local variables ... to make them more descriptive. --- .../ArrayKeySpacingRestrictionsSniff.php | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php index a2f2a3955f..fdbe87a4b9 100644 --- a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php @@ -74,35 +74,35 @@ public function process_token( $stackPtr ) { /* * Handle the spaces around explicit array keys. */ - $need_spaces = $this->phpcsFile->findNext( + $needs_spaces = $this->phpcsFile->findNext( array( \T_CONSTANT_ENCAPSED_STRING, \T_LNUMBER, \T_WHITESPACE, \T_MINUS ), ( $stackPtr + 1 ), $token['bracket_closer'], true ); - $spaced1 = ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code'] ); - $spaced2 = ( \T_WHITESPACE === $this->tokens[ ( $token['bracket_closer'] - 1 ) ]['code'] ); + $has_space_after_opener = ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code'] ); + $has_space_before_close = ( \T_WHITESPACE === $this->tokens[ ( $token['bracket_closer'] - 1 ) ]['code'] ); // It should have spaces unless if it only has strings or numbers as the key. - if ( false !== $need_spaces - && ( false === $spaced1 || false === $spaced2 ) + if ( false !== $needs_spaces + && ( false === $has_space_after_opener || false === $has_space_before_close ) ) { $error = 'Array keys must be surrounded by spaces unless they contain a string or an integer.'; $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpacesAroundArrayKeys' ); if ( true === $fix ) { - if ( ! $spaced1 ) { + if ( ! $has_space_after_opener ) { $this->phpcsFile->fixer->addContentBefore( ( $stackPtr + 1 ), ' ' ); } - if ( ! $spaced2 ) { + if ( ! $has_space_before_close ) { $this->phpcsFile->fixer->addContentBefore( $token['bracket_closer'], ' ' ); } } - } elseif ( false === $need_spaces && ( $spaced1 || $spaced2 ) ) { + } elseif ( false === $needs_spaces && ( $has_space_after_opener || $has_space_before_close ) ) { $error = 'Array keys must NOT be surrounded by spaces if they only contain a string or an integer.'; $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'SpacesAroundArrayKeys' ); if ( true === $fix ) { - if ( $spaced1 ) { + if ( $has_space_after_opener ) { $this->phpcsFile->fixer->beginChangeset(); $this->phpcsFile->fixer->replaceToken( ( $stackPtr + 1 ), '' ); @@ -116,7 +116,7 @@ public function process_token( $stackPtr ) { $this->phpcsFile->fixer->endChangeset(); } - if ( $spaced2 ) { + if ( $has_space_before_close ) { $this->phpcsFile->fixer->beginChangeset(); $this->phpcsFile->fixer->replaceToken( ( $token['bracket_closer'] - 1 ), '' ); @@ -134,8 +134,8 @@ public function process_token( $stackPtr ) { } // If spaces are needed, check that there is only one space. - if ( false !== $need_spaces && ( $spaced1 || $spaced2 ) ) { - if ( $spaced1 ) { + if ( false !== $needs_spaces && ( $has_space_after_opener || $has_space_before_close ) ) { + if ( $has_space_after_opener ) { $ptr = ( $stackPtr + 1 ); $length = 0; if ( $this->tokens[ $ptr ]['line'] !== $this->tokens[ ( $ptr + 1 ) ]['line'] ) { @@ -171,7 +171,7 @@ public function process_token( $stackPtr ) { } } - if ( $spaced2 ) { + if ( $has_space_before_close ) { $prev_non_empty = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $token['bracket_closer'] - 1 ), null, true ); $ptr = ( $prev_non_empty + 1 ); $length = 0; From 010288c1825996563427ae6c7f87afe568e5e78f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 05:10:32 +0200 Subject: [PATCH 170/822] Arrays/ArrayKeySpacingRestrictions: bug fix - require spaces around calculations and allow for + sign This commit fixes two bugs: 1. Signed integers with a plus sign would be treated differently from signed integers with a minus sign. While using the plus sign for unary integers will be rare, it is valid and they should be treated the same as unary integers with a minus sign. 2. When an array key consisted of a calculation with multiple integers and a minus sign, no spaces would be demanded around the array key, even though they key should be surrounded by spaces. Both bugs have now been fixed by walking the tokens in the array key more precisely. Includes unit tests covering both situations. Includes minor tweaks to some conditions as the `$needs_spaces` variables will now always be boolean, so we can make the conditions in which the variable is being used more readable. --- .../ArrayKeySpacingRestrictionsSniff.php | 25 +++++++++++++------ .../ArrayKeySpacingRestrictionsUnitTest.inc | 9 +++++++ ...ayKeySpacingRestrictionsUnitTest.inc.fixed | 9 +++++++ .../ArrayKeySpacingRestrictionsUnitTest.php | 5 +++- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php index fdbe87a4b9..db55b91ef9 100644 --- a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php @@ -74,18 +74,27 @@ public function process_token( $stackPtr ) { /* * Handle the spaces around explicit array keys. */ - $needs_spaces = $this->phpcsFile->findNext( - array( \T_CONSTANT_ENCAPSED_STRING, \T_LNUMBER, \T_WHITESPACE, \T_MINUS ), - ( $stackPtr + 1 ), - $token['bracket_closer'], - true - ); + $needs_spaces = true; + + // Skip over a potential plus/minus sign for integers. + $first_effective = $first_non_ws; + if ( \T_MINUS === $this->tokens[ $first_effective ]['code'] || \T_PLUS === $this->tokens[ $first_effective ]['code'] ) { + $first_effective = $this->phpcsFile->findNext( \T_WHITESPACE, ( $first_effective + 1 ), null, true ); + } + + $next_non_ws = $this->phpcsFile->findNext( \T_WHITESPACE, ( $first_effective + 1 ), null, true ); + if ( ( \T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $first_effective ]['code'] + || \T_LNUMBER === $this->tokens[ $first_effective ]['code'] ) + && $next_non_ws === $token['bracket_closer'] + ) { + $needs_spaces = false; + } $has_space_after_opener = ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code'] ); $has_space_before_close = ( \T_WHITESPACE === $this->tokens[ ( $token['bracket_closer'] - 1 ) ]['code'] ); // It should have spaces unless if it only has strings or numbers as the key. - if ( false !== $needs_spaces + if ( true === $needs_spaces && ( false === $has_space_after_opener || false === $has_space_before_close ) ) { $error = 'Array keys must be surrounded by spaces unless they contain a string or an integer.'; @@ -134,7 +143,7 @@ public function process_token( $stackPtr ) { } // If spaces are needed, check that there is only one space. - if ( false !== $needs_spaces && ( $has_space_after_opener || $has_space_before_close ) ) { + if ( true === $needs_spaces && ( $has_space_after_opener || $has_space_before_close ) ) { if ( $has_space_after_opener ) { $ptr = ( $stackPtr + 1 ); $length = 0; diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc index be7a226fc0..5b1b60e8cd 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc @@ -53,6 +53,15 @@ $bar[/*comment*/] = 10; // Bad. // Integer keys. $arr[0]; // Good. $arr[-1]; // Good. +$arr[+1]; // Good. $arr[ 0 ]; // Bad. $arr[ -1 ]; // Bad. +$arr[ +1 ]; // Bad. + +// Verify key calculations are handled correctly. +$arr[ 10 + 5 ]; // Good. +$arr[ 5-2 - -1 ]; // Good. + +$arr[ 10 + 5]; // Bad. +$arr[5-2 - -1 ]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed index 5fad75e99b..642a2cc260 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed @@ -45,6 +45,15 @@ $bar[ /*comment*/ ] = 10; // Bad. // Integer keys. $arr[0]; // Good. $arr[-1]; // Good. +$arr[+1]; // Good. $arr[0]; // Bad. $arr[-1]; // Bad. +$arr[+1]; // Bad. + +// Verify key calculations are handled correctly. +$arr[ 10 + 5 ]; // Good. +$arr[ 5-2 - -1 ]; // Good. + +$arr[ 10 + 5 ]; // Bad. +$arr[ 5-2 - -1 ]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php index 83308934ac..688c30c270 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php @@ -48,8 +48,11 @@ public function getErrorList() { 45 => 1, 46 => 1, 51 => 1, - 57 => 1, 58 => 1, + 59 => 1, + 60 => 1, + 66 => 1, + 67 => 1, ); } From 8dd890cd8c00b8ba9b20a8914363be45014d8b2c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 05:28:54 +0200 Subject: [PATCH 171/822] Arrays/ArrayKeySpacingRestrictions: add tests with non-decimal integers .. to safeguard these are handled the same as decimal integers. --- .../Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc | 9 +++++++++ .../Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed | 9 +++++++++ .../Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php | 3 +++ 3 files changed, 21 insertions(+) diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc index 5b1b60e8cd..d1673e3a49 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc @@ -65,3 +65,12 @@ $arr[ 5-2 - -1 ]; // Good. $arr[ 10 + 5]; // Bad. $arr[5-2 - -1 ]; // Bad. + +// Verify non-decimal integer keys are handled correctly. +$arr[012]; // Good. +$arr[0b01]; // Good. +$arr[0xCAFE]; // Good. + +$arr[ 012 ]; // Bad. +$arr[ 0b01 ]; // Bad. +$arr[ 0xCAFE ]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed index 642a2cc260..0d918b12ac 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed @@ -57,3 +57,12 @@ $arr[ 5-2 - -1 ]; // Good. $arr[ 10 + 5 ]; // Bad. $arr[ 5-2 - -1 ]; // Bad. + +// Verify non-decimal integer keys are handled correctly. +$arr[012]; // Good. +$arr[0b01]; // Good. +$arr[0xCAFE]; // Good. + +$arr[012]; // Bad. +$arr[0b01]; // Bad. +$arr[0xCAFE]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php index 688c30c270..3dde744720 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php @@ -53,6 +53,9 @@ public function getErrorList() { 60 => 1, 66 => 1, 67 => 1, + 74 => 1, + 75 => 1, + 76 => 1, ); } From 4a9148cf5228d90c42f0bc3d609218878f19e0fb Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 05:46:41 +0200 Subject: [PATCH 172/822] Arrays/ArrayKeySpacingRestrictions: minor simplifications Simplify the fixer code for the "Array keys must [NOT] be surrounded by spaces" errors. --- .../Arrays/ArrayKeySpacingRestrictionsSniff.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php index db55b91ef9..9ff4ede631 100644 --- a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php @@ -93,17 +93,18 @@ public function process_token( $stackPtr ) { $has_space_after_opener = ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code'] ); $has_space_before_close = ( \T_WHITESPACE === $this->tokens[ ( $token['bracket_closer'] - 1 ) ]['code'] ); - // It should have spaces unless if it only has strings or numbers as the key. + // The array key should be surrounded by spaces unless the key only consists of a string or an integer. if ( true === $needs_spaces && ( false === $has_space_after_opener || false === $has_space_before_close ) ) { $error = 'Array keys must be surrounded by spaces unless they contain a string or an integer.'; $fix = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpacesAroundArrayKeys' ); if ( true === $fix ) { - if ( ! $has_space_after_opener ) { - $this->phpcsFile->fixer->addContentBefore( ( $stackPtr + 1 ), ' ' ); + if ( false === $has_space_after_opener ) { + $this->phpcsFile->fixer->addContent( $stackPtr, ' ' ); } - if ( ! $has_space_before_close ) { + + if ( false === $has_space_before_close ) { $this->phpcsFile->fixer->addContentBefore( $token['bracket_closer'], ' ' ); } } @@ -113,9 +114,8 @@ public function process_token( $stackPtr ) { if ( true === $fix ) { if ( $has_space_after_opener ) { $this->phpcsFile->fixer->beginChangeset(); - $this->phpcsFile->fixer->replaceToken( ( $stackPtr + 1 ), '' ); - for ( $i = ( $stackPtr + 2 ); $i < $token['bracket_closer']; $i++ ) { + for ( $i = ( $stackPtr + 1 ); $i < $token['bracket_closer']; $i++ ) { if ( \T_WHITESPACE !== $this->tokens[ $i ]['code'] ) { break; } @@ -125,11 +125,11 @@ public function process_token( $stackPtr ) { $this->phpcsFile->fixer->endChangeset(); } + if ( $has_space_before_close ) { $this->phpcsFile->fixer->beginChangeset(); - $this->phpcsFile->fixer->replaceToken( ( $token['bracket_closer'] - 1 ), '' ); - for ( $i = ( $token['bracket_closer'] - 2 ); $i > $stackPtr; $i-- ) { + for ( $i = ( $token['bracket_closer'] - 1 ); $i > $stackPtr; $i-- ) { if ( \T_WHITESPACE !== $this->tokens[ $i ]['code'] ) { break; } From 6922761716f425ae40de66d56c0266f584a88c6c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 13:27:25 +0200 Subject: [PATCH 173/822] Arrays/ArrayKeySpacingRestrictions: implement the PHPCSUtils SpacesFixer This implements use of the PHPCSUtils `SpacesFixer` class for checking and fixing the width of the whitespace inside the brackets. While this doesn't change the effective behaviour of the sniff, it simplifies the code and improves the clarity of the error messages. Note: the error _codes_ do not change. Old error messages: ``` 33 | ERROR | [x] There should be exactly one space before the array key. Found: 5 33 | ERROR | [x] There should be exactly one space after the array key. Found: 4 34 | ERROR | [x] There should be exactly one space before the array key. Found: newline 35 | ERROR | [x] There should be exactly one space after the array key. Found: newline ``` New error messages: ``` 33 | ERROR | [x] There should be exactly 1 space before the array key. Found: 5 spaces 33 | ERROR | [x] There should be exactly 1 space after the array key. Found: 4 spaces 34 | ERROR | [x] There should be exactly 1 space before the array key. Found: a new line 35 | ERROR | [x] There should be exactly 1 space after the array key. Found: multiple new lines ``` --- .../ArrayKeySpacingRestrictionsSniff.php | 89 +++++-------------- 1 file changed, 20 insertions(+), 69 deletions(-) diff --git a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php index 9ff4ede631..9afc5ed542 100644 --- a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php +++ b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php @@ -9,7 +9,6 @@ namespace WordPressCS\WordPress\Sniffs\Arrays; -use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Fixers\SpacesFixer; use WordPressCS\WordPress\Sniff; @@ -143,78 +142,30 @@ public function process_token( $stackPtr ) { } // If spaces are needed, check that there is only one space. - if ( true === $needs_spaces && ( $has_space_after_opener || $has_space_before_close ) ) { + if ( true === $needs_spaces ) { if ( $has_space_after_opener ) { - $ptr = ( $stackPtr + 1 ); - $length = 0; - if ( $this->tokens[ $ptr ]['line'] !== $this->tokens[ ( $ptr + 1 ) ]['line'] ) { - $length = 'newline'; - } else { - $length = $this->tokens[ $ptr ]['length']; - } - - if ( 1 !== $length ) { - $error = 'There should be exactly one space before the array key. Found: %s'; - $data = array( $length ); - $fix = $this->phpcsFile->addFixableError( - $error, - $ptr, - 'TooMuchSpaceBeforeKey', - $data - ); - - if ( true === $fix ) { - $this->phpcsFile->fixer->beginChangeset(); - $this->phpcsFile->fixer->replaceToken( $ptr, ' ' ); - - for ( $i = ( $ptr + 1 ); $i < $token['bracket_closer']; $i++ ) { - if ( \T_WHITESPACE !== $this->tokens[ $i ]['code'] ) { - break; - } - - $this->phpcsFile->fixer->replaceToken( $i, '' ); - } - - $this->phpcsFile->fixer->endChangeset(); - } - } + $error = 'There should be exactly %1$s before the array key. Found: %2$s'; + SpacesFixer::checkAndFix( + $this->phpcsFile, + $stackPtr, + $first_non_ws, + 1, + $error, + 'TooMuchSpaceBeforeKey' + ); } if ( $has_space_before_close ) { - $prev_non_empty = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $token['bracket_closer'] - 1 ), null, true ); - $ptr = ( $prev_non_empty + 1 ); - $length = 0; - if ( $this->tokens[ $ptr ]['line'] !== $this->tokens[ $token['bracket_closer'] ]['line'] ) { - $length = 'newline'; - } else { - $length = $this->tokens[ $ptr ]['length']; - } - - if ( 1 !== $length ) { - $error = 'There should be exactly one space after the array key. Found: %s'; - $data = array( $length ); - $fix = $this->phpcsFile->addFixableError( - $error, - $ptr, - 'TooMuchSpaceAfterKey', - $data - ); - - if ( true === $fix ) { - $this->phpcsFile->fixer->beginChangeset(); - $this->phpcsFile->fixer->replaceToken( $ptr, ' ' ); - - for ( $i = ( $ptr + 1 ); $i < $token['bracket_closer']; $i++ ) { - if ( \T_WHITESPACE !== $this->tokens[ $i ]['code'] ) { - break; - } - - $this->phpcsFile->fixer->replaceToken( $i, '' ); - } - - $this->phpcsFile->fixer->endChangeset(); - } - } + $last_non_ws = $this->phpcsFile->findPrevious( \T_WHITESPACE, ( $token['bracket_closer'] - 1 ), null, true ); + $error = 'There should be exactly %1$s after the array key. Found: %2$s'; + SpacesFixer::checkAndFix( + $this->phpcsFile, + $last_non_ws, + $token['bracket_closer'], + 1, + $error, + 'TooMuchSpaceAfterKey' + ); } } } From aae019c626427f60d5e02935fd0e8805d57ad464 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 05:30:13 +0200 Subject: [PATCH 174/822] PHP 7.4 | Arrays/ArrayKeySpacingRestrictions: add tests with numeric literals with underscores .. to safeguard these are handled correctly. --- .../Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc | 7 +++++++ .../Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed | 7 +++++++ .../Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php | 2 ++ 3 files changed, 16 insertions(+) diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc index d1673e3a49..e5f261dab5 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc @@ -74,3 +74,10 @@ $arr[0xCAFE]; // Good. $arr[ 012 ]; // Bad. $arr[ 0b01 ]; // Bad. $arr[ 0xCAFE ]; // Bad. + +// Ensure correct handling of PHP 7.4+ numeric literals with underscores. +$arr[1_000_000]; // Good. +$arr[0xCAFE_F00D]; // Good. + +$arr[ 1_000_000 ]; // Bad. +$arr[ 0xCAFE_F00D ]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed index 0d918b12ac..a770c668f4 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed @@ -66,3 +66,10 @@ $arr[0xCAFE]; // Good. $arr[012]; // Bad. $arr[0b01]; // Bad. $arr[0xCAFE]; // Bad. + +// Ensure correct handling of PHP 7.4+ numeric literals with underscores. +$arr[1_000_000]; // Good. +$arr[0xCAFE_F00D]; // Good. + +$arr[1_000_000]; // Bad. +$arr[0xCAFE_F00D]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php index 3dde744720..57085acdec 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php @@ -56,6 +56,8 @@ public function getErrorList() { 74 => 1, 75 => 1, 76 => 1, + 82 => 1, + 83 => 1, ); } From 52d70f1ec22bdb9b6e6bdb7e105659c104371d29 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 17 Jul 2022 05:30:41 +0200 Subject: [PATCH 175/822] PHP 8.1 | Arrays/ArrayKeySpacingRestrictions: add tests with octal numeric literals .. to safeguard these are handled correctly. --- .../Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc | 4 ++++ .../Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed | 4 ++++ .../Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php | 1 + 3 files changed, 9 insertions(+) diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc index e5f261dab5..171f53b6cc 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc @@ -81,3 +81,7 @@ $arr[0xCAFE_F00D]; // Good. $arr[ 1_000_000 ]; // Bad. $arr[ 0xCAFE_F00D ]; // Bad. + +// Ensure correct handling of PHP 8.1+ octal literals. +$arr[0o137]; // Good. +$arr[ 0o137 ]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed index a770c668f4..2996b3d39a 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed @@ -73,3 +73,7 @@ $arr[0xCAFE_F00D]; // Good. $arr[1_000_000]; // Bad. $arr[0xCAFE_F00D]; // Bad. + +// Ensure correct handling of PHP 8.1+ octal literals. +$arr[0o137]; // Good. +$arr[0o137]; // Bad. diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php index 57085acdec..08cb83eb77 100644 --- a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php +++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.php @@ -58,6 +58,7 @@ public function getErrorList() { 76 => 1, 82 => 1, 83 => 1, + 87 => 1, ); } From 1b512610a3d4f54543108008a49d5497fb95f191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Fri, 22 Jul 2022 16:58:52 +0200 Subject: [PATCH 176/822] Reorganize core ruleset to match the reorganized chapters in the WPCS docs --- WordPress-Core/ruleset.xml | 442 +++++++++++++++++++------------------ 1 file changed, 225 insertions(+), 217 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index e9f604805e..789098c094 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -15,196 +15,98 @@ --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + 0 - + 0 - + 0 - - - - - - - - - - - - - - - - + + 0 - - - - - + + + - - - + + - - - + - - - - - + + + + - - - + + - + + - + + + + - - - - 0 - - - 0 - - - 0 - - - 0 - - + Handbook: PHP - Interpolation for Naming Dynamic Hooks. + Ref: https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#interpolation-for-naming-dynamic-hooks - - - - - + - - - + - - + - + + + + + + + + + + + + + + - + + + - - + + + - - + + + + + + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + - - - + + + + - - - - + + - - + + - - - - - - + + + + + + + + + + Best practices: Declare only one class/interface/trait in a file. + - https://github.com/WordPress/WordPress-Coding-Standards/issues/751 + + - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + - - Best practices: Declare only one class/interface/trait in a file. - - From 650eb4764147b40c03719369b52cde3be3b8bc4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Fri, 22 Jul 2022 17:04:41 +0200 Subject: [PATCH 177/822] Update the handbook links --- WordPress-Core/ruleset.xml | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 789098c094..6f225e417a 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -18,7 +18,7 @@ @@ -52,7 +52,7 @@ @@ -259,7 +259,7 @@ @@ -271,7 +271,7 @@ @@ -284,7 +284,7 @@ @@ -294,7 +294,7 @@ @@ -332,7 +332,7 @@ @@ -382,7 +382,7 @@ @@ -413,7 +413,7 @@ @@ -507,7 +507,7 @@ - + From e9614730e79a4101e299f0bb9c2ee37c1e280d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Fri, 12 Aug 2022 17:15:41 +0200 Subject: [PATCH 178/822] Fix the indentation in the core ruleset --- WordPress-Core/ruleset.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 6f225e417a..af2272c193 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -15,7 +15,7 @@ --> - - From 3373a49bcd4b4ad91796be5a1de63bca322b4695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 14 Aug 2022 10:40:18 +0200 Subject: [PATCH 180/822] Update WordPress-Core/ruleset.xml Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress-Core/ruleset.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 345ddf684e..5a869dce4f 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -17,7 +17,7 @@ From 7f3ebd2e1b96b693975fa8fcc6c885149b80c0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 14 Aug 2022 10:40:25 +0200 Subject: [PATCH 181/822] Update WordPress-Core/ruleset.xml Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress-Core/ruleset.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 5a869dce4f..9510e37413 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -225,8 +225,9 @@ - + From 3b85df228743edcc29a7837f60f287adbd1815fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 14 Aug 2022 10:40:29 +0200 Subject: [PATCH 182/822] Update WordPress-Core/ruleset.xml Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress-Core/ruleset.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 9510e37413..e290a22580 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -314,8 +314,7 @@ Ref: https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#only-one-object-structure-class-interface-trait-per-file ############################################################################# --> - + Best practices: Declare only one class/interface/trait in a file. From 0676c32bd380ec3c1f3f8419d99d3207093d5832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 14 Aug 2022 10:40:41 +0200 Subject: [PATCH 183/822] Update WordPress-Core/ruleset.xml Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress-Core/ruleset.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index e290a22580..14c3ac0234 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -397,9 +397,8 @@ placeholders. Note that they are not 'quoted'! --> - + From 61d782576c5e1a25861ebf392370f071374295d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 14 Aug 2022 11:24:57 +0200 Subject: [PATCH 184/822] Apply suggestions from the PR and update the covers rule texts --- WordPress-Core/ruleset.xml | 77 +++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 14c3ac0234..eee861589b 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -40,7 +40,7 @@ @@ -51,7 +51,7 @@ @@ -66,7 +66,7 @@ @@ -95,7 +95,7 @@ @@ -126,8 +126,7 @@ - + @@ -165,7 +164,7 @@ + For float casts use (float), not (real) which is deprecated in PHP 7.4, and removed in PHP 8. --> @@ -177,12 +176,12 @@ - + - + @@ -193,7 +192,7 @@ @@ -260,7 +259,7 @@ @@ -272,7 +271,7 @@ @@ -285,7 +284,7 @@ @@ -295,7 +294,7 @@ @@ -310,7 +309,7 @@ @@ -322,7 +321,7 @@ @@ -332,12 +331,12 @@ - + - @@ -360,7 +359,7 @@ @@ -371,7 +370,7 @@ @@ -382,7 +381,7 @@ @@ -393,18 +392,18 @@ SQL slash escaping when passed. https://github.com/WordPress/WordPress-Coding-Standards/issues/640 --> + + + - - - @@ -412,7 +411,7 @@ @@ -452,13 +451,23 @@ + is deprecated in PHP 7.2 and has been removed in PHP 8.0. ... these must not be used. --> + + + + @@ -475,7 +484,7 @@ From afeca3dc7094b77fe18864c083f0428f418afb90 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Wed, 24 Aug 2022 17:20:10 +0100 Subject: [PATCH 185/822] Update composer.json keywords As per getcomposer.org/doc/04-schema.md#keywords by including "static analysis", then later versions of Composer will prompt users if the package is installed with `composer require` instead of `composer require-dev`. --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 74b01ea39b..8f397a4e3d 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,7 @@ "keywords": [ "phpcs", "standards", + "static analysis", "WordPress" ], "license": "MIT", From 16d1af9a8cdcf4161f62d4593bd17b4b81f831bf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 8 Jun 2022 08:36:23 +0200 Subject: [PATCH 186/822] Composer/GH Actions: start using PHPCSDevTools 1.2.0 PHPCSDevTools 1.2.0 introduces an XSD for the XML docs which can accompany sniffs. This commit: * Updates the PHPCSDevTools to version 1.2.0. * Adds a new check against the XSD for all sniff XML Docs files. Ref: https://github.com/PHPCSStandards/PHPCSDevTools/releases/tag/1.2.0 --- .github/workflows/ruleset-checks-sniffs.yml | 6 +++++- composer.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index fddc940360..8d18a6d4ba 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -72,7 +72,7 @@ jobs: - name: Show PHPCS results in PR run: cs2pr ./phpcs-report.xml --graceful-warnings - # Validate the XML files. + # Validate the Ruleset XML files. # @link http://xmlsoft.org/xmllint.html - name: Validate the WordPress rulesets run: xmllint --noout --schema vendor/squizlabs/php_codesniffer/phpcs.xsd ./*/ruleset.xml @@ -80,6 +80,10 @@ jobs: - name: Validate the sample ruleset run: xmllint --noout --schema vendor/squizlabs/php_codesniffer/phpcs.xsd ./phpcs.xml.dist.sample + # Validate the Documentation XML files. + - name: Validate documentation against schema + run: xmllint --noout --schema vendor/phpcsstandards/phpcsdevtools/DocsXsd/phpcsdocs.xsd ./WordPress/Docs/*/*Standard.xml + - name: Check the code-style consistency of the xml files run: | diff -B --tabsize=4 ./WordPress/ruleset.xml <(xmllint --format "./WordPress/ruleset.xml") diff --git a/composer.json b/composer.json index 8f397a4e3d..6444787229 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "require-dev": { "phpcompatibility/php-compatibility": "^9.0", "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0", - "phpcsstandards/phpcsdevtools": "^1.0", + "phpcsstandards/phpcsdevtools": "^1.2.0", "php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-console-highlighter": "^1.0.0" }, From 49ef41141ed6f1db190aa311bb31f8f265ca4607 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 8 Jun 2022 08:44:38 +0200 Subject: [PATCH 187/822] Sniff XML docs: add schema to docs Includes minor tweaks to some of the titles. Includes adding the `` header if it didn't exist in the file. --- WordPress/Docs/Arrays/ArrayIndentationStandard.xml | 6 +++++- .../Docs/Arrays/ArrayKeySpacingRestrictionsStandard.xml | 6 +++++- WordPress/Docs/Arrays/CommaAfterArrayItemStandard.xml | 6 +++++- .../Docs/Arrays/MultipleStatementAlignmentStandard.xml | 6 +++++- WordPress/Docs/Classes/ClassInstantiationStandard.xml | 6 +++++- .../Docs/CodeAnalysis/EscapedNotTranslatedStandard.xml | 6 +++++- WordPress/Docs/DateTime/CurrentTimeTimestampStandard.xml | 6 +++++- WordPress/Docs/DateTime/RestrictedFunctionsStandard.xml | 6 +++++- .../Docs/NamingConventions/PrefixAllGlobalsStandard.xml | 6 +++++- WordPress/Docs/NamingConventions/ValidHookNameStandard.xml | 5 ++++- .../Docs/NamingConventions/ValidPostTypeSlugStandard.xml | 6 +++++- WordPress/Docs/PHP/IniSetStandard.xml | 6 +++++- WordPress/Docs/PHP/StrictInArrayStandard.xml | 6 +++++- WordPress/Docs/PHP/YodaConditionsStandard.xml | 6 +++++- WordPress/Docs/Security/SafeRedirectStandard.xml | 6 +++++- WordPress/Docs/WP/CapitalPDangitStandard.xml | 6 +++++- WordPress/Docs/WP/CronIntervalStandard.xml | 6 +++++- WordPress/Docs/WP/DeprecatedClassesStandard.xml | 6 +++++- WordPress/Docs/WP/DeprecatedFunctionsStandard.xml | 6 +++++- WordPress/Docs/WP/DeprecatedParameterValuesStandard.xml | 6 +++++- WordPress/Docs/WP/DeprecatedParametersStandard.xml | 6 +++++- WordPress/Docs/WP/EnqueuedResourceParametersStandard.xml | 6 +++++- WordPress/Docs/WP/EnqueuedResourcesStandard.xml | 6 +++++- WordPress/Docs/WP/PostsPerPageStandard.xml | 6 +++++- WordPress/Docs/WhiteSpace/CastStructureSpacingStandard.xml | 6 +++++- WordPress/Docs/WhiteSpace/OperatorSpacingStandard.xml | 6 +++++- WordPress/Docs/WhiteSpace/PrecisionAlignmentStandard.xml | 6 +++++- 27 files changed, 134 insertions(+), 27 deletions(-) diff --git a/WordPress/Docs/Arrays/ArrayIndentationStandard.xml b/WordPress/Docs/Arrays/ArrayIndentationStandard.xml index 5b9a1deea3..0833cce3bf 100644 --- a/WordPress/Docs/Arrays/ArrayIndentationStandard.xml +++ b/WordPress/Docs/Arrays/ArrayIndentationStandard.xml @@ -1,4 +1,8 @@ - + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Fri, 14 Oct 2022 22:28:21 +0200 Subject: [PATCH 188/822] GH Actions: fix use of deprecated `set-output` GitHub has deprecated the use of `set-output` (and `set-state`) in favour of new environment files. This commit updates workflows to use the new methodology. Refs: * https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ * https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files --- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/unit-tests.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index f7998e2909..ab5bd3457a 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -50,9 +50,9 @@ jobs: id: set_ini run: | if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then - echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT else - echo '::set-output name=PHP_INI::error_reporting=-1, display_errors=On' + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT fi - name: Set up PHP diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 5020375e05..8e96b835dc 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -56,9 +56,9 @@ jobs: id: set_ini run: | if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then - echo '::set-output name=PHP_INI::error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT else - echo '::set-output name=PHP_INI::error_reporting=-1, display_errors=On' + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT fi - name: Set up PHP From e670ed6b031b07b2a31653c50f84ee4ce34306d6 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 23 Oct 2022 11:06:01 +0200 Subject: [PATCH 189/822] GH Actions: harden the workflow against PHPCS ruleset errors If there is a ruleset error, the `cs2pr` action doesn't receive an `xml` report and exits with a `0` error code, even though the PHPCS run failed (though not on CS errors, but on a ruleset error). This changes the GH Actions workflow to allow for that situation and still fail the build in that case. --- .github/workflows/ruleset-checks-sniffs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index 8d18a6d4ba..1607297d6f 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -66,10 +66,11 @@ jobs: # @link https://github.com/WordPress/WordPress-Coding-Standards # @link http://pear.php.net/package/PHP_CodeSniffer/ - name: Run PHPCS ignoring warnings - continue-on-error: true + id: phpcs run: vendor/bin/phpcs --runtime-set ignore_warnings_on_exit 1 --report-full --report-checkstyle=./phpcs-report.xml - name: Show PHPCS results in PR + if: ${{ always() && steps.phpcs.outcome == 'failure' }} run: cs2pr ./phpcs-report.xml --graceful-warnings # Validate the Ruleset XML files. From a7f6cc6f0cbb223f9899ab2abd526072c8945307 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 24 Oct 2022 16:23:59 +0200 Subject: [PATCH 190/822] Composer: up the minimum PHPCS version to 3.7.1 Follow up on 2058 The minimum PHPCS version for PHPCSUtils 1.0.0 will be 3.7.1, so the minimum PHPCS version for WPCS should be in line with that. The difference between 3.7.0 and 3.7.1 is very small. They were released just days apart with 3.7.1 fixing a pertinent bug in the retokenization of reserved keywords, which was updated in PHPCS 3.7.0. Includes updating the GH Actions matrixes for this change. --- .github/CONTRIBUTING.md | 2 +- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/ruleset-checks-sniffs.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- README.md | 2 +- composer.json | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4acbf78a09..8b4acb11b9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -36,7 +36,7 @@ When you introduce new `public` sniff properties, or your sniff extends a class ## Pre-requisites * WordPress-Coding-Standards -* PHP_CodeSniffer 3.7.0 or higher +* PHP_CodeSniffer 3.7.1 or higher * PHPUnit 4.x, 5.x, 6.x or 7.x The WordPress Coding Standards use the `PHP_CodeSniffer` native unit test suite for unit testing the sniffs. diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index ab5bd3457a..cb23467085 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -36,9 +36,9 @@ jobs: phpcs_version: [ 'dev-master' ] include: - php: '7.3' - phpcs_version: '3.7.0' + phpcs_version: '3.7.1' - php: '5.4' - phpcs_version: '3.7.0' + phpcs_version: '3.7.1' steps: - name: Checkout repository diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index 1607297d6f..f359ed9ece 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -120,7 +120,7 @@ jobs: strategy: matrix: php: [ '7.4' ] - phpcs_version: [ 'dev-master', '3.7.0' ] + phpcs_version: [ 'dev-master', '3.7.1' ] steps: - name: Checkout repository diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 8e96b835dc..3ba3f940a0 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -35,7 +35,7 @@ jobs: strategy: matrix: php: [ '8.1', '8.0', '7.4', '7.3', '7.2', '7.1', '7.0', '5.6', '5.5', '5.4' ] - phpcs_version: [ 'dev-master', '3.7.0' ] + phpcs_version: [ 'dev-master', '3.7.1' ] allowed_failure: [ false ] include: # Add extra build to test against PHPCS 4. diff --git a/README.md b/README.md index 4043438803..c3669ff975 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ This project is a collection of [PHP_CodeSniffer](https://github.com/squizlabs/P ### Requirements -The WordPress Coding Standards require PHP 5.4 or higher and [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version **3.7.0** or higher. +The WordPress Coding Standards require PHP 5.4 or higher and [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version **3.7.1** or higher. ### Composer diff --git a/composer.json b/composer.json index 6444787229..cf7705a04a 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.7.0", + "squizlabs/php_codesniffer": "^3.7.1", "phpcsstandards/phpcsutils": "^1.0", "phpcsstandards/phpcsextra": "^1.0" }, From 9e770788d2121c332007775fd6b2ce6e9c48b09c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Apr 2022 11:32:41 +0200 Subject: [PATCH 191/822] EnqueuedResourcesSniff: use Collections method instead of property All the `Collections` class properties have been deprecated in PHPCSUtils 1.0.0-alph4 in favour of methods with the same name, due to too many new tokens being introduced in PHP itself and the properties therefor not being a viable path for the future. --- WordPress/Sniffs/WP/EnqueuedResourcesSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php index b462e20c3c..c1c45379de 100644 --- a/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php +++ b/WordPress/Sniffs/WP/EnqueuedResourcesSniff.php @@ -36,7 +36,7 @@ class EnqueuedResourcesSniff extends Sniff { * @return array */ public function register() { - $targets = Collections::$textStingStartTokens; + $targets = Collections::textStringStartTokens(); $targets[] = \T_INLINE_HTML; return $targets; From ad4bab4b8662cb16fcea3d0db61cdc54d28b4a20 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Apr 2022 13:52:52 +0200 Subject: [PATCH 192/822] CronInterval: add the parameter name to allow for named parameters PHPCSUtils 1.0.0-alpha4 supports named parameters in the `PassedParameters` class, but requires for the parameter name to be passed either as a string or an array (of multiple names in case of a renamed parameter). The `CronInterval` sniff not passing the parameter name would cause the tests to fail - even when the tests do not contain a test for named parameters yet -, so let's fix the function call. Note: this doesn't add proper support for named parameters to the sniff yet. That will be addressed later. --- WordPress/Sniffs/WP/CronIntervalSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/CronIntervalSniff.php b/WordPress/Sniffs/WP/CronIntervalSniff.php index 21ee0e9b87..38fa176885 100644 --- a/WordPress/Sniffs/WP/CronIntervalSniff.php +++ b/WordPress/Sniffs/WP/CronIntervalSniff.php @@ -98,7 +98,7 @@ public function process_token( $stackPtr ) { return; } - $callback = PassedParameters::getParameter( $this->phpcsFile, $functionPtr, 2 ); + $callback = PassedParameters::getParameter( $this->phpcsFile, $functionPtr, 2, 'callback' ); if ( false === $callback ) { return; } From 6eca312a13bd972be3e8211b90c309bde8cb60d7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Apr 2022 11:23:18 +0200 Subject: [PATCH 193/822] Sniff::addMessage(): switch over to the PHPCSUtils version PHPCSUtils 1.0.0-alpha4 has a new `MessageHelper` class containing methods for the same, so we can now switch out the WPCS native methods for the PHPCSUtils ones. Includes changing some long lines to multi-line function calls. --- ...stractArrayAssignmentRestrictionsSniff.php | 4 +- .../AbstractFunctionRestrictionsSniff.php | 6 +- WordPress/Sniff.php | 70 ------------------- .../PrefixAllGlobalsSniff.php | 6 +- .../Security/NonceVerificationSniff.php | 4 +- .../Sniffs/WP/DeprecatedClassesSniff.php | 4 +- .../Sniffs/WP/DeprecatedFunctionsSniff.php | 4 +- .../WP/DeprecatedParameterValuesSniff.php | 4 +- .../Sniffs/WP/DeprecatedParametersSniff.php | 3 +- WordPress/Sniffs/WP/I18nSniff.php | 38 ++++++++-- 10 files changed, 56 insertions(+), 87 deletions(-) diff --git a/WordPress/AbstractArrayAssignmentRestrictionsSniff.php b/WordPress/AbstractArrayAssignmentRestrictionsSniff.php index df9932bb7d..5dbf9562bd 100644 --- a/WordPress/AbstractArrayAssignmentRestrictionsSniff.php +++ b/WordPress/AbstractArrayAssignmentRestrictionsSniff.php @@ -9,6 +9,7 @@ namespace WordPressCS\WordPress; +use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\Sniff; @@ -212,7 +213,8 @@ public function process_token( $stackPtr ) { $message = $output; } - $this->addMessage( + MessageHelper::addMessage( + $this->phpcsFile, $message, $stackPtr, ( 'error' === $group['type'] ), diff --git a/WordPress/AbstractFunctionRestrictionsSniff.php b/WordPress/AbstractFunctionRestrictionsSniff.php index af8cd10b18..1599a74b38 100644 --- a/WordPress/AbstractFunctionRestrictionsSniff.php +++ b/WordPress/AbstractFunctionRestrictionsSniff.php @@ -9,8 +9,9 @@ namespace WordPressCS\WordPress; -use WordPressCS\WordPress\Sniff; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Utils\MessageHelper; +use WordPressCS\WordPress\Sniff; /** * Restricts usage of some functions. @@ -310,7 +311,8 @@ public function check_for_matches( $stackPtr ) { */ public function process_matched_token( $stackPtr, $group_name, $matched_content ) { - $this->addMessage( + MessageHelper::addMessage( + $this->phpcsFile, $this->groups[ $group_name ]['message'], $stackPtr, ( 'error' === $this->groups[ $group_name ]['type'] ), diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index c54d6c23c4..89d3f6e439 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -845,76 +845,6 @@ protected function init( File $phpcsFile ) { $this->tokens = $phpcsFile->getTokens(); } - /** - * Add a PHPCS message to the output stack as either a warning or an error. - * - * @since 0.11.0 - * - * @param string $message The message. - * @param int $stackPtr The position of the token the message relates to. - * @param bool $is_error Optional. Whether to report the message as an 'error' or 'warning'. - * Defaults to true (error). - * @param string $code Optional error code for the message. Defaults to 'Found'. - * @param array $data Optional input for the data replacements. - * @param int $severity Optional. Severity level. Defaults to 0 which will translate to - * the PHPCS default severity level. - * @return bool - */ - protected function addMessage( $message, $stackPtr, $is_error = true, $code = 'Found', $data = array(), $severity = 0 ) { - return $this->throwMessage( $message, $stackPtr, $is_error, $code, $data, $severity, false ); - } - - /** - * Add a fixable PHPCS message to the output stack as either a warning or an error. - * - * @since 0.11.0 - * - * @param string $message The message. - * @param int $stackPtr The position of the token the message relates to. - * @param bool $is_error Optional. Whether to report the message as an 'error' or 'warning'. - * Defaults to true (error). - * @param string $code Optional error code for the message. Defaults to 'Found'. - * @param array $data Optional input for the data replacements. - * @param int $severity Optional. Severity level. Defaults to 0 which will translate to - * the PHPCS default severity level. - * @return bool - */ - protected function addFixableMessage( $message, $stackPtr, $is_error = true, $code = 'Found', $data = array(), $severity = 0 ) { - return $this->throwMessage( $message, $stackPtr, $is_error, $code, $data, $severity, true ); - } - - /** - * Add a PHPCS message to the output stack as either a warning or an error. - * - * @since 0.11.0 - * - * @param string $message The message. - * @param int $stackPtr The position of the token the message relates to. - * @param bool $is_error Optional. Whether to report the message as an 'error' or 'warning'. - * Defaults to true (error). - * @param string $code Optional error code for the message. Defaults to 'Found'. - * @param array $data Optional input for the data replacements. - * @param int $severity Optional. Severity level. Defaults to 0 which will translate to - * the PHPCS default severity level. - * @param bool $fixable Optional. Whether this is a fixable error. Defaults to false. - * @return bool - */ - private function throwMessage( $message, $stackPtr, $is_error = true, $code = 'Found', $data = array(), $severity = 0, $fixable = false ) { - - $method = 'add'; - if ( true === $fixable ) { - $method .= 'Fixable'; - } - - if ( true === $is_error ) { - $method .= 'Error'; - } else { - $method .= 'Warning'; - } - - return \call_user_func( array( $this->phpcsFile, $method ), $message, $stackPtr, $code, $data, $severity ); - } - /** * Convert an arbitrary string to an alphanumeric string with underscores. * diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index 616f89a723..fd23a0c47d 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -12,6 +12,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Utils\Lists; +use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\Namespaces; use PHPCSUtils\Utils\Scopes; use PHPCSUtils\Utils\TextStrings; @@ -741,7 +742,8 @@ protected function process_variable_assignment( $stackPtr, $in_list = false ) { } // Still here ? In that case, the variable name should be prefixed. - $recorded = $this->addMessage( + $recorded = MessageHelper::addMessage( + $this->phpcsFile, self::ERROR_MSG, $stackPtr, $is_error, @@ -885,7 +887,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $data[] = $raw_content; - $recorded = $this->addMessage( self::ERROR_MSG, $first_non_empty, $is_error, $error_code, $data ); + $recorded = MessageHelper::addMessage( $this->phpcsFile, self::ERROR_MSG, $first_non_empty, $is_error, $error_code, $data ); if ( true === $recorded ) { $this->record_potential_prefix_metric( $stackPtr, $raw_content ); diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php index 934ff8004d..2784b363c9 100644 --- a/WordPress/Sniffs/Security/NonceVerificationSniff.php +++ b/WordPress/Sniffs/Security/NonceVerificationSniff.php @@ -9,6 +9,7 @@ namespace WordPressCS\WordPress\Sniffs\Security; +use PHPCSUtils\Utils\MessageHelper; use WordPressCS\WordPress\Sniff; /** @@ -127,7 +128,8 @@ public function process_token( $stackPtr ) { } // If we're still here, no nonce-verification function was found. - $this->addMessage( + MessageHelper::addMessage( + $this->phpcsFile, 'Processing form data without nonce verification.', $stackPtr, $this->superglobals[ $instance['content'] ], diff --git a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php index 25c6e8cbdd..dd7418b3b8 100644 --- a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php @@ -9,6 +9,7 @@ namespace WordPressCS\WordPress\Sniffs\WP; +use PHPCSUtils\Utils\MessageHelper; use WordPressCS\WordPress\AbstractClassRestrictionsSniff; use WordPressCS\WordPress\Helpers\MinimumWPVersionTrait; @@ -111,7 +112,8 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $data[] = $this->deprecated_classes[ $class_name ]['alt']; } - $this->addMessage( + MessageHelper::addMessage( + $this->phpcsFile, $message, $stackPtr, ( version_compare( $this->deprecated_classes[ $class_name ]['version'], $this->minimum_supported_version, '<' ) ), diff --git a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php index 2676c82dcb..4430d67731 100644 --- a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php @@ -9,6 +9,7 @@ namespace WordPressCS\WordPress\Sniffs\WP; +use PHPCSUtils\Utils\MessageHelper; use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; use WordPressCS\WordPress\Helpers\MinimumWPVersionTrait; @@ -1413,7 +1414,8 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $data[] = $this->deprecated_functions[ $function_name ]['alt']; } - $this->addMessage( + MessageHelper::addMessage( + $this->phpcsFile, $message, $stackPtr, ( version_compare( $this->deprecated_functions[ $function_name ]['version'], $this->minimum_supported_version, '<' ) ), diff --git a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php index 7ad4904fcb..5ac9508331 100644 --- a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php @@ -10,6 +10,7 @@ namespace WordPressCS\WordPress\Sniffs\WP; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\AbstractFunctionParameterSniff; use WordPressCS\WordPress\Helpers\MinimumWPVersionTrait; @@ -208,7 +209,8 @@ protected function process_parameter( $matched_content, $parameter, $parameter_a } $is_error = version_compare( $parameter_args[ $matched_parameter ]['version'], $this->minimum_supported_version, '<' ); - $this->addMessage( + MessageHelper::addMessage( + $this->phpcsFile, $message, $parameter_position, $is_error, diff --git a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php index ca6114526f..6beae0163e 100644 --- a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php @@ -9,6 +9,7 @@ namespace WordPressCS\WordPress\Sniffs\WP; +use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\AbstractFunctionParameterSniff; use WordPressCS\WordPress\Helpers\MinimumWPVersionTrait; @@ -335,7 +336,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $message .= ' Instead do not pass the parameter.'; } - $this->addMessage( $message, $stackPtr, $is_error, $code, $data, 0 ); + MessageHelper::addMessage( $this->phpcsFile, $message, $stackPtr, $is_error, $code, $data, 0 ); } } diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 8dd700ae0d..5b61c86c13 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\TextStrings; use XMLReader; use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; @@ -433,7 +434,7 @@ protected function check_argument_tokens( $context ) { if ( empty( $tokens ) || 0 === \count( $tokens ) ) { $code = $this->string_to_errorcode( 'MissingArg' . ucfirst( $arg_name ) ); if ( 'domain' !== $arg_name ) { - $this->addMessage( 'Missing $%s arg.', $stack_ptr, $is_error, $code, array( $arg_name ) ); + MessageHelper::addMessage( $this->phpcsFile, 'Missing $%s arg.', $stack_ptr, $is_error, $code, array( $arg_name ) ); return false; } @@ -450,7 +451,7 @@ protected function check_argument_tokens( $context ) { array( $arg_name ) ); } elseif ( ! empty( $this->text_domain ) ) { - $this->addMessage( 'Missing $%s arg.', $stack_ptr, $is_error, $code, array( $arg_name ) ); + MessageHelper::addMessage( $this->phpcsFile, 'Missing $%s arg.', $stack_ptr, $is_error, $code, array( $arg_name ) ); } return false; @@ -462,7 +463,14 @@ protected function check_argument_tokens( $context ) { $contents .= $token['content']; } $code = $this->string_to_errorcode( 'NonSingularStringLiteral' . ucfirst( $arg_name ) ); - $this->addMessage( 'The $%s arg must be a single string literal, not "%s".', $stack_ptr, $is_error, $code, array( $arg_name, $contents ) ); + MessageHelper::addMessage( + $this->phpcsFile, + 'The $%s arg must be a single string literal, not "%s".', + $stack_ptr, + $is_error, + $code, + array( $arg_name, $contents ) + ); return false; } @@ -474,7 +482,14 @@ protected function check_argument_tokens( $context ) { $interpolated_variables = TextStringHelper::get_interpolated_variables( $content ); foreach ( $interpolated_variables as $interpolated_variable ) { $code = $this->string_to_errorcode( 'InterpolatedVariable' . ucfirst( $arg_name ) ); - $this->addMessage( 'The $%s arg must not contain interpolated variables. Found "$%s".', $stack_ptr, $is_error, $code, array( $arg_name, $interpolated_variable ) ); + MessageHelper::addMessage( + $this->phpcsFile, + 'The $%s arg must not contain interpolated variables. Found "$%s".', + $stack_ptr, + $is_error, + $code, + array( $arg_name, $interpolated_variable ) + ); } if ( ! empty( $interpolated_variables ) ) { return false; @@ -486,7 +501,8 @@ protected function check_argument_tokens( $context ) { $stripped_content = TextStrings::stripQuotes( $content ); if ( ! \in_array( $stripped_content, $this->text_domain, true ) ) { - $this->addMessage( + MessageHelper::addMessage( + $this->phpcsFile, 'Mismatched text domain. Expected \'%s\' but got %s.', $stack_ptr, $is_error, @@ -531,7 +547,14 @@ protected function check_argument_tokens( $context ) { } $code = $this->string_to_errorcode( 'NonSingularStringLiteral' . ucfirst( $arg_name ) ); - $this->addMessage( 'The $%s arg must be a single string literal, not "%s".', $stack_ptr, $is_error, $code, array( $arg_name, $content ) ); + MessageHelper::addMessage( + $this->phpcsFile, + 'The $%s arg must be a single string literal, not "%s".', + $stack_ptr, + $is_error, + $code, + array( $arg_name, $content ) + ); return false; } @@ -616,7 +639,8 @@ protected function check_text( $context ) { $replacements[ $i ] = str_replace( '$', '\\$', $replacements[ $i ] ); } - $fix = $this->addFixableMessage( + $fix = MessageHelper::addFixableMessage( + $this->phpcsFile, 'Multiple placeholders should be ordered. Expected \'%s\', but got %s.', $stack_ptr, $is_error, From b812a91b37f6962ee55a215b376b0982c81a3dfc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Apr 2022 14:07:39 +0200 Subject: [PATCH 194/822] Sniff::string_to_errorcode(): switch over to the PHPCSUtils version PHPCSUtils 1.0.0-alpha4 has a new `MessageHelper` class containing a method for the same, so we can now switch out the WPCS native method for the PHPCSUtils one. --- .../AbstractArrayAssignmentRestrictionsSniff.php | 2 +- WordPress/AbstractFunctionRestrictionsSniff.php | 2 +- WordPress/Sniff.php | 15 --------------- WordPress/Sniffs/PHP/IniSetSniff.php | 3 ++- WordPress/Sniffs/WP/DeprecatedClassesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php | 2 +- .../Sniffs/WP/DeprecatedParameterValuesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedParametersSniff.php | 2 +- WordPress/Sniffs/WP/DiscouragedConstantsSniff.php | 5 +++-- WordPress/Sniffs/WP/I18nSniff.php | 12 ++++++------ 10 files changed, 17 insertions(+), 30 deletions(-) diff --git a/WordPress/AbstractArrayAssignmentRestrictionsSniff.php b/WordPress/AbstractArrayAssignmentRestrictionsSniff.php index 5dbf9562bd..18912c96c4 100644 --- a/WordPress/AbstractArrayAssignmentRestrictionsSniff.php +++ b/WordPress/AbstractArrayAssignmentRestrictionsSniff.php @@ -218,7 +218,7 @@ public function process_token( $stackPtr ) { $message, $stackPtr, ( 'error' === $group['type'] ), - $this->string_to_errorcode( $groupName . '_' . $key ), + MessageHelper::stringToErrorcode( $groupName . '_' . $key ), array( $key, $val ) ); } diff --git a/WordPress/AbstractFunctionRestrictionsSniff.php b/WordPress/AbstractFunctionRestrictionsSniff.php index 1599a74b38..67c3f80787 100644 --- a/WordPress/AbstractFunctionRestrictionsSniff.php +++ b/WordPress/AbstractFunctionRestrictionsSniff.php @@ -316,7 +316,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $this->groups[ $group_name ]['message'], $stackPtr, ( 'error' === $this->groups[ $group_name ]['type'] ), - $this->string_to_errorcode( $group_name . '_' . $matched_content ), + MessageHelper::stringToErrorcode( $group_name . '_' . $matched_content ), array( $matched_content ) ); } diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 89d3f6e439..6f4d272c37 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -845,21 +845,6 @@ protected function init( File $phpcsFile ) { $this->tokens = $phpcsFile->getTokens(); } - /** - * Convert an arbitrary string to an alphanumeric string with underscores. - * - * Pre-empt issues with arbitrary strings being used as error codes in XML and PHP. - * - * @since 0.11.0 - * - * @param string $base_string Arbitrary string. - * - * @return string - */ - protected function string_to_errorcode( $base_string ) { - return preg_replace( '`[^a-z0-9_]`i', '_', $base_string ); - } - /** * Transform the name of a PHP construct (function, variable etc) to one in snake_case. * diff --git a/WordPress/Sniffs/PHP/IniSetSniff.php b/WordPress/Sniffs/PHP/IniSetSniff.php index 62ff297460..350b5ab4d4 100644 --- a/WordPress/Sniffs/PHP/IniSetSniff.php +++ b/WordPress/Sniffs/PHP/IniSetSniff.php @@ -9,6 +9,7 @@ namespace WordPressCS\WordPress\Sniffs\PHP; +use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\AbstractFunctionParameterSniff; @@ -156,7 +157,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $this->phpcsFile->addError( '%s(%s, %s) found. %s', $stackPtr, - $this->string_to_errorcode( $option_name . '_Disallowed' ), + MessageHelper::stringToErrorcode( $option_name . '_Disallowed' ), array( $matched_content, $parameters[1]['raw'], diff --git a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php index dd7418b3b8..71a2d84f40 100644 --- a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php @@ -117,7 +117,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $message, $stackPtr, ( version_compare( $this->deprecated_classes[ $class_name ]['version'], $this->minimum_supported_version, '<' ) ), - $this->string_to_errorcode( $class_name . 'Found' ), + MessageHelper::stringToErrorcode( $class_name . 'Found' ), $data ); } diff --git a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php index 4430d67731..edb06e26c9 100644 --- a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php @@ -1419,7 +1419,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $message, $stackPtr, ( version_compare( $this->deprecated_functions[ $function_name ]['version'], $this->minimum_supported_version, '<' ) ), - $this->string_to_errorcode( $matched_content . 'Found' ), + MessageHelper::stringToErrorcode( $matched_content . 'Found' ), $data ); } diff --git a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php index 5ac9508331..a31ec00e2e 100644 --- a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php @@ -214,7 +214,7 @@ protected function process_parameter( $matched_content, $parameter, $parameter_a $message, $parameter_position, $is_error, - $this->string_to_errorcode( 'Found' ), + 'Found', $data ); } diff --git a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php index 6beae0163e..770cb31ccd 100644 --- a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php @@ -320,7 +320,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $message = 'The parameter "%s" at position #%s of %s() has been deprecated since WordPress version %s.'; $is_error = version_compare( $parameter_args['version'], $this->minimum_supported_version, '<' ); - $code = $this->string_to_errorcode( ucfirst( $matched_content ) . 'Param' . $position . 'Found' ); + $code = MessageHelper::stringToErrorcode( ucfirst( $matched_content ) . 'Param' . $position . 'Found' ); $data = array( $parameters[ $position ]['raw'], diff --git a/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php b/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php index 9d4137d914..f300a2a3bc 100644 --- a/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php +++ b/WordPress/Sniffs/WP/DiscouragedConstantsSniff.php @@ -11,6 +11,7 @@ use WordPressCS\WordPress\AbstractFunctionParameterSniff; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\Scopes; use PHPCSUtils\Utils\TextStrings; @@ -172,7 +173,7 @@ public function process_arbitrary_tstring( $stackPtr ) { $this->phpcsFile->addWarning( 'Found usage of constant "%s". Use %s instead.', $stackPtr, - $this->string_to_errorcode( $content . 'UsageFound' ), + MessageHelper::stringToErrorcode( $content . 'UsageFound' ), array( $content, $this->discouraged_constants[ $content ], @@ -207,7 +208,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p $this->phpcsFile->addWarning( 'Found declaration of constant "%s". Use %s instead.', $stackPtr, - $this->string_to_errorcode( $raw_content . 'DeclarationFound' ), + MessageHelper::stringToErrorcode( $raw_content . 'DeclarationFound' ), array( $raw_content, $this->discouraged_constants[ $raw_content ], diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 5b61c86c13..1afa213427 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -432,7 +432,7 @@ protected function check_argument_tokens( $context ) { $content = isset( $tokens[0] ) ? $tokens[0]['content'] : ''; if ( empty( $tokens ) || 0 === \count( $tokens ) ) { - $code = $this->string_to_errorcode( 'MissingArg' . ucfirst( $arg_name ) ); + $code = MessageHelper::stringToErrorcode( 'MissingArg' . ucfirst( $arg_name ) ); if ( 'domain' !== $arg_name ) { MessageHelper::addMessage( $this->phpcsFile, 'Missing $%s arg.', $stack_ptr, $is_error, $code, array( $arg_name ) ); return false; @@ -462,7 +462,7 @@ protected function check_argument_tokens( $context ) { foreach ( $tokens as $token ) { $contents .= $token['content']; } - $code = $this->string_to_errorcode( 'NonSingularStringLiteral' . ucfirst( $arg_name ) ); + $code = MessageHelper::stringToErrorcode( 'NonSingularStringLiteral' . ucfirst( $arg_name ) ); MessageHelper::addMessage( $this->phpcsFile, 'The $%s arg must be a single string literal, not "%s".', @@ -481,7 +481,7 @@ protected function check_argument_tokens( $context ) { if ( \T_DOUBLE_QUOTED_STRING === $tokens[0]['code'] || \T_HEREDOC === $tokens[0]['code'] ) { $interpolated_variables = TextStringHelper::get_interpolated_variables( $content ); foreach ( $interpolated_variables as $interpolated_variable ) { - $code = $this->string_to_errorcode( 'InterpolatedVariable' . ucfirst( $arg_name ) ); + $code = MessageHelper::stringToErrorcode( 'InterpolatedVariable' . ucfirst( $arg_name ) ); MessageHelper::addMessage( $this->phpcsFile, 'The $%s arg must not contain interpolated variables. Found "$%s".', @@ -546,7 +546,7 @@ protected function check_argument_tokens( $context ) { return true; } - $code = $this->string_to_errorcode( 'NonSingularStringLiteral' . ucfirst( $arg_name ) ); + $code = MessageHelper::stringToErrorcode( 'NonSingularStringLiteral' . ucfirst( $arg_name ) ); MessageHelper::addMessage( $this->phpcsFile, 'The $%s arg must be a single string literal, not "%s".', @@ -612,7 +612,7 @@ protected function check_text( $context ) { $all_matches_count = preg_match_all( self::SPRINTF_PLACEHOLDER_REGEX, $content, $all_matches ); if ( $unordered_matches_count > 0 && $unordered_matches_count !== $all_matches_count && $all_matches_count > 1 ) { - $code = $this->string_to_errorcode( 'MixedOrderedPlaceholders' . ucfirst( $arg_name ) ); + $code = MessageHelper::stringToErrorcode( 'MixedOrderedPlaceholders' . ucfirst( $arg_name ) ); $this->phpcsFile->addError( 'Multiple placeholders should be ordered. Mix of ordered and non-ordered placeholders found. Found: %s.', $stack_ptr, @@ -621,7 +621,7 @@ protected function check_text( $context ) { ); } elseif ( $unordered_matches_count >= 2 ) { - $code = $this->string_to_errorcode( 'UnorderedPlaceholders' . ucfirst( $arg_name ) ); + $code = MessageHelper::stringToErrorcode( 'UnorderedPlaceholders' . ucfirst( $arg_name ) ); $suggestions = array(); $replace_regexes = array(); From 2c52e9b6ab395793e9831327a02c13461c7f2325 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 18 Jun 2022 06:15:28 +0200 Subject: [PATCH 195/822] TextStringHelper: remove the strip_interpolated_variables() method ... in favour of the significantly more comprehensive PHPCSUtils `TextStrings::stripEmbeds()` method. This improves the handling of embedded variables in double quoted strings (and consequently fixes some bugs). Bug confirmed via the tests added to the `ValidPostTypeSlug` sniff. Without this fix, the "text stripped of embeds" for these test cases would look like this: ``` string(24) "testing123-${(foo)}-test" string(19) "testing123-"]}-test" ``` I.e. the embeds wouldn't be, or wouldn't be completely, stripped. With the fix, the embeds in both texts are correctly stripped, resulting in: ``` string(16) "testing123--test" ``` As for the sniff, for the `ValidPostTypeSlug` sniff, the bug meant that the sniff would report three false positives: ``` 55 | ERROR | register_post_type() called with invalid post type "testing123-${(foo)}-test". Post type contains invalid characters. Only lowercase | | alphanumeric characters, dashes, and underscores are allowed. 55 | ERROR | A post type slug must not exceed 20 characters. Found: "testing123-${(foo)}-test" (24 characters). 56 | ERROR | register_post_type() called with invalid post type "testing123-${foo["${bar['baz']}"]}-test". Post type contains invalid characters. | | Only lowercase alphanumeric characters, dashes, and underscores are allowed. ``` These are all fixed now. --- WordPress/Helpers/TextStringHelper.php | 35 ++----------------- .../DB/PreparedSQLPlaceholdersSniff.php | 2 +- .../ValidPostTypeSlugSniff.php | 3 +- .../ValidPostTypeSlugUnitTest.inc | 4 +++ .../ValidPostTypeSlugUnitTest.php | 2 ++ 5 files changed, 10 insertions(+), 36 deletions(-) diff --git a/WordPress/Helpers/TextStringHelper.php b/WordPress/Helpers/TextStringHelper.php index 9246835280..4c701d8ffb 100644 --- a/WordPress/Helpers/TextStringHelper.php +++ b/WordPress/Helpers/TextStringHelper.php @@ -21,21 +21,11 @@ * the future by functions from PHPCSUtils.} * * @package WPCS\WordPressCodingStandards - * @since 3.0.0 The constant and methods in this class were previously contained in the - * `WordPressCS\WordPress\Sniff` class and have been moved here. + * @since 3.0.0 The method in this class was previously contained in the + * `WordPressCS\WordPress\Sniff` class and has been moved here. */ final class TextStringHelper { - /** - * Regex to get complex variables from T_DOUBLE_QUOTED_STRING or T_HEREDOC. - * - * @since 0.14.0 - * @since 3.0.0 Moved from the Sniff class to this class. - * - * @var string - */ - const REGEX_COMPLEX_VARS = '`(?:(\{)?(?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(?:->\$?(?P>varname)|\[[^\]]+\]|::\$?(?P>varname)|\([^\)]*\))*(?(3)\}|)(?(2)\}|)(?(1)\}|)`'; - /** * Get the interpolated variable names from a string. * @@ -60,25 +50,4 @@ public static function get_interpolated_variables( $string ) { } return $variables; } - - /** - * Strip variables from an arbitrary double quoted/heredoc string. - * - * Intended for use with the contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. - * - * @since 0.14.0 - * @since 3.0.0 - Moved from the Sniff class to this class. - * - The method was made `static`. - * - * @param string $string The raw string. - * - * @return string String without variables in it. - */ - public static function strip_interpolated_variables( $string ) { - if ( strpos( $string, '$' ) === false ) { - return $string; - } - - return preg_replace( self::REGEX_COMPLEX_VARS, '', $string ); - } } diff --git a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php index fde54a9ce7..d85d09e9aa 100644 --- a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php @@ -275,7 +275,7 @@ public function process_token( $stackPtr ) { || \T_HEREDOC === $this->tokens[ $i ]['code'] ) { // Only interested in actual query text, so strip out variables. - $stripped_content = TextStringHelper::strip_interpolated_variables( $content ); + $stripped_content = TextStrings::stripEmbeds( $content ); if ( $stripped_content !== $content ) { $interpolated_vars = TextStringHelper::get_interpolated_variables( $content ); $vars_without_wpdb = array_diff( $interpolated_vars, array( 'wpdb' ) ); diff --git a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php index 0d76b5c74b..28234dc4f4 100644 --- a/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php +++ b/WordPress/Sniffs/NamingConventions/ValidPostTypeSlugSniff.php @@ -12,7 +12,6 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\AbstractFunctionParameterSniff; -use WordPressCS\WordPress\Helpers\TextStringHelper; /** * Validates post type names. @@ -163,7 +162,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p 'PartiallyDynamic', $data ); - $post_type = TextStringHelper::strip_interpolated_variables( $post_type ); + $post_type = TextStrings::stripEmbeds( $post_type ); } if ( preg_match( self::VALID_POST_TYPE_CHARACTERS, $post_type ) === 0 ) { diff --git a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.inc b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.inc index fa9d4dcfa8..d110c3cfbc 100644 --- a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.inc +++ b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.inc @@ -50,3 +50,7 @@ register_post_type( "my-own-post-type-too-long-{$i}" ); // 1x Error, Too long. 1 register_post_type( 'my/own/post/type/too/long', array() ); // Bad. Invalid chars: "/" and too long. register_post_type( 'wp_block', array() ); // Bad. Must only error on reserved keyword, not invalid prefix. + +// Test handling of more complex embedded variables and expressions. +register_post_type("testing123-${(foo)}-test"); +register_post_type("testing123-${foo["${bar['baz']}"]}-test"); diff --git a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php index 12bdf3b9a9..e24c12ea59 100644 --- a/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php +++ b/WordPress/Tests/NamingConventions/ValidPostTypeSlugUnitTest.php @@ -71,6 +71,8 @@ public function getWarningList() { 40 => 1, 45 => 1, 49 => 1, + 55 => 1, + 56 => 1, ); } } From 73c09b61848120bf60935987a9eaf0eecf25392f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Apr 2022 15:11:20 +0200 Subject: [PATCH 196/822] Sniff::is_foreach_as(): switch over to the PHPCSUtils version PHPCSUtils 1.0.0-alpha4 has a new `Context` class containing a more versatile method for the same, so we can now switch out the WPCS native method for the PHPCSUtils one. --- WordPress/Sniff.php | 35 ------------------- .../PrefixAllGlobalsSniff.php | 3 +- .../WP/GlobalVariablesOverrideSniff.php | 5 +-- 3 files changed, 5 insertions(+), 38 deletions(-) diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php index 6f4d272c37..4ddd616336 100644 --- a/WordPress/Sniff.php +++ b/WordPress/Sniff.php @@ -2005,41 +2005,6 @@ public function is_use_of_global_constant( $stackPtr ) { return true; } - /** - * Determine if a variable is in the `as $key => $value` part of a foreach condition. - * - * @since 1.0.0 - * @since 1.1.0 Moved from the PrefixAllGlobals sniff to the Sniff base class. - * - * @param int $stackPtr Pointer to the variable. - * - * @return bool True if it is. False otherwise. - */ - protected function is_foreach_as( $stackPtr ) { - if ( ! isset( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) { - return false; - } - - $nested_parenthesis = $this->tokens[ $stackPtr ]['nested_parenthesis']; - $close_parenthesis = end( $nested_parenthesis ); - $open_parenthesis = key( $nested_parenthesis ); - if ( ! isset( $this->tokens[ $close_parenthesis ]['parenthesis_owner'] ) ) { - return false; - } - - if ( \T_FOREACH !== $this->tokens[ $this->tokens[ $close_parenthesis ]['parenthesis_owner'] ]['code'] ) { - return false; - } - - $as_ptr = $this->phpcsFile->findNext( \T_AS, ( $open_parenthesis + 1 ), $close_parenthesis ); - if ( false === $as_ptr ) { - // Should never happen. - return false; - } - - return ( $stackPtr > $as_ptr ); - } - /** * Get a list of the token pointers to the variables being assigned to in a list statement. * diff --git a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php index fd23a0c47d..45d7749eaa 100644 --- a/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php +++ b/WordPress/Sniffs/NamingConventions/PrefixAllGlobalsSniff.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Utils\Context; use PHPCSUtils\Utils\Lists; use PHPCSUtils\Utils\MessageHelper; use PHPCSUtils\Utils\Namespaces; @@ -629,7 +630,7 @@ protected function process_variable_assignment( $stackPtr, $in_list = false ) { */ if ( false === $in_list && false === $this->is_assignment( $stackPtr ) - && false === $this->is_foreach_as( $stackPtr ) + && Context::inForeachCondition( $this->phpcsFile, $stackPtr ) !== 'afterAs' ) { return; } diff --git a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php index fb3f05f7d1..bcec93624d 100644 --- a/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php +++ b/WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php @@ -10,6 +10,7 @@ namespace WordPressCS\WordPress\Sniffs\WP; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Utils\Context; use PHPCSUtils\Utils\Lists; use PHPCSUtils\Utils\Scopes; use PHPCSUtils\Utils\TextStrings; @@ -265,7 +266,7 @@ protected function process_variable_assignment( $stackPtr, $in_list = false ) { */ if ( false === $in_list && false === $this->is_assignment( $stackPtr ) - && false === $this->is_foreach_as( $stackPtr ) + && Context::inForeachCondition( $this->phpcsFile, $stackPtr ) !== 'afterAs' ) { return; } @@ -418,7 +419,7 @@ protected function process_global_statement( $stackPtr, $in_function_scope ) { } // Check if this is a variable assignment within a `foreach()` declaration. - if ( $this->is_foreach_as( $ptr ) === true ) { + if ( Context::inForeachCondition( $this->phpcsFile, $ptr ) === 'afterAs' ) { $this->add_error( $ptr ); } } From aa0c9923aab453c2acee0f986342144b010ad6c9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 18 Jun 2022 06:46:28 +0200 Subject: [PATCH 197/822] WP/I18n: use PHPCSUtils for checking string embeds Switch out the use of the WPCS native `TextStringHelper::get_interpolated_variables()` method in favour of the significantly more comprehensive PHPCSUtils `TextStrings::getEmbeds()` method. This improves the handling of embedded variables in double quoted strings (and consequently fixes some bugs). For some samples of embedded variables/expressions, the sniff would previously correctly report on the embed, but would contain an incomplete representation of the embed in the error message: ``` 223 | ERROR | [ ] The $text arg must not contain interpolated variables. Found "$foo". 224 | ERROR | [ ] The $text arg must not contain interpolated variables. Found "$foo". 225 | ERROR | [ ] The $text arg must not contain interpolated variables. Found "$foo". ``` For other embedded variables/expressions, the sniff would previously not throw an error (false negative). ```php // No error, while an error should be thrown. __( "{$foo['bar']->baz()()}", 'my-slug' ); __( "${foo->bar}", 'my-slug' ); __( "${foo["${bar['baz']}"]}", 'my-slug' ); ``` With the implemented fix, all embeds will now result in the expected error and the error messages will contain a correct representation of the embed: ``` 222 | ERROR | [ ] The $text arg must not contain interpolated variables or expressions. Found "${foo}". 223 | ERROR | [ ] The $text arg must not contain interpolated variables or expressions. Found "{$foo['bar']}". 224 | ERROR | [ ] The $text arg must not contain interpolated variables or expressions. Found "{$foo->bar()}". 225 | ERROR | [ ] The $text arg must not contain interpolated variables or expressions. Found "{$foo['bar']->baz()()}". 226 | ERROR | [ ] The $text arg must not contain interpolated variables or expressions. Found "${foo->bar}". 227 | ERROR | [ ] The $text arg must not contain interpolated variables or expressions. Found "${foo["${bar['baz']}"]}". ``` Includes minor improvement to the error message. To prevent an unnecessary BC-break, I'm electing not to change the error code. --- WordPress/Sniffs/WP/I18nSniff.php | 5 ++--- WordPress/Tests/WP/I18nUnitTest.1.inc | 8 ++++++++ WordPress/Tests/WP/I18nUnitTest.1.inc.fixed | 8 ++++++++ WordPress/Tests/WP/I18nUnitTest.php | 6 ++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/WP/I18nSniff.php b/WordPress/Sniffs/WP/I18nSniff.php index 1afa213427..b072883dbc 100644 --- a/WordPress/Sniffs/WP/I18nSniff.php +++ b/WordPress/Sniffs/WP/I18nSniff.php @@ -15,7 +15,6 @@ use PHPCSUtils\Utils\TextStrings; use XMLReader; use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; -use WordPressCS\WordPress\Helpers\TextStringHelper; /** * Makes sure WP internationalization functions are used properly. @@ -479,12 +478,12 @@ protected function check_argument_tokens( $context ) { } if ( \T_DOUBLE_QUOTED_STRING === $tokens[0]['code'] || \T_HEREDOC === $tokens[0]['code'] ) { - $interpolated_variables = TextStringHelper::get_interpolated_variables( $content ); + $interpolated_variables = TextStrings::getEmbeds( $content ); foreach ( $interpolated_variables as $interpolated_variable ) { $code = MessageHelper::stringToErrorcode( 'InterpolatedVariable' . ucfirst( $arg_name ) ); MessageHelper::addMessage( $this->phpcsFile, - 'The $%s arg must not contain interpolated variables. Found "$%s".', + 'The $%s arg must not contain interpolated variables or expressions. Found "%s".', $stack_ptr, $is_error, $code, diff --git a/WordPress/Tests/WP/I18nUnitTest.1.inc b/WordPress/Tests/WP/I18nUnitTest.1.inc index 9dee14b160..3ec15f1ee3 100644 --- a/WordPress/Tests/WP/I18nUnitTest.1.inc +++ b/WordPress/Tests/WP/I18nUnitTest.1.inc @@ -217,3 +217,11 @@ __( 'Foo', 'my-slug' ); // phpcs:set WordPress.WP.I18n text_domain[] // phpcs:set WordPress.WP.I18n check_translator_comments true + +// Test handling of more complex embedded variables and expressions. +__( "${foo}", 'my-slug' ); +__( "{$foo['bar']}", 'my-slug' ); +__( "{$foo->bar()}", 'my-slug' ); +__( "{$foo['bar']->baz()()}", 'my-slug' ); +__( "${foo->bar}", 'my-slug' ); +__( "${foo["${bar['baz']}"]}", 'my-slug' ); diff --git a/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed b/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed index f143370ec0..5a2cd96880 100644 --- a/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed +++ b/WordPress/Tests/WP/I18nUnitTest.1.inc.fixed @@ -217,3 +217,11 @@ __( 'Foo', 'my-slug' ); // phpcs:set WordPress.WP.I18n text_domain[] // phpcs:set WordPress.WP.I18n check_translator_comments true + +// Test handling of more complex embedded variables and expressions. +__( "${foo}", 'my-slug' ); +__( "{$foo['bar']}", 'my-slug' ); +__( "{$foo->bar()}", 'my-slug' ); +__( "{$foo['bar']->baz()()}", 'my-slug' ); +__( "${foo->bar}", 'my-slug' ); +__( "${foo["${bar['baz']}"]}", 'my-slug' ); diff --git a/WordPress/Tests/WP/I18nUnitTest.php b/WordPress/Tests/WP/I18nUnitTest.php index 0d81d06e30..a30ef55718 100644 --- a/WordPress/Tests/WP/I18nUnitTest.php +++ b/WordPress/Tests/WP/I18nUnitTest.php @@ -119,6 +119,12 @@ public function getErrorList( $testFile = '' ) { 178 => 1, 181 => 3, 184 => 1, + 222 => 1, + 223 => 1, + 224 => 1, + 225 => 1, + 226 => 1, + 227 => 1, ); case 'I18nUnitTest.2.inc': From 22ef882f217d1814a96de24e592bec559c9f0a24 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 18 Jun 2022 05:57:59 +0200 Subject: [PATCH 198/822] DB/PreparedSQL: use PHPCSUtils for checking string embeds Switch out the use of the WPCS native `TextStringHelper::get_interpolated_variables()` method in favour of the significantly more comprehensive PHPCSUtils `TextStrings::getEmbeds()` method. This improves the handling of embedded variables in double quoted strings (and consequently fixes some bugs). For some samples of embedded variables/expressions, the sniff would previously correctly report on the embed, but would contain an incomplete/incorrect representation of the embed in the error message: ```php $wpdb->query( "SELECT * FROM {$wpdb->bar()} WHERE post_title LIKE '{$title->bar()}';" ); // 106 | ERROR | Use placeholders and $wpdb->prepare(); found interpolated variable $title at "SELECT * FROM {$wpdb->bar()} WHERE post_title LIKE '{$title->bar()}';" $wpdb->query( "SELECT * FROM ${wpdb->{$baz}} WHERE post_title LIKE '${title->{$sub}}';" ); // 108 | ERROR | Use placeholders and $wpdb->prepare(); found interpolated variable $sub at "SELECT * FROM ${wpdb->{$baz}} WHERE post_title LIKE '${title->{$sub}}';" ``` In other cases, the `$wpdb` variable was not correctly recognized as such (false positive): ```php $wpdb->query( "SELECT * FROM ${wpdb->{$baz}} WHERE post_title LIKE '${title->{$sub}}';" ); // 108 | ERROR | Use placeholders and $wpdb->prepare(); found interpolated variable $baz at "SELECT * FROM ${wpdb->{$baz}} WHERE post_title LIKE '${title->{$baz}}';" ``` For other embedded variables/expressions, the sniff would previously not throw an error (false negative). ```php // No error, while an error should be thrown. $wpdb->query( "SELECT * FROM ${wpdb->bar} WHERE post_title LIKE '${title->sub}';" ); // Bad x 1. $wpdb->query( "SELECT * FROM ${wpdb->{${'a'}}} WHERE post_title LIKE '${title->{${'sub'}}}';" ); // Bad x 1. ``` With the implemented fix, all embeds will now result in the expected errors and the error messages will contain a correct representation of the embed: ``` 106 | ERROR | Use placeholders and $wpdb->prepare(); found interpolated variable {$title->bar()} at "SELECT * FROM {$wpdb->bar()} WHERE post_title LIKE '{$title->bar()}';" 107 | ERROR | Use placeholders and $wpdb->prepare(); found interpolated variable ${title->bar} at "SELECT * FROM ${wpdb->bar} WHERE post_title LIKE '${title->bar}';" 108 | ERROR | Use placeholders and $wpdb->prepare(); found interpolated variable ${title->{$baz}} at "SELECT * FROM ${wpdb->{$baz}} WHERE post_title LIKE '${title->{$baz}}';" 109 | ERROR | Use placeholders and $wpdb->prepare(); found interpolated variable ${title->{${'a'}}} at "SELECT * FROM ${wpdb->{${'a'}}} WHERE post_title LIKE '${title->{${'a'}}}';" ``` Note: the matching of `$wpdb` has been improved, but does not check whether a known table name is accessed or anything. This is no different than before, but may warrant further improvement in the future. --- WordPress/Sniffs/DB/PreparedSQLSniff.php | 10 +++--- WordPress/Tests/DB/PreparedSQLUnitTest.inc | 6 ++++ WordPress/Tests/DB/PreparedSQLUnitTest.php | 38 ++++++++++++---------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/WordPress/Sniffs/DB/PreparedSQLSniff.php b/WordPress/Sniffs/DB/PreparedSQLSniff.php index c15826c14c..4373ee8a5d 100644 --- a/WordPress/Sniffs/DB/PreparedSQLSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLSniff.php @@ -10,7 +10,7 @@ namespace WordPressCS\WordPress\Sniffs\DB; use PHP_CodeSniffer\Util\Tokens; -use WordPressCS\WordPress\Helpers\TextStringHelper; +use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\Sniff; /** @@ -139,15 +139,17 @@ public function process_token( $stackPtr ) { ) { $bad_variables = array_filter( - TextStringHelper::get_interpolated_variables( $this->tokens[ $this->i ]['content'] ), + TextStrings::getEmbeds( $this->tokens[ $this->i ]['content'] ), function ( $symbol ) { - return ( 'wpdb' !== $symbol ); + return ( strpos( $symbol, '$wpdb' ) !== 0 + && strpos( $symbol, '{$wpdb') !== 0 + && strpos( $symbol, '${wpdb') !== 0 ); } ); foreach ( $bad_variables as $bad_variable ) { $this->phpcsFile->addError( - 'Use placeholders and $wpdb->prepare(); found interpolated variable $%s at %s', + 'Use placeholders and $wpdb->prepare(); found interpolated variable %s at %s', $this->i, 'InterpolatedNotPrepared', array( diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.inc index 3fa34f89e7..699630bd1c 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.inc @@ -102,5 +102,11 @@ $wpdb->query( . ";" ); +// Test handling of more complex embedded variables and expressions. +$wpdb->query( "SELECT * FROM {$wpdb->bar()} WHERE post_title LIKE '{$title->sub()}';" ); // Bad x 1. +$wpdb->query( "SELECT * FROM ${wpdb->bar} WHERE post_title LIKE '${title->sub}';" ); // Bad x 1. +$wpdb->query( "SELECT * FROM ${wpdb->{$baz}} WHERE post_title LIKE '${title->{$sub}}';" ); // Bad x 1. +$wpdb->query( "SELECT * FROM ${wpdb->{${'a'}}} WHERE post_title LIKE '${title->{${'sub'}}}';" ); // Bad x 1. + // Don't throw an error during live coding. wpdb::prepare( "SELECT * FROM $wpdb->posts diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.php b/WordPress/Tests/DB/PreparedSQLUnitTest.php index 78e484a076..36c481abe2 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.php @@ -31,23 +31,27 @@ class PreparedSQLUnitTest extends AbstractSniffUnitTest { */ public function getErrorList() { return array( - 3 => 1, - 4 => 1, - 5 => 1, - 7 => 1, - 8 => 1, - 11 => 1, // Old-style WPCS ignore comments are no longer supported. - 12 => 1, // Old-style WPCS ignore comments are no longer supported. - 16 => 1, - 17 => 1, - 18 => 1, - 20 => 1, - 21 => 1, - 54 => 1, - 64 => 1, - 71 => 1, - 85 => 1, - 90 => 1, + 3 => 1, + 4 => 1, + 5 => 1, + 7 => 1, + 8 => 1, + 11 => 1, // Old-style WPCS ignore comments are no longer supported. + 12 => 1, // Old-style WPCS ignore comments are no longer supported. + 16 => 1, + 17 => 1, + 18 => 1, + 20 => 1, + 21 => 1, + 54 => 1, + 64 => 1, + 71 => 1, + 85 => 1, + 90 => 1, + 106 => 1, + 107 => 1, + 108 => 1, + 109 => 1, ); } From 69dd8c1d9320f9c791e2b669abc52a9a46a80c9a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jun 2022 08:50:29 +0200 Subject: [PATCH 199/822] DB/PreparedSQL: improve matching of `$wpdb` While probably still not perfect, this improves how the `$wpdb` variable is matched in embeds. * The regex will match all possible "start of" embeds - `$wpdb`, `{$wpdb` and `${wpdb`. * The regex requires that the `$wpdb` variable is followed by an object operator - either `->` or the PHP 8.1 `?->` - to access a table name. Note: I'm not sure we should actually allow `?->` as in that case, if `$wpdb` would be `null`, the result would be `null`, which would convert to an empty string in a double quoted string. Then again, that would just make for an invalid query and that is not the concern of this sniff (which is why I included it anyway). * `$wpdb` on its own will no longer match as it would be invalid anyway (the `WPDB` class does not have a `__toString()` method). Includes one extra unit test, though the principle of it is already covered by most existing tests. --- WordPress/Sniffs/DB/PreparedSQLSniff.php | 4 +--- WordPress/Tests/DB/PreparedSQLUnitTest.inc | 5 ++++- WordPress/Tests/DB/PreparedSQLUnitTest.php | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/DB/PreparedSQLSniff.php b/WordPress/Sniffs/DB/PreparedSQLSniff.php index 4373ee8a5d..93a3ce23de 100644 --- a/WordPress/Sniffs/DB/PreparedSQLSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLSniff.php @@ -141,9 +141,7 @@ public function process_token( $stackPtr ) { $bad_variables = array_filter( TextStrings::getEmbeds( $this->tokens[ $this->i ]['content'] ), function ( $symbol ) { - return ( strpos( $symbol, '$wpdb' ) !== 0 - && strpos( $symbol, '{$wpdb') !== 0 - && strpos( $symbol, '${wpdb') !== 0 ); + return preg_match( '`^\{?\$\{?wpdb\??->`', $symbol ) !== 1; } ); diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.inc index 699630bd1c..ef58abc469 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.inc @@ -82,7 +82,7 @@ ND implode( ',', array_fill( 0, count( $post_ids ), '%d' ) ) ), $post_ids ) ); // OK. -wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // Bad. +wpdb::prepare( "SELECT * FROM $wpdb?->posts WHERE post_title LIKE '" . foo() . "';" ); // Bad. $wpdb->query( // Some arbitrary comment. "SELECT * @@ -108,5 +108,8 @@ $wpdb->query( "SELECT * FROM ${wpdb->bar} WHERE post_title LIKE '${title->sub}'; $wpdb->query( "SELECT * FROM ${wpdb->{$baz}} WHERE post_title LIKE '${title->{$sub}}';" ); // Bad x 1. $wpdb->query( "SELECT * FROM ${wpdb->{${'a'}}} WHERE post_title LIKE '${title->{${'sub'}}}';" ); // Bad x 1. +// More defensive variable checking +$wpdb->query( "SELECT * FROM $wpdb" ); // Bad x 1, $wpdb on its own is not valid. + // Don't throw an error during live coding. wpdb::prepare( "SELECT * FROM $wpdb->posts diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.php b/WordPress/Tests/DB/PreparedSQLUnitTest.php index 36c481abe2..0e679f0efc 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.php @@ -52,6 +52,7 @@ public function getErrorList() { 107 => 1, 108 => 1, 109 => 1, + 112 => 1, ); } From 90d8accc3affd8b8823d5778e634a97f981876c1 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jun 2022 09:35:45 +0200 Subject: [PATCH 200/822] DB/PreparedSQLPlaceholders: use PHPCSUtils for checking string embeds and improve `$wpdb` matching This change is along the same lines as the change made for the `PreparedSQL` sniff, but as the `PreparedSQLPlaceholders` sniff only uses the embeds to prevent duplicate messages, extra unit tests which would actually fail would be pretty complex to create. All the same, this should be considered safeguarded by the existing unit tests. --- .../Sniffs/DB/PreparedSQLPlaceholdersSniff.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php index d85d09e9aa..b88750e79f 100644 --- a/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php +++ b/WordPress/Sniffs/DB/PreparedSQLPlaceholdersSniff.php @@ -12,7 +12,6 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\PassedParameters; use PHPCSUtils\Utils\TextStrings; -use WordPressCS\WordPress\Helpers\TextStringHelper; use WordPressCS\WordPress\Sniff; /** @@ -277,15 +276,20 @@ public function process_token( $stackPtr ) { // Only interested in actual query text, so strip out variables. $stripped_content = TextStrings::stripEmbeds( $content ); if ( $stripped_content !== $content ) { - $interpolated_vars = TextStringHelper::get_interpolated_variables( $content ); - $vars_without_wpdb = array_diff( $interpolated_vars, array( 'wpdb' ) ); - $content = $stripped_content; + $vars_without_wpdb = array_filter( + TextStrings::getEmbeds( $content ), + function ( $symbol ) { + return preg_match( '`^\{?\$\{?wpdb\??->`', $symbol ) !== 1; + } + ); + + $content = $stripped_content; if ( ! empty( $vars_without_wpdb ) ) { $variable_found = true; } } - unset( $stripped_content, $interpolated_vars, $vars_without_wpdb ); + unset( $stripped_content, $vars_without_wpdb ); } $placeholders = preg_match_all( '`' . self::PREPARE_PLACEHOLDER_REGEX . '`x', $content, $matches ); From cfe13aa4a546c7467ea3f835e62cf71597b51952 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 27 Jun 2022 17:40:04 +0200 Subject: [PATCH 201/822] Security/ValidatedSanitizedInput: use PHPCSUtils for checking string embeds Switch out the use of the WPCS native `TextStringHelper::get_interpolated_variables()` method in favour of the significantly more comprehensive PHPCSUtils `TextStrings::getEmbeds()` method. This improves the handling of embedded variables in double quoted strings (and consequently fixes some bugs). For various embedded variables/expressions, the sniff would previously not throw an error (false negative), for example: ```php // No error, while an error should be thrown. echo "{$_GET['bar']}"; echo "${_REQUEST['bar']}"; echo "${_GET["${bar}"]}"; echo "${_FILES["${bar['baz']}"]}"; ``` With the implemented fix, all embedded superglobals the sniff looks for, will now result in the expected error: Note: the "bad" comment for the heredoc is _above_ the test instead of as a trailing comment as a trailing comment would be a parse error in PHP < 7.3. --- .../Sniffs/Security/ValidatedSanitizedInputSniff.php | 10 ++++++---- .../Tests/Security/ValidatedSanitizedInputUnitTest.inc | 9 +++++++++ .../Tests/Security/ValidatedSanitizedInputUnitTest.php | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php index d3810ff68e..2f17cc2c1f 100644 --- a/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php +++ b/WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php @@ -10,7 +10,7 @@ namespace WordPressCS\WordPress\Sniffs\Security; use PHP_CodeSniffer\Util\Tokens; -use WordPressCS\WordPress\Helpers\TextStringHelper; +use PHPCSUtils\Utils\TextStrings; use WordPressCS\WordPress\Helpers\VariableHelper; use WordPressCS\WordPress\Sniff; @@ -98,12 +98,14 @@ public function process_token( $stackPtr ) { if ( \T_DOUBLE_QUOTED_STRING === $this->tokens[ $stackPtr ]['code'] || \T_HEREDOC === $this->tokens[ $stackPtr ]['code'] ) { + // Retrieve all embeds, but use only the initial variable name part. $interpolated_variables = array_map( - function ( $symbol ) { - return '$' . $symbol; + function( $embed ) { + return '$' . preg_replace( '`^(\{?\$\{?\(?)([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)(.*)$`', '$2', $embed ); }, - TextStringHelper::get_interpolated_variables( $this->tokens[ $stackPtr ]['content'] ) + TextStrings::getEmbeds( $this->tokens[ $stackPtr ]['content'] ) ); + foreach ( array_intersect( $interpolated_variables, $superglobals ) as $bad_variable ) { $this->phpcsFile->addError( 'Detected usage of a non-sanitized, non-validated input variable %s: %s', $stackPtr, 'InputNotValidatedNotSanitized', array( $bad_variable, $this->tokens[ $stackPtr ]['content'] ) ); } diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc index f5d5dd6e07..2ee10c881c 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc @@ -336,3 +336,12 @@ echo wp_sanitize_redirect( wp_unslash( $_GET['test'] ) ); // OK. $result = match ( $_POST['foo'] ) {}; // Ok. $result = match ( do_something( wp_unslash( $_POST['foo'] ) ) ) {}; // Bad. + +// Test handling of more complex embedded variables and expressions. +function test_handling_embeds() { + echo "My ${_POST} and {$_GET['bar']} and ${_REQUEST['bar']}"; // Bad x 3. + // Below heredoc: bad x 3. + echo <<<"EOD" +Do ${(_POST)} and ${_GET["${bar}"]} and ${_FILES["${bar['baz']}"]} +EOD; +} diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php index ac41f98ad2..2f51624db5 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php @@ -81,6 +81,8 @@ public function getErrorList() { 317 => 1, 323 => 1, 338 => 1, + 342 => 3, + 345 => 3, ); } From d3c0d98c109bb36d3e28784d153294d473c0754b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 7 Jun 2022 00:00:06 +0200 Subject: [PATCH 202/822] TextStringHelper: remove the class After the implementation of the PHPCSUtils `TextString::getEmbeds()` function in all relevant sniffs, the `TextStringHelper::get_interpolated_variables()` method is no longer used in WPCS, so this Helper class has become redundant. --- WordPress/Helpers/TextStringHelper.php | 53 -------------------------- 1 file changed, 53 deletions(-) delete mode 100644 WordPress/Helpers/TextStringHelper.php diff --git a/WordPress/Helpers/TextStringHelper.php b/WordPress/Helpers/TextStringHelper.php deleted file mode 100644 index 4c701d8ffb..0000000000 --- a/WordPress/Helpers/TextStringHelper.php +++ /dev/null @@ -1,53 +0,0 @@ -\\\\*)\$(?P\w+)/', $string, $match_sets, \PREG_SET_ORDER ) ) { - foreach ( $match_sets as $matches ) { - if ( ! isset( $matches['backslashes'] ) || ( \strlen( $matches['backslashes'] ) % 2 ) === 0 ) { - $variables[] = $matches['symbol']; - } - } - } - return $variables; - } -} From 03b9b65585c3709781bbd52ebb2f228f567dcb85 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 12 Aug 2022 18:40:23 +0200 Subject: [PATCH 203/822] :sparkles: New `WordPress.WhiteSpace.ObjectOperatorSpacing` sniff This sniff largely defers to the upstream `Squiz.WhiteSpace.ObjectOperatorSpacing` sniff, which was previously already included. The only real difference between the two sniffs is that for class resolution using `ClassName::class`, new lines around the `::` object operator will not be ignored. The WPCS sniff has the same default property settings as the upstream sniff and changes to the property values should be made in the ruleset. Includes docs. Includes unit tests covering the difference and safeguarding that the sniff doesn't overreach. --- WordPress-Core/ruleset.xml | 2 +- .../ObjectOperatorSpacingStandard.xml | 19 ++++++ .../WhiteSpace/ObjectOperatorSpacingSniff.php | 65 +++++++++++++++++++ .../ObjectOperatorSpacingUnitTest.inc | 55 ++++++++++++++++ .../ObjectOperatorSpacingUnitTest.inc.fixed | 45 +++++++++++++ .../ObjectOperatorSpacingUnitTest.php | 59 +++++++++++++++++ 6 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 WordPress/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml create mode 100644 WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php create mode 100644 WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.inc create mode 100644 WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.inc.fixed create mode 100644 WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.php diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index eee861589b..b467c8e930 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -526,7 +526,7 @@ - + diff --git a/WordPress/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml b/WordPress/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml new file mode 100644 index 0000000000..47ffb1e8e6 --- /dev/null +++ b/WordPress/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml @@ -0,0 +1,19 @@ + + + , ?->, ::) should not have any spaces around them, though new lines are allowed except for use with the `::class` constant. + ]]> + + + + ->bar(); + ]]> + + + ?-> bar(); + ]]> + + + diff --git a/WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php new file mode 100644 index 0000000000..2970fe927d --- /dev/null +++ b/WordPress/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php @@ -0,0 +1,65 @@ +getTokens(); + $property_adjusted = false; + + // Check for `::class` and don't ignore new lines in that case. + if ( true === $this->ignoreNewlines + && \T_DOUBLE_COLON === $tokens[ $stackPtr ]['code'] + ) { + $next_non_empty = $phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true ); + if ( \T_STRING === $tokens[ $next_non_empty ]['code'] + && 'class' === strtolower( $tokens[ $next_non_empty ]['content'] ) + ) { + $property_adjusted = true; + $this->ignoreNewlines = false; + } + } + + $return = parent::process( $phpcsFile, $stackPtr ); + + if ( true === $property_adjusted ) { + $this->ignoreNewlines = true; + } + + return $return; + } +} diff --git a/WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.inc b/WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.inc new file mode 100644 index 0000000000..ec042a295f --- /dev/null +++ b/WordPress/Tests/WhiteSpace/ObjectOperatorSpacingUnitTest.inc @@ -0,0 +1,55 @@ + + */ + public function getErrorList() { + return array( + 11 => 2, + 12 => 2, + 13 => 2, + 16 => 2, + 19 => 2, + 22 => 2, + 26 => 2, + 36 => 2, + 37 => 2, + 38 => 2, + 47 => 2, + 51 => 2, + ); + } + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @return array + */ + public function getWarningList() { + return array(); + } +} From 61bcaa53abe84400a4a35884475bfb47ea6d2314 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 27 Oct 2022 17:02:55 +0200 Subject: [PATCH 204/822] WPCS-Extra: enable the `Generic.CodeAnalysis.UnusedFunctionParameter` sniff The reason why the sniff was disabled up to now was that WP uses callbacks a lot and the hooked in functions may not use all parameters passed to them. This concern was previously raised in https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/pull/382#discussion_r29981655, also see https://github.com/WordPress/WordPress-Coding-Standards/pull/382/commits/522b35f3ebac915d6eebb92624fc703c193aee60 To this end, I've send in a [PR upstream](https://github.com/squizlabs/PHP_CodeSniffer/pull/1318) to address these concerns, which has subsequently been merged. The adjusted version of the sniff was released in PHPCS 3.4.0, which means the sniff can now be added. Note: the sniff has since then also been adjusted to handle arrow functions correctly, as well as constructor property promotion. Fixes 1510 --- WordPress-Extra/ruleset.xml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index 3c33ad3111..f2616291b7 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -48,13 +48,23 @@ - - - + + + + + + + + + + + + From e13cb6cd0099dc6bc5cc49dc5f67a7b9c1d27a9b Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Jul 2022 15:39:44 +0200 Subject: [PATCH 205/822] Core: move rules related to include/require statements from `Extra` to `Core` > 1. No parentheses shall be used for `include[_once]` and `require[_once]` statements. > As `include[_once]` and `require[_once]` are language constructs, they do not need parentheses around the path. > 2. There should be exactly one space between the `include[_once]` and `require[_once]` keyword and the start of the path. > 3. It is strongly recommended to use `require[_once]` for unconditional includes. > When using `include[_once]` PHP will throw a warning when the file is not found, but will continue execution which will almost certainly lead to other errors/warnings/notices being thrown if your application depends on the file being available, potentially leading to security leaks. For that reason, `require[_once]` is generally the better choice as it will throw a Fatal Error if the file cannot be found. Refs: * https://make.wordpress.org/core/2020/03/20/updating-the-coding-standards-for-modern-php/ - Include/Require section * https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#writing-include-require-statements * WordPress/wpcs-docs 111 * WordPress/WordPress-Coding-Standards 1007 * WordPress/WordPress-Coding-Standards 1143 * WordPress/WordPress-Coding-Standards 1145 * WordPress/WordPress-Coding-Standards 1153 * WordPress/WordPress-Coding-Standards 1163 Closes 1862 --- WordPress-Core/ruleset.xml | 25 +++++++++++++++++++++++++ WordPress-Extra/ruleset.xml | 17 ----------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index b467c8e930..50aa707511 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -64,6 +64,31 @@ https://github.com/WordPress/WordPress-Coding-Standards/issues/527 --> + + + + + + + + + + + warning + + + warning + + + - - - warning - - - warning - - - warning - - - - - From bf049fd9dbbec52b27c2bceb938b592a03de906d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 22 Jul 2022 14:46:07 +0200 Subject: [PATCH 206/822] Core: add sniffs to check there is no blank line before a function close brace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > 1. There should be no blank line between the content of a function and the function’s closing brace. Includes removing this rule from the WPCS native ruleset in which we already enforced it (as it will now be inherited from the `WordPress` ruleset). Refs: * https://make.wordpress.org/core/2020/03/20/updating-the-coding-standards-for-modern-php/ - Function closing brace section * https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#remove-trailing-spaces * https://github.com/WordPress/wpcs-docs/pull/110 Loosely related to #1101 --- .phpcs.xml.dist | 2 -- WordPress-Core/ruleset.xml | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 6a4fba088f..08c86032b1 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -30,8 +30,6 @@ - - diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 50aa707511..c567d7b975 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -294,6 +294,10 @@ + + + + - - Best practices: Declare only one class/interface/trait in a file. - + @@ -336,6 +339,23 @@ https://github.com/WordPress/WordPress-Coding-Standards/issues/1330 --> + + + + + + + + + + + + + + + 0 + + + 0 + + + + + + + - - + + + 5 + + + + + 5 + + From 808c905066a0977119d336611cb893b8557eb0f3 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 28 Oct 2022 09:37:37 +0200 Subject: [PATCH 210/822] Core: move rules related to property/method modifier order from `Extra` to `Core` > 1. When using multiple modifiers for a property or method declaration, the order should be as follows: > 1. First the optional `abstract` or `final` keyword. > 2. Next a visibility keyword. > 3. Lastly, the optional `static` [red: or `readonly`] keyword. For property declarations, this is already covered by the `PSR2.Classes.PropertyDeclaration` sniff. For method declarations, the `PSR2.Methods.MethodDeclaration` sniff has now been moved from `Extra` to `Core`. The `PSR2.Methods.MethodDeclaration` sniff contains one additional error code, which IMO should probably not (yet) go into the `Core` ruleset. * `Underscore` - which warns against prefixing a method name with an underscore, advising to use visibility instead. While I'm 100% in favour of this, introducing this for WP Core would be problematic as renaming (`public`/`protected`) methods would be a BC-break. As this rule was previously already included in the `Extra` ruleset, the error code which is being silenced for `Core`, will be "unsilenced" again for `Extra`. The `PSR2.Classes.PropertyDeclaration` sniff does not yet account for ordering the visibility vs readonly keywords. I have opened a PR upstream - squizlabs/PHP_CodeSniffer 3637 - proposing to add a check for this to the `PSR2.Classes.PropertyDeclaration` sniff. * If that PR would be accepted, WPCS will automatically inherit the check and we'd be good. * If that PR would be rejected, I propose to create a dedicated sniff in PHPCSExtra to handle property modifier keywords with configuration options for the preferred order. Refs: * https://make.wordpress.org/core/2020/03/20/updating-the-coding-standards-for-modern-php/ - Visibility should always be declared section * https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#visibility-and-modifier-order * WordPress/wpcs-docs 108 * WordPress/WordPress-Coding-Standards 1101 * WordPress/WordPress-Coding-Standards 1103 * squizlabs/PHP_CodeSniffer 3637 --- WordPress-Core/ruleset.xml | 31 +++++++++++++++++++++++++++++++ WordPress-Extra/ruleset.xml | 4 +++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 2fc7299c89..05e4bf67d9 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -387,6 +387,37 @@ + + + + + + + + + + + + 0 + + + - 5 + + 5 + From d4402e51bcf9f3966fd57bfadf86a87185f0c343 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 23 Jul 2022 23:32:48 +0200 Subject: [PATCH 211/822] Core: move last modifier keyword sniff from Extra to Core While this was not explicitly mentioned in the Make post, it is implied that there should be exactly one space after each modifier keyword for properties and methods. This was already being checked for in `Extra`. I'm proposing to move this sniff to the `Core` ruleset. Note: I've checked and introducing this sniff to the `Core` ruleset does not yield any issues for WP Core as is, so it would be a silent introduction. Refs: * WordPress/WordPress-Coding-Standards 1101 --- WordPress-Core/ruleset.xml | 3 +++ WordPress-Extra/ruleset.xml | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 05e4bf67d9..323ed05023 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -417,6 +417,9 @@ 0 + + + - - From 0121356075174d58bfd6a4aac68cbe2a32a9ddea Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 28 Oct 2022 09:44:45 +0200 Subject: [PATCH 212/822] Core: move `BacktickOperator` sniff from `Extra` to `Core` > 1. Use of the backtick operator is not allowed. Refs: * https://make.wordpress.org/core/2020/03/20/updating-the-coding-standards-for-modern-php/ - Shell Commands section * https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/#shell-commands * WordPress/wpcs-docs 114 * WordPress/WordPress-Coding-Standards 646 --- WordPress-Core/ruleset.xml | 10 ++++++++++ WordPress-Extra/ruleset.xml | 3 --- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 2fc7299c89..787e6afe07 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -559,6 +559,16 @@ + + + + + - - From 12c32b5593571c91276819ff8df9e72029778806 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 30 Oct 2022 20:15:06 +0100 Subject: [PATCH 213/822] Core: only allow one property declaration per statement As per the discussion in 2101. --- WordPress-Core/ruleset.xml | 6 ++---- WordPress-Extra/ruleset.xml | 6 ------ 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 044354e398..e85cd14a6d 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -373,14 +373,12 @@ ############################################################################# --> + visibility should be explicitly declared. + Includes "only one property declaration per statement". --> 0 - - 0 - diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index aff7e94b7d..1c9efaa995 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -58,12 +58,6 @@ 5 - - - 5 - - From 1bc0e35948df4e2e798df1c8a596fc9794a09122 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 4 Nov 2022 03:07:22 +0100 Subject: [PATCH 214/822] Extra: fix typo in rule --- WordPress-Extra/ruleset.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index 1c9efaa995..c7261b08fe 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -42,7 +42,7 @@ - + From f718222920b754b050bd0d84c11bdf8cbcd8773c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 4 Nov 2022 19:41:28 +0100 Subject: [PATCH 215/822] GH Actions: bust the cache semi-regularly Caches used in GH Actions do not get updated, they can only be replaced by a different cache with a different cache key. Now the predefined Composer install action this repo is using already creates a pretty comprehensive cache key: > `ramsey/composer-install` will auto-generate a cache key which is composed of the following elements: > * The OS image name, like `ubuntu-latest`. > * The exact PHP version, like `8.1.11`. > * The options passed via `composer-options`. > * The dependency version setting as per `dependency-versions`. > * The working directory as per `working-directory`. > * A hash of the `composer.json` and/or `composer.lock` files. This means that aside from other factors, the cache will always be busted when changes are made to the (committed) `composer.json` or the `composer.lock` file (if the latter exists in the repo). For packages running on recent versions of PHP, it also means that the cache will automatically be busted once a month when a new PHP version comes out. ### The problem For runs on older PHP versions which don't receive updates anymore, the cache will not be busted via new PHP version releases, so effectively, the cache will only be busted when a change is made to the `composer.json`/`composer.lock` file - which may not happen that frequently on low-traffic repos. But... packages _in use_ on those older PHP versions - especially dependencies of declared dependencies - may still release new versions and those new versions will not exist in the cache and will need to be downloaded each time the action is run and over time the cache gets less and less relevant as more and more packages will need to be downloaded for each run. ### The solution To combat this issue, a new `custom-cache-suffix` option has been added to the Composer install action in version 2.2.0. This new option allows for providing some extra information to add to the cache key, which allows for busting the cache based on your own additional criteria. This commit implements the use of this `custom-cache-suffix` option for all relevant workflows in this repo. Refs: * https://github.com/ramsey/composer-install/#custom-cache-suffix * https://github.com/ramsey/composer-install/releases/tag/2.2.0 --- .github/workflows/quicktest.yml | 3 +++ .github/workflows/ruleset-checks-sniffs.yml | 6 ++++++ .github/workflows/unit-tests.yml | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index cb23467085..294d964e18 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -67,6 +67,9 @@ jobs: - name: Install Composer dependencies uses: ramsey/composer-install@v2 + with: + # Bust the cache at least once a month - output format: YYYY-MM-DD. + custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") - name: Lint PHP files against parse errors if: ${{ matrix.phpcs_version == 'dev-master' }} diff --git a/.github/workflows/ruleset-checks-sniffs.yml b/.github/workflows/ruleset-checks-sniffs.yml index f359ed9ece..325db68645 100644 --- a/.github/workflows/ruleset-checks-sniffs.yml +++ b/.github/workflows/ruleset-checks-sniffs.yml @@ -52,6 +52,9 @@ jobs: - name: Install Composer dependencies uses: ramsey/composer-install@v2 + with: + # Bust the cache at least once a month - output format: YYYY-MM-DD. + custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") - name: Install xmllint run: | @@ -139,6 +142,9 @@ jobs: - name: Install Composer dependencies uses: ramsey/composer-install@v2 + with: + # Bust the cache at least once a month - output format: YYYY-MM-DD. + custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") - name: Test the WordPress-Core ruleset run: $(pwd)/vendor/bin/phpcs -ps ./Tests/RulesetCheck/class-ruleset-test.inc --standard=WordPress-Core diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 3ba3f940a0..18fa870d3d 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -82,12 +82,16 @@ jobs: - name: Install Composer dependencies (PHP < 8.0 ) if: ${{ matrix.php < 8.0 }} uses: ramsey/composer-install@v2 + with: + # Bust the cache at least once a month - output format: YYYY-MM-DD. + custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") - name: Install Composer dependencies (PHP >= 8.0) if: ${{ matrix.php >= 8.0 }} uses: ramsey/composer-install@v2 with: composer-options: --ignore-platform-reqs + custom-cache-suffix: $(date -u -d "-0 month -$(($(date +%d)-1)) days" "+%F") - name: Lint PHP files against parse errors if: ${{ matrix.phpcs_version == 'dev-master' }} From 67e06d0578e240c44787f955bb7841ff91f3a19f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 5 Nov 2022 18:46:20 +0100 Subject: [PATCH 216/822] Extra: fix (more) typos in rules --- WordPress-Extra/ruleset.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index c7261b08fe..2c469a593e 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -41,9 +41,9 @@ - + - + From 61dc3dd4d16a28c76b7638c6178cbb4a89dea32f Mon Sep 17 00:00:00 2001 From: Sandesh Date: Fri, 11 Nov 2022 19:24:44 +0530 Subject: [PATCH 217/822] Removed file_get_contents() from the list as it is already checked in another group --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index 2366cb83a2..103249abcc 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -77,7 +77,6 @@ public function getGroups() { 'chown', 'delete', 'fclose', - 'file_get_contents', 'file_put_contents', 'flock', 'fopen', From e3aa034451e1e736534386099a04a6efc81d3644 Mon Sep 17 00:00:00 2001 From: Sandesh Date: Sat, 12 Nov 2022 13:27:33 +0530 Subject: [PATCH 218/822] Seprated WP counter function and removed updated the list of filesystem functions --- .../Sniffs/WP/AlternativeFunctionsSniff.php | 49 ++++++++----------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index 6a3c169b83..901658c018 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -126,39 +126,29 @@ public function getGroups() { ), ), + 'unlink' => array( + 'type' => 'warning', + 'message' => '%s() is discouraged. Use wp_delete_file() for remote URLs instead.', + 'since' => '2.7.0', + 'functions' => array( + 'unlink', + ), + ), + 'file_system_read' => array( 'type' => 'warning', 'message' => 'File operations should use WP_Filesystem methods instead of direct PHP filesystem calls. Found: %s()', 'since' => '2.5.0', 'functions' => array( - // 'chgrp', - // 'chmod', - // 'chown', - // 'delete', - // 'fclose', - // 'file_put_contents', - // 'flock', - // 'fopen', - // 'fputcsv', - // 'fputs', - // 'fread', - // 'fsockopen', - // 'ftruncate', - // 'fwrite', - // 'is_writable', - // 'is_writeable', - // 'lchgrp', - // 'lchown', - // 'link', - // 'mkdir', - // 'pfsockopen', - // 'readfile', - // 'rename', - // 'rmdir', - // 'symlink', - // 'tempnam', - // 'touch', - // 'unlink', + 'chgrp', + 'chmod', + 'chown', + 'is_writable', + 'is_writeable', + 'mkdir', + 'rename', + 'rmdir', + 'touch', 'readfile', 'fclose', 'fopen', @@ -167,6 +157,9 @@ public function getGroups() { 'file_put_contents', 'fsockopen', 'pfsockopen', + // 'fputcsv', + // 'fputs', + // 'ftruncate', ), ), From 44bea02712dbb65fdd33b13a1e492afb27957359 Mon Sep 17 00:00:00 2001 From: Sandesh Date: Sat, 12 Nov 2022 13:32:36 +0530 Subject: [PATCH 219/822] Updated since of unlink function --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index 901658c018..e5b639c24e 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -129,7 +129,7 @@ public function getGroups() { 'unlink' => array( 'type' => 'warning', 'message' => '%s() is discouraged. Use wp_delete_file() for remote URLs instead.', - 'since' => '2.7.0', + 'since' => 'x.x.x', 'functions' => array( 'unlink', ), From 27cd9cb9d6a3a5c82e1ee74bb7d3d3f0911c9f8a Mon Sep 17 00:00:00 2001 From: Sandesh Date: Sat, 12 Nov 2022 17:43:41 +0530 Subject: [PATCH 220/822] Removed commented code --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index e5b639c24e..aaf0ffbd5c 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -157,9 +157,7 @@ public function getGroups() { 'file_put_contents', 'fsockopen', 'pfsockopen', - // 'fputcsv', - // 'fputs', - // 'ftruncate', + 'fputs', ), ), From 7c8ba9a300c15d0bf5205c9e05469d5e2e4057ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Fri, 25 Nov 2022 18:17:18 +0100 Subject: [PATCH 221/822] Fix the get_wp_version_from_cli method The getCommandLineData didn't correctly pick up the command line parameter. This fixes that issue. --- WordPress/Helpers/MinimumWPVersionTrait.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/WordPress/Helpers/MinimumWPVersionTrait.php b/WordPress/Helpers/MinimumWPVersionTrait.php index bf5c65f1f9..232fddc7cf 100644 --- a/WordPress/Helpers/MinimumWPVersionTrait.php +++ b/WordPress/Helpers/MinimumWPVersionTrait.php @@ -9,7 +9,6 @@ namespace WordPressCS\WordPress\Helpers; -use PHP_CodeSniffer\Files\File; use PHPCSUtils\BackCompat\Helper; /** @@ -81,12 +80,9 @@ trait MinimumWPVersionTrait { * @since 0.14.0 * @since 3.0.0 - Moved from the Sniff class to this dedicated Trait. * - Renamed from `get_wp_version_from_cl()` to `get_wp_version_from_cli()`. - * - Now requires the $phpcsFile object to be passed in. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. */ - protected function get_wp_version_from_cli( File $phpcsFile ) { - $cli_supported_version = Helper::getCommandLineData( $phpcsFile, 'minimum_supported_wp_version' ); + protected function get_wp_version_from_cli() { + $cli_supported_version = Helper::getConfigData( 'minimum_supported_wp_version' ); if ( empty( $cli_supported_version ) ) { return; From 2bbb31722f71f70b1899fac03beb158057644284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Fri, 25 Nov 2022 18:18:04 +0100 Subject: [PATCH 222/822] Update the sniffs with the updated get_wp_version_from_cli method --- WordPress/Sniffs/WP/AlternativeFunctionsSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedClassesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php | 2 +- WordPress/Sniffs/WP/DeprecatedParametersSniff.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index 9a0e17b0d6..cad367fcc4 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -185,7 +185,7 @@ public function getGroups() { */ public function process_matched_token( $stackPtr, $group_name, $matched_content ) { - $this->get_wp_version_from_cli( $this->phpcsFile ); + $this->get_wp_version_from_cli(); /* * Deal with exceptions. diff --git a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php index 71a2d84f40..c1fd8e051d 100644 --- a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php @@ -97,7 +97,7 @@ public function getGroups() { */ public function process_matched_token( $stackPtr, $group_name, $matched_content ) { - $this->get_wp_version_from_cli( $this->phpcsFile ); + $this->get_wp_version_from_cli(); $class_name = ltrim( strtolower( $matched_content ), '\\' ); diff --git a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php index edb06e26c9..b9379c4e54 100644 --- a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php @@ -1399,7 +1399,7 @@ public function getGroups() { */ public function process_matched_token( $stackPtr, $group_name, $matched_content ) { - $this->get_wp_version_from_cli( $this->phpcsFile ); + $this->get_wp_version_from_cli(); $function_name = strtolower( $matched_content ); diff --git a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php index a31ec00e2e..be90ca7075 100644 --- a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php @@ -155,7 +155,7 @@ class DeprecatedParameterValuesSniff extends AbstractFunctionParameterSniff { * @return void */ public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { - $this->get_wp_version_from_cli( $this->phpcsFile ); + $this->get_wp_version_from_cli(); $param_count = \count( $parameters ); foreach ( $this->target_functions[ $matched_content ] as $position => $parameter_args ) { diff --git a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php index 770cb31ccd..787da50856 100644 --- a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php @@ -284,7 +284,7 @@ class DeprecatedParametersSniff extends AbstractFunctionParameterSniff { */ public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { - $this->get_wp_version_from_cli( $this->phpcsFile ); + $this->get_wp_version_from_cli(); $paramCount = \count( $parameters ); foreach ( $this->target_functions[ $matched_content ] as $position => $parameter_args ) { From dd3ef96f2b0aabc0d73e6ea24f07de97994f0876 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 28 Nov 2022 15:05:38 +0100 Subject: [PATCH 223/822] :sparkles: New `WordPress.WP.ClassNameCase` sniff ... to check that any class name references to WP native classes use the case of the class as per the class declaration. As class names in PHP are case-insensitive, this is a `warning`, not an `error`. Open questions: * Should the same by checked for classes from external dependencies, like PHPMailer, SimplePie, Requests etc ? We could have separate arrays for each of these. * Is the name of the sniff correct or should it be made more generic ? I mean, at this time, WP only contains classes, no interfaces, traits or enums, but that may change in the future and the logic for checking this is largely the same, so it would make sense to add those checks to this sniff. I'm proposing to add this sniff to the WP Core ruleset, so both Core as well as plugins and themes will benefit from it. FYI: I've ran the sniff over WP Core and it triggers no issues. This sniff was inspired by a discussion I had with aristath and SergeyBiryukov earlier today. ---- Future scope: 1. Expand the places where we check for the use of class/oo names. A new abstract class/oo-name sniff is expected to be added to PHPCSUtils in the foreseeable future which will also check for the use of class names in `catch` statements, type declarations etc. Once that class is available, we should consider switching. 2. As maintaining the list of classes will be a manual task which would need to be executed after each release, it would be good to create some tooling which can update the list automatically and/or generate the update which would need to be applied. Related 1803. --- WordPress-Core/ruleset.xml | 3 + WordPress/Docs/WP/ClassNameCaseStandard.xml | 23 + WordPress/Sniffs/WP/ClassNameCaseSniff.php | 416 +++++++++++++++++++ WordPress/Tests/WP/ClassNameCaseUnitTest.inc | 53 +++ WordPress/Tests/WP/ClassNameCaseUnitTest.php | 46 ++ 5 files changed, 541 insertions(+) create mode 100644 WordPress/Docs/WP/ClassNameCaseStandard.xml create mode 100644 WordPress/Sniffs/WP/ClassNameCaseSniff.php create mode 100644 WordPress/Tests/WP/ClassNameCaseUnitTest.inc create mode 100644 WordPress/Tests/WP/ClassNameCaseUnitTest.php diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index e85cd14a6d..824543a3a3 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -673,4 +673,7 @@ + + + diff --git a/WordPress/Docs/WP/ClassNameCaseStandard.xml b/WordPress/Docs/WP/ClassNameCaseStandard.xml new file mode 100644 index 0000000000..b17ec3f955 --- /dev/null +++ b/WordPress/Docs/WP/ClassNameCaseStandard.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/WordPress/Sniffs/WP/ClassNameCaseSniff.php b/WordPress/Sniffs/WP/ClassNameCaseSniff.php new file mode 100644 index 0000000000..c7dc51cb17 --- /dev/null +++ b/WordPress/Sniffs/WP/ClassNameCaseSniff.php @@ -0,0 +1,416 @@ +wp_classes_lc = array_map( 'strtolower', $this->wp_classes ); + $this->wp_classes = array_combine( $this->wp_classes_lc, $this->wp_classes ); + } + + /** + * Groups of classes to restrict. + * + * @since 3.0.0 + * + * @return array + */ + public function getGroups() { + return array( + 'wp_classes' => array( + 'classes' => $this->wp_classes_lc, + ), + ); + } + + /** + * Process a matched token. + * + * @since 3.0.0 + * + * @param int $stackPtr The position of the current token in the stack. + * @param string $group_name The name of the group which was matched. Will + * always be 'wp_classes'. + * @param string $matched_content The token content (class name) which was matched. + * + * @return void + */ + public function process_matched_token( $stackPtr, $group_name, $matched_content ) { + + $matched_unqualified = ltrim( $matched_content, '\\' ); + $matched_lowercase = strtolower( $matched_unqualified ); + $matched_proper_case = $this->wp_classes[ $matched_lowercase ]; + + if ( $matched_unqualified === $matched_proper_case ) { + // Already using proper case, nothing to do. + return; + } + + $warning = 'It is strongly recommended to refer to classes by their properly cased name. Expected: %s Found: %s'; + $data = array( + $matched_proper_case, + $matched_unqualified, + ); + + $this->phpcsFile->addWarning( $warning, $stackPtr, 'Incorrect', $data ); + } +} diff --git a/WordPress/Tests/WP/ClassNameCaseUnitTest.inc b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc new file mode 100644 index 0000000000..8ae8ea507e --- /dev/null +++ b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc @@ -0,0 +1,53 @@ + => + */ + public function getErrorList() { + return array(); + } + + /** + * Returns the lines where warnings should occur. + * + * @return array => + */ + public function getWarningList() { + return array( + 30 => 1, + 31 => 1, + 33 => 1, + 35 => 1, + 36 => 1, + ); + } +} From 0c2b772cba8dc2fae8f83dd9f166c268141e4fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 27 Nov 2022 09:53:16 +0100 Subject: [PATCH 224/822] Group all the checks in one place and add script descriptions Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> Co-authored-by: Gary Jones --- .github/workflows/quicktest.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- composer.json | 21 +++++++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 294d964e18..0b2fcdea70 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -73,7 +73,7 @@ jobs: - name: Lint PHP files against parse errors if: ${{ matrix.phpcs_version == 'dev-master' }} - run: composer lint-ci + run: composer lint -- --checkstyle - name: Run unit tests run: composer run-tests diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 18fa870d3d..ad6df60843 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -95,7 +95,7 @@ jobs: - name: Lint PHP files against parse errors if: ${{ matrix.phpcs_version == 'dev-master' }} - run: composer lint-ci | cs2pr + run: composer lint -- --checkstyle | cs2pr - name: Run the unit tests - PHP 5.4 - 8.0 if: ${{ matrix.php < '8.1' }} diff --git a/composer.json b/composer.json index cf7705a04a..f9ec27028a 100644 --- a/composer.json +++ b/composer.json @@ -39,18 +39,12 @@ "lint": [ "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --show-deprecated --exclude vendor --exclude .git" ], - "lint-ci": [ - "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --show-deprecated --exclude vendor --exclude .git --checkstyle" - ], "check-cs": [ "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" ], "fix-cs": [ "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf" ], - "install-codestandards": [ - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run" - ], "run-tests": [ "@php ./vendor/phpunit/phpunit/phpunit --filter WordPress ./vendor/squizlabs/php_codesniffer/tests/AllTests.php" ], @@ -59,8 +53,23 @@ ], "check-complete-strict": [ "@php ./vendor/phpcsstandards/phpcsdevtools/bin/phpcs-check-feature-completeness ./WordPress" + ], + "check-all": [ + "@lint", + "@check-cs", + "@run-tests", + "@check-complete-strict" ] }, + "scripts-descriptions": { + "lint": "Lint PHP files against parse errors.", + "check-cs": "Run the PHPCS script against the entire codebase.", + "fix-cs": "Run the PHPCBF script to fix all the autofixable violations on the codebase.", + "run-tests": "Run all the unit tests for the WordPress Coding Standards sniffs.", + "check-complete": "Check if all the sniffs have tests.", + "check-complete-strict": "Check if all the sniffs have unit tests and XML documentation.", + "check-all": "Run all checks (lint, phpcs, feature completeness) and tests." + }, "support": { "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki", From 7605f1a6cd23dae199fea49c7d25c19f2bf0203e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 28 Nov 2022 21:07:14 +0100 Subject: [PATCH 225/822] WP/ClassNameCase: minor documentation tweaks --- WordPress/Sniffs/WP/ClassNameCaseSniff.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Sniffs/WP/ClassNameCaseSniff.php b/WordPress/Sniffs/WP/ClassNameCaseSniff.php index c7dc51cb17..b990593636 100644 --- a/WordPress/Sniffs/WP/ClassNameCaseSniff.php +++ b/WordPress/Sniffs/WP/ClassNameCaseSniff.php @@ -23,13 +23,13 @@ class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { /** * List of all WP native classes. * - * To be updated after every major release. - * * List is sorted alphabetically and based on the WIP autoloading PR. * {@link https://github.com/WordPress/wordpress-develop/pull/3470} * * Note: this list will be enhanced in the class constructor. * + * {@internal To be updated after every major release. Last updated for WordPress 6.1.1.} + * * @since 3.0.0 * * @var string[] The class names in their "proper" case. From a300c3be2e01e7df1ce557e13b4065488e7dbb8e Mon Sep 17 00:00:00 2001 From: jrfnl Date: Tue, 29 Nov 2022 02:34:12 +0100 Subject: [PATCH 226/822] WP/ClassNameCase: add support for examining classes in WP external dependencies Includes adding class lists for these external dependencies. Includes additional unit tests. Note: the `Sodium_Compat` dependency is explicitly not addressed as this is a polyfill for PHP Core, so to approach it, the PHP Core functions/classes should be used, not those declared within Sodium_Compat. --- WordPress/Sniffs/WP/ClassNameCaseSniff.php | 276 ++++++++++++++++++- WordPress/Tests/WP/ClassNameCaseUnitTest.inc | 16 +- WordPress/Tests/WP/ClassNameCaseUnitTest.php | 14 +- 3 files changed, 291 insertions(+), 15 deletions(-) diff --git a/WordPress/Sniffs/WP/ClassNameCaseSniff.php b/WordPress/Sniffs/WP/ClassNameCaseSniff.php index b990593636..7aa5b9d3e6 100644 --- a/WordPress/Sniffs/WP/ClassNameCaseSniff.php +++ b/WordPress/Sniffs/WP/ClassNameCaseSniff.php @@ -345,6 +345,179 @@ class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { 'wpdb', ); + /** + * List of all GetID3 classes include in WP Core. + * + * Note: this list will be enhanced in the class constructor. + * + * {@internal To be updated after every major release. Last updated for WordPress 6.1.1.} + * + * @since 3.0.0 + * + * @var string[] The class names in their "proper" case. + * The constructor will add the lowercased class name as a key to each entry. + */ + private $getid3_classes = array( + 'AMFReader', + 'AMFStream', + 'AVCSequenceParameterSetReader', + 'getID3', + 'getid3_ac3', + 'getid3_apetag', + 'getid3_asf', + 'getid3_dts', + 'getid3_exception', + 'getid3_flac', + 'getid3_flv', + 'getid3_handler', + 'getid3_id3v1', + 'getid3_id3v2', + 'getid3_lib', + 'getid3_lyrics3', + 'getid3_matroska', + 'getid3_mp3', + 'getid3_ogg', + 'getid3_quicktime', + 'getid3_riff', + ); + + /** + * List of all PHPMailer classes include in WP Core. + * + * Note: this list will be enhanced in the class constructor. + * + * {@internal To be updated after every major release. Last updated for WordPress 6.1.1.} + * + * @since 3.0.0 + * + * @var string[] The class names in their "proper" case. + * The constructor will add the lowercased class name as a key to each entry. + */ + private $phpmailer_classes = array( + 'PHPMailer\\PHPMailer\\Exception', + 'PHPMailer\\PHPMailer\\PHPMailer', + 'PHPMailer\\PHPMailer\\SMTP', + ); + + /** + * List of all Requests classes included in WP Core. + * + * Note: this list will be enhanced in the class constructor. + * + * {@internal To be updated after every major release. Last updated for WordPress 6.1.1.} + * + * @since 3.0.0 + * + * @var string[] The class names in their "proper" case. + * The constructor will add the lowercased class name as a key to each entry. + */ + private $requests_classes = array( + // Interfaces. + 'Requests_Auth', + 'Requests_Hooker', + 'Requests_Proxy', + 'Requests_Transport', + + // Classes. + 'Requests', + 'Requests_Auth_Basic', + 'Requests_Cookie', + 'Requests_Cookie_Jar', + 'Requests_Exception', + 'Requests_Exception_HTTP', + 'Requests_Exception_Transport', + 'Requests_Exception_Transport_cURL', + 'Requests_Exception_HTTP_304', + 'Requests_Exception_HTTP_305', + 'Requests_Exception_HTTP_306', + 'Requests_Exception_HTTP_400', + 'Requests_Exception_HTTP_401', + 'Requests_Exception_HTTP_402', + 'Requests_Exception_HTTP_403', + 'Requests_Exception_HTTP_404', + 'Requests_Exception_HTTP_405', + 'Requests_Exception_HTTP_406', + 'Requests_Exception_HTTP_407', + 'Requests_Exception_HTTP_408', + 'Requests_Exception_HTTP_409', + 'Requests_Exception_HTTP_410', + 'Requests_Exception_HTTP_411', + 'Requests_Exception_HTTP_412', + 'Requests_Exception_HTTP_413', + 'Requests_Exception_HTTP_414', + 'Requests_Exception_HTTP_415', + 'Requests_Exception_HTTP_416', + 'Requests_Exception_HTTP_417', + 'Requests_Exception_HTTP_418', + 'Requests_Exception_HTTP_428', + 'Requests_Exception_HTTP_429', + 'Requests_Exception_HTTP_431', + 'Requests_Exception_HTTP_500', + 'Requests_Exception_HTTP_501', + 'Requests_Exception_HTTP_502', + 'Requests_Exception_HTTP_503', + 'Requests_Exception_HTTP_504', + 'Requests_Exception_HTTP_505', + 'Requests_Exception_HTTP_511', + 'Requests_Exception_HTTP_Unknown', + 'Requests_Hooks', + 'Requests_IDNAEncoder', + 'Requests_IPv6', + 'Requests_IRI', + 'Requests_Proxy_HTTP', + 'Requests_Response', + 'Requests_Response_Headers', + 'Requests_Session', + 'Requests_SSL', + 'Requests_Transport_cURL', + 'Requests_Transport_fsockopen', + 'Requests_Utility_CaseInsensitiveDictionary', + 'Requests_Utility_FilteredIterator', + ); + + /** + * List of all SimplePier classes included in WP Core. + * + * Note: this list will be enhanced in the class constructor. + * + * {@internal To be updated after every major release. Last updated for WordPress 6.1.1.} + * + * @since 3.0.0 + * + * @var string[] The class names in their "proper" case. + * The constructor will add the lowercased class name as a key to each entry. + */ + private $simplepie_classes = array( + 'SimplePie', + 'SimplePie_Author', + 'SimplePie_Cache', + 'SimplePie_Caption', + 'SimplePie_Category', + 'SimplePie_Copyright', + 'SimplePie_Core', + 'SimplePie_Credit', + 'SimplePie_Enclosure', + 'SimplePie_Exception', + 'SimplePie_File', + 'SimplePie_gzdecode', + 'SimplePie_IRI', + 'SimplePie_Item', + 'SimplePie_Locator', + 'SimplePie_Misc', + 'SimplePie_Parser', + 'SimplePie_Rating', + 'SimplePie_Registry', + 'SimplePie_Restriction', + 'SimplePie_Sanitize', + 'SimplePie_Source', + 'SimplePie_Content_Type_Sniffer', + 'SimplePie_Decode_HTML_Entities', + 'SimplePie_HTTP_Parser', + 'SimplePie_Net_IPv6', + 'SimplePie_Parse_Date', + 'SimplePie_XML_Declaration_Parser', + ); + /** * List of all WP native classes in lowercase. * @@ -356,15 +529,77 @@ class ClassNameCaseSniff extends AbstractClassRestrictionsSniff { */ private $wp_classes_lc = array(); + /** + * List of all GetID3 classes in lowercase. + * + * This array is automatically generated in the class constructor based on the $phpmailer_classes property. + * + * @since 3.0.0 + * + * @var string[] The class names in lowercase. + */ + private $getid3_classes_lc = array(); + + /** + * List of all PHPMailer classes in lowercase. + * + * This array is automatically generated in the class constructor based on the $phpmailer_classes property. + * + * @since 3.0.0 + * + * @var string[] The class names in lowercase. + */ + private $phpmailer_classes_lc = array(); + + /** + * List of all Requests classes in lowercase. + * + * This array is automatically generated in the class constructor based on the $requests_classes property. + * + * @since 3.0.0 + * + * @var string[] The class names in lowercase. + */ + private $requests_classes_lc = array(); + + /** + * List of all SimplePie classes in lowercase. + * + * This array is automatically generated in the class constructor based on the $simplepie_classes property. + * + * @since 3.0.0 + * + * @var string[] The class names in lowercase. + */ + private $simplepie_classes_lc = array(); + + /** + * Groups names. + * + * Used to dynamically fill in some of the above properties and to generate the getGroups() array. + * + * @var array + */ + private $class_groups = array( + 'wp_classes', + 'getid3_classes', + 'phpmailer_classes', + 'requests_classes', + 'simplepie_classes', + ); + /** * Constructor. * * @since 3.0.0 */ public function __construct() { - // Adjust the $wp_classes property to have the lowercased version of the value as a key. - $this->wp_classes_lc = array_map( 'strtolower', $this->wp_classes ); - $this->wp_classes = array_combine( $this->wp_classes_lc, $this->wp_classes ); + // Adjust the class list properties to have the lowercased version of the value as a key. + foreach ( $this->class_groups as $name ) { + $name_lc = $name . '_lc'; + $this->$name_lc = array_map( 'strtolower', $this->$name ); + $this->$name = array_combine( $this->$name_lc, $this->$name ); + } } /** @@ -375,11 +610,15 @@ public function __construct() { * @return array */ public function getGroups() { - return array( - 'wp_classes' => array( - 'classes' => $this->wp_classes_lc, - ), - ); + $groups = array(); + foreach ( $this->class_groups as $name ) { + $name_lc = $name . '_lc'; + $groups[ $name ] = array( + 'classes' => $this->$name_lc, + ); + } + + return $groups; } /** @@ -398,7 +637,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $matched_unqualified = ltrim( $matched_content, '\\' ); $matched_lowercase = strtolower( $matched_unqualified ); - $matched_proper_case = $this->wp_classes[ $matched_lowercase ]; + $matched_proper_case = $this->get_proper_case( $matched_lowercase ); if ( $matched_unqualified === $matched_proper_case ) { // Already using proper case, nothing to do. @@ -413,4 +652,23 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $this->phpcsFile->addWarning( $warning, $stackPtr, 'Incorrect', $data ); } + + /** + * Match a lowercase class name to its proper cased name. + * + * @param string $matched_lc Lowercase class name. + * + * @return string + */ + private function get_proper_case( $matched_lc ) { + foreach ( $this->class_groups as $name ) { + $current = $this->$name; // Needed to prevent issues with PHP < 7.0. + if ( isset( $current[ $matched_lc ] ) ) { + return $current[ $matched_lc ]; + } + } + + // Shouldn't be possible. + return ''; // @codeCoverageIgnore + } } diff --git a/WordPress/Tests/WP/ClassNameCaseUnitTest.inc b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc index 8ae8ea507e..eccde3b20a 100644 --- a/WordPress/Tests/WP/ClassNameCaseUnitTest.inc +++ b/WordPress/Tests/WP/ClassNameCaseUnitTest.inc @@ -12,10 +12,10 @@ class Foo { $obj = new Not_A_WP_Core_Class(); + /* * These all use the class name in proper case. */ - $obj = new WP_Importer(); $obj = new \WP_Query; @@ -24,6 +24,13 @@ class MyList extends WP_List_Table {} echo WP_User_Search::$users_per_page; WP_Customize_New_Menu_Control::foo(); +// External libraries. +$obj = new getID3; +class MyMailer extends PHPMailer\PHPMailer\PHPMailer {} +$obj = new Requests_Cookie_Jar(); +$anon = class extends SimplePie_IRI {}; + + /* * These all use the class name in an unconventional case. */ @@ -35,6 +42,13 @@ class MyList extends \WP_LIST_table {} echo wp_user_search::$users_per_page; WP_Customize_NEW_Menu_Control::foo(); +// External libraries. +$obj = new GetID3(); +class MyMailer extends PhpMailer\PhpMailer\PhpMailer {} +$obj = new Requests_cookie_jar(); +$anon = class extends SimplePie_Iri {}; + + /* * These will not (yet) be detected as the abstract doesn't handle these. * This will be fixed in the future when the PHPCSUtils abstract will be made available. diff --git a/WordPress/Tests/WP/ClassNameCaseUnitTest.php b/WordPress/Tests/WP/ClassNameCaseUnitTest.php index 43806ce674..862ec11761 100644 --- a/WordPress/Tests/WP/ClassNameCaseUnitTest.php +++ b/WordPress/Tests/WP/ClassNameCaseUnitTest.php @@ -36,11 +36,15 @@ public function getErrorList() { */ public function getWarningList() { return array( - 30 => 1, - 31 => 1, - 33 => 1, - 35 => 1, - 36 => 1, + 37 => 1, + 38 => 1, + 40 => 1, + 42 => 1, + 43 => 1, + 46 => 1, + 47 => 1, + 48 => 1, + 49 => 1, ); } } From a9d9be35234e7f1182ebcfc9ba859679521a4657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Fri, 25 Nov 2022 11:55:52 +0100 Subject: [PATCH 227/822] Add sniff that will check that capabilities are used correctly. The sniff will check if the functions that are accepting capabilities as the argument actually use capabilities and not roles. It was rewritten to include helper functions from PHPCSUtils, cleanup code, and add additional tests. The list of core functions that are using capabilities as a parameter was updated with changes up to WordPress 6.1.0, as well as the list of capabilities. The sniff is also compatible with PHP 8 (named arguments). Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> Co-authored-by: Ulrich Pogson Co-authored-by: Kevin Haig Co-authored-by: Gary Jones --- WordPress-Extra/ruleset.xml | 3 + WordPress/Docs/WP/CapabilitiesStandard.xml | 69 +++ WordPress/Sniffs/WP/CapabilitiesSniff.php | 478 ++++++++++++++++++ WordPress/Tests/WP/CapabilitiesUnitTest.1.inc | 117 +++++ WordPress/Tests/WP/CapabilitiesUnitTest.2.inc | 14 + WordPress/Tests/WP/CapabilitiesUnitTest.3.inc | 14 + WordPress/Tests/WP/CapabilitiesUnitTest.php | 130 +++++ 7 files changed, 825 insertions(+) create mode 100644 WordPress/Docs/WP/CapabilitiesStandard.xml create mode 100644 WordPress/Sniffs/WP/CapabilitiesSniff.php create mode 100644 WordPress/Tests/WP/CapabilitiesUnitTest.1.inc create mode 100644 WordPress/Tests/WP/CapabilitiesUnitTest.2.inc create mode 100644 WordPress/Tests/WP/CapabilitiesUnitTest.3.inc create mode 100644 WordPress/Tests/WP/CapabilitiesUnitTest.php diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index 2c469a593e..111d39faa5 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -84,6 +84,9 @@ + + + diff --git a/WordPress/Docs/WP/CapabilitiesStandard.xml b/WordPress/Docs/WP/CapabilitiesStandard.xml new file mode 100644 index 0000000000..a65848e8e1 --- /dev/null +++ b/WordPress/Docs/WP/CapabilitiesStandard.xml @@ -0,0 +1,69 @@ + + + + + + + + 'manage_sites' ) ) { } + ]]> + + + 'manage_site', $user->ID ); + ]]> + + + + + + + + 'manage_options', + 'options_page_slug', + 'project_options_page_cb' +); + ]]> + + + 'author', + 'options_page_slug', + 'project_options_page_cb' +); + ]]> + + + + + + + + 'read' ) ) { } + ]]> + + + 'level_6' ) ) { } + ]]> + + + diff --git a/WordPress/Sniffs/WP/CapabilitiesSniff.php b/WordPress/Sniffs/WP/CapabilitiesSniff.php new file mode 100644 index 0000000000..b980be1d54 --- /dev/null +++ b/WordPress/Sniffs/WP/CapabilitiesSniff.php @@ -0,0 +1,478 @@ + The key is the name of a function we're targetting, + * the value is an array containing the 1-based parameter position + * of the "capability" parameter within the function, as well as + * the name of the parameter as declared in the function. + * If the parameter name has been renamed since the release of PHP 8.0, + * the parameter can be set as an array. + */ + protected $target_functions = array( + 'add_comments_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_dashboard_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_links_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_management_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_media_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_menu_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_object_page' => array( // Deprecated since WP 4.5.0. + 'position' => 3, + 'name' => 'capability', + ), + 'add_options_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_pages_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_plugins_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_posts_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_submenu_page' => array( + 'position' => 4, + 'name' => 'capability', + ), + 'add_theme_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_users_page' => array( + 'position' => 3, + 'name' => 'capability', + ), + 'add_utility_page' => array( // Deprecated since WP 4.5.0. + 'position' => 3, + 'name' => 'capability', + ), + 'author_can' => array( + 'position' => 2, + 'name' => 'capability', + ), + 'current_user_can' => array( + 'position' => 1, + 'name' => 'capability', + ), + 'current_user_can_for_blog' => array( + 'position' => 2, + 'name' => 'capability', + ), + 'map_meta_cap' => array( + 'position' => 1, + 'name' => 'cap', + ), + 'user_can' => array( + 'position' => 2, + 'name' => 'capability', + ), + ); + + /** + * List of core roles which should not to be used directly. + * + * @since 3.0.0 + * + * @var array Role available in WP Core. + */ + private $core_roles = array( + 'super_admin' => true, + 'administrator' => true, + 'editor' => true, + 'author' => true, + 'contributor' => true, + 'subscriber' => true, + ); + + /** + * List of known primitive and meta core capabilities. + * + * Sources: + * - {@link https://wordpress.org/support/article/roles-and-capabilities/ Roles and Capabilities handbook page} + * - The `map_meta_cap()` function in the `src/wp-includes/capabilities.php` file. + * - The tests in the `tests/phpunit/tests/user/capabilities.php` file. + * + * List is sorted alphabetically. + * + * {@internal To be updated after every major release. Last updated for WordPress 6.1.0.} + * + * @since 3.0.0 + * + * @var array All capabilities available in core. + */ + private $core_capabilities = array( + 'activate_plugin' => true, + 'activate_plugins' => true, + 'add_comment_meta' => true, + 'add_post_meta' => true, + 'add_term_meta' => true, + 'add_user_meta' => true, + 'add_users' => true, + 'assign_categories' => true, + 'assign_post_tags' => true, + 'assign_term' => true, + 'create_app_password' => true, + 'create_sites' => true, + 'create_users' => true, + 'customize' => true, + 'deactivate_plugin' => true, + 'deactivate_plugins' => true, + 'delete_app_password' => true, + 'delete_app_passwords' => true, + 'delete_block' => true, // Only seen in tests. + 'delete_blocks' => true, // Alias for 'delete_posts', but supported. + 'delete_categories' => true, + 'delete_comment_meta' => true, + 'delete_others_blocks' => true, // Alias for 'delete_others_posts', but supported. + 'delete_others_pages' => true, + 'delete_others_posts' => true, + 'delete_page' => true, // Alias, but supported. + 'delete_pages' => true, + 'delete_plugins' => true, + 'delete_post_tags' => true, + 'delete_post' => true, // Alias, but supported. + 'delete_post_meta' => true, + 'delete_posts' => true, + 'delete_private_blocks' => true, // Alias for 'delete_private_posts', but supported. + 'delete_private_pages' => true, + 'delete_private_posts' => true, + 'delete_published_blocks' => true, // Alias for 'delete_published_posts', but supported. + 'delete_published_pages' => true, + 'delete_published_posts' => true, + 'delete_site' => true, + 'delete_sites' => true, + 'delete_term' => true, + 'delete_term_meta' => true, + 'delete_themes' => true, + 'delete_user' => true, // Alias for 'delete_users', but supported. + 'delete_user_meta' => true, + 'delete_users' => true, + 'edit_app_password' => true, + 'edit_categories' => true, + 'edit_block' => true, // Only seen in tests. + 'edit_blocks' => true, // Alias for 'edit_posts', but supported. + 'edit_comment' => true, // Alias, but supported. + 'edit_comment_meta' => true, + 'edit_css' => true, + 'edit_dashboard' => true, + 'edit_files' => true, + 'edit_others_blocks' => true, // Alias for 'edit_others_posts', but supported. + 'edit_others_pages' => true, + 'edit_others_posts' => true, + 'edit_page' => true, // Alias, but supported. + 'edit_pages' => true, + 'edit_plugins' => true, + 'edit_post_tags' => true, + 'edit_post' => true, // Alias, but supported. + 'edit_post_meta' => true, + 'edit_posts' => true, + 'edit_private_blocks' => true, // Alias for 'edit_private_posts', but supported. + 'edit_private_pages' => true, + 'edit_private_posts' => true, + 'edit_published_blocks' => true, // Alias for 'edit_published_posts', but supported. + 'edit_published_pages' => true, + 'edit_published_posts' => true, + 'edit_term' => true, + 'edit_term_meta' => true, + 'edit_theme_options' => true, + 'edit_themes' => true, + 'edit_user' => true, // Alias for 'edit_users', but supported. + 'edit_user_meta' => true, + 'edit_users' => true, + 'erase_others_personal_data' => true, + 'export' => true, + 'export_others_personal_data' => true, + 'import' => true, + 'install_languages' => true, + 'install_plugins' => true, + 'install_themes' => true, + 'list_app_passwords' => true, + 'list_users' => true, + 'manage_categories' => true, + 'manage_links' => true, + 'manage_network' => true, + 'manage_network_options' => true, + 'manage_network_plugins' => true, + 'manage_network_themes' => true, + 'manage_network_users' => true, + 'manage_options' => true, + 'manage_post_tags' => true, + 'manage_privacy_options' => true, + 'manage_sites' => true, + 'moderate_comments' => true, + 'publish_blocks' => true, // Alias for 'publish_posts', but supported. + 'publish_pages' => true, + 'publish_post' => true, // Alias, but supported. + 'publish_posts' => true, + 'promote_user' => true, + 'promote_users' => true, + 'read' => true, + 'read_block' => true, // Only seen in tests. + 'read_post' => true, // Alias, but supported. + 'read_page' => true, // Alias, but supported. + 'read_app_password' => true, + 'read_private_blocks' => true, // Alias for 'read_private_posts', but supported. + 'read_private_pages' => true, + 'read_private_posts' => true, + 'remove_user' => true, // Alias for 'remove_users', but supported. + 'remove_users' => true, + 'resume_plugin' => true, // Alias for 'resume_plugins', but supported. + 'resume_plugins' => true, + 'resume_theme' => true, // Alias for 'resume_themes', but supported. + 'resume_themes' => true, + 'setup_network' => true, + 'switch_themes' => true, + 'unfiltered_html' => true, + 'unfiltered_upload' => true, + 'update_core' => true, + 'update_https' => true, + 'update_languages' => true, + 'update_plugins' => true, + 'update_php' => true, + 'update_themes' => true, + 'upgrade_network' => true, + 'upload_files' => true, + 'upload_plugins' => true, + 'upload_themes' => true, + 'view_site_health_checks' => true, + ); + + /** + * List of deprecated core capabilities. + * + * User Levels were deprecated in version 3.0. + * + * {@internal To be updated after every major release. Last updated for WordPress 6.1.0.} + * + * @link https://github.com/WordPress/wordpress-develop/blob/master/tests/phpunit/tests/user/capabilities.php + * + * @since 3.0.0 + * + * @var array All deprecated capabilities in core. + */ + private $deprecated_capabilities = array( + 'level_10' => '3.0.0', + 'level_9' => '3.0.0', + 'level_8' => '3.0.0', + 'level_7' => '3.0.0', + 'level_6' => '3.0.0', + 'level_5' => '3.0.0', + 'level_4' => '3.0.0', + 'level_3' => '3.0.0', + 'level_2' => '3.0.0', + 'level_1' => '3.0.0', + 'level_0' => '3.0.0', + ); + + /** + * Process the parameters of a matched function. + * + * @since 3.0.0 + * + * @param int $stackPtr The position of the current token in the stack. + * @param array $group_name The name of the group which was matched. + * @param string $matched_content The token content (function name) which was matched. + * @param array $parameters Array with information about the parameters. + * + * @return void + */ + public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) { + $function_name_lc = strtolower( $matched_content ); + $function_details = $this->target_functions[ $function_name_lc ]; + + $parameter = PassedParameters::getParameterFromStack( + $parameters, + $function_details['position'], + $function_details['name'] + ); + + if ( false === $parameter ) { + return; + } + + // If the parameter is anything other than T_CONSTANT_ENCAPSED_STRING throw a warning and bow out. + $first_non_empty = null; + for ( $i = $parameter['start']; $i <= $parameter['end']; $i++ ) { + if ( isset( Tokens::$emptyTokens[ $this->tokens[ $i ]['code'] ] ) ) { + continue; + } + + if ( \T_CONSTANT_ENCAPSED_STRING !== $this->tokens[ $i ]['code'] + || null !== $first_non_empty + ) { + // Throw warning at low severity. + $this->phpcsFile->addWarning( + 'Couldn\'t determine the value passed to the $%s parameter in function call to %s(). Please check if it matches a valid capability. Found: %s', + $i, + 'Undetermined', + array( + $function_details['name'], + $matched_content, + $parameter['clean'], + ), + 3 // Message severity set to below default. + ); + return; + } + + $first_non_empty = $i; + } + + if ( null === $first_non_empty ) { + // Parse error. Bow out. + return; + } + + /* + * As of this point we know that the `$capabilities` parameter only contains the one token + * and that that token is a `T_CONSTANT_ENCAPSED_STRING`. + */ + $matched_parameter = TextStrings::stripQuotes( $this->tokens[ $first_non_empty ]['content'] ); + + if ( isset( $this->core_capabilities[ $matched_parameter ] ) ) { + return; + } + + if ( empty( $matched_parameter ) ) { + $this->phpcsFile->addError( + 'An empty string is not a valid capability. Empty string found as the $%s parameter in a function call to %s()"', + $first_non_empty, + 'Invalid', + array( + $function_details['name'], + $matched_content, + ) + ); + return; + } + + // Check if additional capabilities were registered via the ruleset and if the found capability matches any of those. + $custom_capabilities = $this->merge_custom_array( $this->custom_capabilities, array() ); + if ( isset( $custom_capabilities[ $matched_parameter ] ) ) { + return; + } + + if ( isset( $this->deprecated_capabilities[ $matched_parameter ] ) ) { + $this->get_wp_version_from_cli( $this->phpcsFile ); + $is_error = version_compare( $this->deprecated_capabilities[ $matched_parameter ], $this->minimum_supported_version, '<' ); + + $data = array( + $matched_parameter, + $matched_content, + $this->deprecated_capabilities[ $matched_parameter ], + ); + + MessageHelper::addMessage( + $this->phpcsFile, + 'The capability "%s", found in the function call to %s(), has been deprecated since WordPress version %s.', + $first_non_empty, + $is_error, + 'Deprecated', + $data + ); + return; + } + + if ( isset( $this->core_roles[ $matched_parameter ] ) ) { + $this->phpcsFile->addError( + 'Capabilities should be used instead of roles. Found "%s" in function call to %s()', + $first_non_empty, + 'RoleFound', + array( + $matched_parameter, + $matched_content, + ) + ); + return; + } + + $this->phpcsFile->addWarning( + 'Found unknown capability "%s" in function call to %s(). Please check the spelling of the capability. If this is a custom capability, please verify the capability is registered with WordPress via a call to WP_Role(s)->add_cap().' . \PHP_EOL . 'Custom capabilities can be made known to this sniff by setting the "custom_capabilities" property in the PHPCS ruleset.', + $first_non_empty, + 'Unknown', + array( + $matched_parameter, + $matched_content, + ) + ); + } + +} diff --git a/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc b/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc new file mode 100644 index 0000000000..40226dcdc5 --- /dev/null +++ b/WordPress/Tests/WP/CapabilitiesUnitTest.1.inc @@ -0,0 +1,117 @@ +ID ); // OK. + +/* + * Low severity warnings, usually these need to be manually checked. + */ +add_posts_page( 'page_title', 'menu_title', 'admin' . 'istrator', 'menu_slug', 'function' ); // Low severity warning. +if ( author_can( $post, $capability ) ) { } // Low severity warning. +add_submenu_page( + 'parent_slug', + 'page_title', + 'menu_title', + $variable, // Low severity warning. + 'menu_slug', + 'function' +); +add_menu_page( $pagetitle, $menu_title, $subscriber, 'handle', 'function', 'icon_url' ); // Low severity warning. +add_plugins_page( 'page_title', 'menu_title', $cap, 'menu_slug', 'function' ); // Low severity warning. +add_options_page( $pagetitle, $menu_title, CONSTANT, 'menu_slug', 'function' ); // Low severity warning. +add_posts_page( 'page_title', 'menu_title', self /* comment */ :: CAPABILITY, 'menu_slug', 'function' ); // Low severity warning. +add_posts_page( 'page_title', 'menu_title', 'admin' /* comment */ . 'istrator', 'menu_slug', 'function' ); // Low severity warning. +add_menu_page( + $p, + $t, // Comment. + $capability, // Low severity warning. +); +add_menu_page( $p, $t, 'admin' . 'istrator' ); // Low severity warning. +add_menu_page($p, $t, $caps['level'] ); // Low severity warning. + +// Parse error, but just making sure we account for all possibilities. +add_menu_page($p, $t, 'level_' 'level' ); // Low severity warning. + +/* + * Empty capability parameter. + */ +if ( author_can( $post, '' ) ) { } // Error. + +/* + * Deprecated capabilities. + */ +// phpcs:set WordPress.WP.Capabilities minimum_supported_version 2.9 +if ( author_can( $post, 'level_3' ) ) { } // Warning. + +// phpcs:set WordPress.WP.Capabilities minimum_supported_version 5.9 +if ( author_can( $post, 'level_5' ) ) { } // Error. +add_options_page( 'page_title', 'menu_title', 'level_10', 'menu_slug', 'function' ); // Error. + +/* + * Unknown capabilities, could be that they need to be set in the property, but weren't. + */ +if ( author_can( $post, 'custom_cap' ) ) { } // Warning. +if ( current_user_can( 'foo_bar' ) ) { } // Warning. +if ( current_user_can_for_blog( '3', 'custom_cap' ) ) { } // Warning. +add_users_page( 'page_title', 'menu_title', 'foo_bar', 'menu_slug', 'function' ); // Warning. +add_management_page( 'page_title', 'menu_title', 'foo_bar', 'menu_slug', 'function' ); // Warning. +add_menu_page( $pagetitle, 'menu_title', 'foo_bar', 'handle', 'function', 'icon_url' ); // Warning. + +/* + * Roles found instead of capabilities. + */ +add_posts_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Error. +add_media_page( 'page_title', 'menu_title', 'editor', 'menu_slug', 'function' ); // Error. +add_pages_page( 'page_title', 'menu_title', 'author', 'menu_slug', 'function' ); // Error. +add_comments_page( 'page_title', 'menu_title', 'contributor', 'menu_slug', 'function' ); // Error. +add_theme_page( 'page_title', $menu_title, 'subscriber', 'menu_slug', 'function' ); // Error. +add_plugins_page( 'page_title', 'menu_title', 'super_admin', 'menu_slug', 'function' ); // Error. +add_users_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Error. +add_management_page( 'page_title', 'menu_title', 'editor', 'menu_slug', 'function' ); // Error. +if ( current_user_can( 'super_admin' ) ) { } // Error. +if( current_user_can_for_blog( '1', 'editor' ) ) { } // Error. +add_dashboard_page( + 'page_title', + 'menu_title', + 'super_admin' /* Comment */, // Error. + 'menu_slug', + 'function' +); +add_utility_page( + 'page_title' + ,'menu_title' + ,'super_admin' // Error. + ,'menu_slug' + ,'function' + ,'icon_url' +); + +// PHP 8.0 named parameters support. +add_menu_page( capability: 'foobar', page_title: $p, menu_title: $m ); // Warning. + +/* + * Testing handling of the custom capabilities properties. + */ +// phpcs:set WordPress.WP.Capabilities custom_capabilities[] custom_cap,foo_bar +if ( current_user_can( 'foo_bar' ) ) { } // OK. +if ( author_can( $post, 'custom_cap' ) ) { } // OK. +if ( author_can( $post, 'custom_capability' ) ) { } // Warning. + +// phpcs:set WordPress.WP.Capabilities custom_capabilities[] + +// Making sure that the warnings and errors are showing up in the case where we unset the custom capabilities. +if ( author_can( $post, 'custom_cap' ) ) { } // Warning. +map_meta_cap( 'editor', $user->ID ); // Error. + +// Another parse error, but the sniff should still handle this correctly (by bowing out). +add_menu_page( $p, $t, /* deliberately empty */, $slug, ); + +add_menu_page( [] ); // Should bow out because the parameter is not found. + +$obj->current_user_can( 'foo_bar' ); // Ok. We're not checking for method calls. +My\NamespaceS\add_posts_page( 'page_title', 'menu_title', 'administrator', 'menu_slug', 'function' ); // Ok. We're not checking namespaced functions. + +// Parse error, should be handled correctly by bowing out. +add_posts_page( 'page_title', diff --git a/WordPress/Tests/WP/CapabilitiesUnitTest.2.inc b/WordPress/Tests/WP/CapabilitiesUnitTest.2.inc new file mode 100644 index 0000000000..acc1d5aaf1 --- /dev/null +++ b/WordPress/Tests/WP/CapabilitiesUnitTest.2.inc @@ -0,0 +1,14 @@ +warningSeverity = 3; + } elseif ( 'CapabilitiesUnitTest.2.inc' === $filename ) { + Helper::setConfigData( 'minimum_supported_wp_version', '2.9', true, $config ); + } elseif ( 'CapabilitiesUnitTest.3.inc' === $filename ) { + Helper::setConfigData( 'minimum_supported_wp_version', '6.1', true, $config ); + } else { + // Delete for other files. + Helper::setConfigData( 'minimum_supported_wp_version', null, true, $config ); + } + } + + /** + * Returns the lines where errors should occur. + * + * @param string $testFile The name of the file being tested. + * + * @return array => + */ + public function getErrorList( $testFile = '' ) { + switch ( $testFile ) { + case 'CapabilitiesUnitTest.1.inc': + return array( + 40 => 1, + 49 => 1, + 50 => 1, + 65 => 1, + 66 => 1, + 67 => 1, + 68 => 1, + 69 => 1, + 70 => 1, + 71 => 1, + 72 => 1, + 73 => 1, + 74 => 1, + 78 => 1, + 85 => 1, + 106 => 1, + ); + + case 'CapabilitiesUnitTest.3.inc': + return array( + 10 => 1, + 12 => 1, + 14 => 1, + ); + + default: + return array(); + } + } + + /** + * Returns the lines where warnings should occur. + * + * @param string $testFile The name of the file being tested. + * + * @return array => + */ + public function getWarningList( $testFile = '' ) { + switch ( $testFile ) { + case 'CapabilitiesUnitTest.1.inc': + return array( + 11 => 1, + 12 => 1, + 17 => 1, + 21 => 1, + 22 => 1, + 23 => 1, + 24 => 1, + 25 => 1, + 29 => 1, + 31 => 1, + 32 => 1, + 35 => 1, + 46 => 1, + 55 => 1, + 56 => 1, + 57 => 1, + 58 => 1, + 59 => 1, + 60 => 1, + 92 => 1, + 100 => 1, + 105 => 1, + ); + + case 'CapabilitiesUnitTest.2.inc': + return array( + 10 => 1, + 12 => 1, + 14 => 1, + ); + + default: + return array(); + } + } +} From 8c7b230da4313472c8fe6afb421f43e9598b95c2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 26 Nov 2022 14:48:21 +0100 Subject: [PATCH 228/822] MinimumWPVersionTrait: rename minimum WP version property As discussed in 2113, this changes the name for both the CLI setting as well as the property to `minimum_wp_version` in all applicable places. Note: documentation (`phpcs.xml.dist.sample` and the Wiki) is not being updated in this PR. The wiki should be reviewed and updated just before release. The update to the `phpcs.xml.dist.sample` file is included in a WIP PR to update all public facing documentation just before the release. Closes 2113 --- WordPress/Helpers/MinimumWPVersionTrait.php | 35 ++++++++++--------- .../Sniffs/WP/AlternativeFunctionsSniff.php | 6 ++-- WordPress/Sniffs/WP/CapabilitiesSniff.php | 4 ++- .../Sniffs/WP/DeprecatedClassesSniff.php | 4 +-- .../Sniffs/WP/DeprecatedFunctionsSniff.php | 4 +-- .../WP/DeprecatedParameterValuesSniff.php | 4 +-- .../Sniffs/WP/DeprecatedParametersSniff.php | 4 +-- .../Tests/WP/AlternativeFunctionsUnitTest.inc | 10 +++--- WordPress/Tests/WP/CapabilitiesUnitTest.1.inc | 4 +-- WordPress/Tests/WP/CapabilitiesUnitTest.php | 6 ++-- 10 files changed, 42 insertions(+), 39 deletions(-) diff --git a/WordPress/Helpers/MinimumWPVersionTrait.php b/WordPress/Helpers/MinimumWPVersionTrait.php index 232fddc7cf..96810d3578 100644 --- a/WordPress/Helpers/MinimumWPVersionTrait.php +++ b/WordPress/Helpers/MinimumWPVersionTrait.php @@ -19,7 +19,7 @@ * - Add appropriate `use` statement(s) to the file/class which intends to use this functionality. * - Call the `MinimumWPVersionTrait::get_wp_version_from_cli()` method in the `process()`/`process_token()` * method. - * - After that, the `MinimumWPVersionTrait::$minimum_supported_version` property can be freely used + * - After that, the `MinimumWPVersionTrait::$minimum_wp_version` property can be freely used * in the sniff. * * @package WPCS\WordPressCodingStandards @@ -32,12 +32,12 @@ trait MinimumWPVersionTrait { * Minimum supported WordPress version. * * Currently used by the `WordPress.WP.AlternativeFunctions`, - * `WordPress.WP.DeprecatedClasses`, `WordPress.WP.DeprecatedFunctions`, - * `WordPress.WP.DeprecatedParameter` and the `WordPress.WP.DeprecatedParameterValues` sniff. + * `WordPress.WP.Capabilities`, `WordPress.WP.DeprecatedClasses`, + * `WordPress.WP.DeprecatedFunctions`, `WordPress.WP.DeprecatedParameter` + * and the `WordPress.WP.DeprecatedParameterValues` sniff. * - * These sniffs will throw an error when usage of a deprecated class/function/parameter - * is detected if the class/function/parameter was deprecated before the minimum - * supported WP version; a warning otherwise. + * These sniffs will adapt their behaviour based on the minimum supported WP version + * indicated. * By default, it is set to presume that a project will support the current * WP version and up to three releases before. * @@ -48,41 +48,42 @@ trait MinimumWPVersionTrait { * Example usage: * * - * + * * * * - * Alternatively, the value can be passed in one go for all sniff using it via + * Alternatively, the value can be passed in one go for all sniffs using it via * the command line or by setting a `` value in a custom phpcs.xml ruleset. - * Note: the `_wp_` in the command line property name! * - * CL: `phpcs --runtime-set minimum_supported_wp_version 4.5` - * Ruleset: `` + * CL: `phpcs --runtime-set minimum_wp_version 4.5` + * Ruleset: `` * * @since 0.14.0 Previously the individual sniffs each contained this property. - * @since 3.0.0 Moved from the Sniff class to this dedicated Trait. + * @since 3.0.0 - Moved from the Sniff class to this dedicated Trait. + * - The property has been renamed from `$minimum_supported_version` to `$minimum_wp_version`. + * - The CLI option has been renamed from `minimum_supported_wp_version` to `minimum_wp_version`. * * @internal When the value of this property is changed, it will also need * to be changed in the `WP/AlternativeFunctionsUnitTest.inc` file. * * @var string WordPress version. */ - public $minimum_supported_version = '5.1'; + public $minimum_wp_version = '5.1'; /** * Overrule the minimum supported WordPress version with a command-line/config value. * * Handle setting the minimum supported WP version in one go for all sniffs which * expect it via the command line or via a `` variable in a ruleset. - * The config variable overrules the default `$minimum_supported_version` and/or a - * `$minimum_supported_version` set for individual sniffs through the ruleset. + * The config variable overrules the default `$minimum_wp_version` and/or a + * `$minimum_wp_version` set for individual sniffs through the ruleset. * * @since 0.14.0 * @since 3.0.0 - Moved from the Sniff class to this dedicated Trait. * - Renamed from `get_wp_version_from_cl()` to `get_wp_version_from_cli()`. */ protected function get_wp_version_from_cli() { - $cli_supported_version = Helper::getConfigData( 'minimum_supported_wp_version' ); + $cli_supported_version = Helper::getConfigData( 'minimum_wp_version' ); if ( empty( $cli_supported_version ) ) { return; @@ -92,7 +93,7 @@ protected function get_wp_version_from_cli() { if ( ! empty( $cli_supported_version ) && filter_var( $cli_supported_version, \FILTER_VALIDATE_FLOAT ) !== false ) { - $this->minimum_supported_version = $cli_supported_version; + $this->minimum_wp_version = $cli_supported_version; } } diff --git a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php index cad367fcc4..cccaf5ddaf 100644 --- a/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php +++ b/WordPress/Sniffs/WP/AlternativeFunctionsSniff.php @@ -24,7 +24,7 @@ * @since 1.0.0 - Takes the minimum supported WP version into account. * - Takes exceptions based on passed parameters into account. * - * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_supported_version + * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_wp_version */ class AlternativeFunctionsSniff extends AbstractFunctionRestrictionsSniff { @@ -210,7 +210,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content * @see https://developer.wordpress.org/reference/functions/wp_parse_url/#changelog */ if ( PassedParameters::getParameterCount( $this->phpcsFile, $stackPtr ) !== 1 - && version_compare( $this->minimum_supported_version, '4.7.0', '<' ) + && version_compare( $this->minimum_wp_version, '4.7.0', '<' ) ) { return; } @@ -288,7 +288,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content } // Verify if the alternative is available in the minimum supported WP version. - if ( version_compare( $this->groups[ $group_name ]['since'], $this->minimum_supported_version, '<=' ) ) { + if ( version_compare( $this->groups[ $group_name ]['since'], $this->minimum_wp_version, '<=' ) ) { return parent::process_matched_token( $stackPtr, $group_name, $matched_content ); } } diff --git a/WordPress/Sniffs/WP/CapabilitiesSniff.php b/WordPress/Sniffs/WP/CapabilitiesSniff.php index b980be1d54..942b6b6b92 100644 --- a/WordPress/Sniffs/WP/CapabilitiesSniff.php +++ b/WordPress/Sniffs/WP/CapabilitiesSniff.php @@ -24,6 +24,8 @@ * @package WPCS\WordPressCodingStandards * * @since 3.0.0 + * + * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_wp_version */ class CapabilitiesSniff extends AbstractFunctionParameterSniff { @@ -432,7 +434,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p if ( isset( $this->deprecated_capabilities[ $matched_parameter ] ) ) { $this->get_wp_version_from_cli( $this->phpcsFile ); - $is_error = version_compare( $this->deprecated_capabilities[ $matched_parameter ], $this->minimum_supported_version, '<' ); + $is_error = version_compare( $this->deprecated_capabilities[ $matched_parameter ], $this->minimum_wp_version, '<' ); $data = array( $matched_parameter, diff --git a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php index c1fd8e051d..effc42dfab 100644 --- a/WordPress/Sniffs/WP/DeprecatedClassesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedClassesSniff.php @@ -30,7 +30,7 @@ * being provided via the command-line or as as value * in a custom ruleset. * - * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_supported_version + * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_wp_version */ class DeprecatedClassesSniff extends AbstractClassRestrictionsSniff { @@ -116,7 +116,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $this->phpcsFile, $message, $stackPtr, - ( version_compare( $this->deprecated_classes[ $class_name ]['version'], $this->minimum_supported_version, '<' ) ), + ( version_compare( $this->deprecated_classes[ $class_name ]['version'], $this->minimum_wp_version, '<' ) ), MessageHelper::stringToErrorcode( $class_name . 'Found' ), $data ); diff --git a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php index b9379c4e54..2e5968d083 100644 --- a/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedFunctionsSniff.php @@ -30,7 +30,7 @@ * being provided via the command-line or as as value * in a custom ruleset. * - * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_supported_version + * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_wp_version */ class DeprecatedFunctionsSniff extends AbstractFunctionRestrictionsSniff { @@ -1418,7 +1418,7 @@ public function process_matched_token( $stackPtr, $group_name, $matched_content $this->phpcsFile, $message, $stackPtr, - ( version_compare( $this->deprecated_functions[ $function_name ]['version'], $this->minimum_supported_version, '<' ) ), + ( version_compare( $this->deprecated_functions[ $function_name ]['version'], $this->minimum_wp_version, '<' ) ), MessageHelper::stringToErrorcode( $matched_content . 'Found' ), $data ); diff --git a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php index be90ca7075..c726a840ef 100644 --- a/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParameterValuesSniff.php @@ -22,7 +22,7 @@ * * @since 1.0.0 * - * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_supported_version + * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_wp_version */ class DeprecatedParameterValuesSniff extends AbstractFunctionParameterSniff { @@ -208,7 +208,7 @@ protected function process_parameter( $matched_content, $parameter, $parameter_a $data[] = $parameter_args[ $matched_parameter ]['alt']; } - $is_error = version_compare( $parameter_args[ $matched_parameter ]['version'], $this->minimum_supported_version, '<' ); + $is_error = version_compare( $parameter_args[ $matched_parameter ]['version'], $this->minimum_wp_version, '<' ); MessageHelper::addMessage( $this->phpcsFile, $message, diff --git a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php index 787da50856..623e5fbc7e 100644 --- a/WordPress/Sniffs/WP/DeprecatedParametersSniff.php +++ b/WordPress/Sniffs/WP/DeprecatedParametersSniff.php @@ -31,7 +31,7 @@ * being provided via the command-line or as as value * in a custom ruleset. * - * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_supported_version + * @uses \WordPressCS\WordPress\Helpers\MinimumWPVersionTrait::$minimum_wp_version */ class DeprecatedParametersSniff extends AbstractFunctionParameterSniff { @@ -319,7 +319,7 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p } $message = 'The parameter "%s" at position #%s of %s() has been deprecated since WordPress version %s.'; - $is_error = version_compare( $parameter_args['version'], $this->minimum_supported_version, '<' ); + $is_error = version_compare( $parameter_args['version'], $this->minimum_wp_version, '<' ); $code = MessageHelper::stringToErrorcode( ucfirst( $matched_content ) . 'Param' . $position . 'Found' ); $data = array( diff --git a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc index d819f25a11..c74000b6d5 100644 --- a/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc +++ b/WordPress/Tests/WP/AlternativeFunctionsUnitTest.inc @@ -28,17 +28,17 @@ srand(); // Warning. mt_srand(); // Warning. wp_rand(); // OK. -// phpcs:set WordPress.WP.AlternativeFunctions minimum_supported_version 4.0 +// phpcs:set WordPress.WP.AlternativeFunctions minimum_wp_version 4.0 parse_url( 'http://example.com/' ); // OK. -// phpcs:set WordPress.WP.AlternativeFunctions minimum_supported_version 4.6 +// phpcs:set WordPress.WP.AlternativeFunctions minimum_wp_version 4.6 strip_tags( $something, '