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