From 1b2153fb9a8c682a15172135437979f0742282c3 Mon Sep 17 00:00:00 2001 From: Sergio Vera Date: Mon, 15 Nov 2021 10:45:27 +0100 Subject: [PATCH 1/5] AC-1059: Move PHPCompatibility rules from Magento tests --- Magento2/ruleset.xml | 6 ++++ composer.json | 3 +- composer.lock | 78 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/Magento2/ruleset.xml b/Magento2/ruleset.xml index c200c35e..0ea74416 100644 --- a/Magento2/ruleset.xml +++ b/Magento2/ruleset.xml @@ -738,3 +738,9 @@ 0 + + Magento 2 specific ruleset which checks for PHP cross version compatibility. + + + + diff --git a/composer.json b/composer.json index 36a71bbf..cf6dd7e4 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "squizlabs/php_codesniffer": "^3.6", "webonyx/graphql-php": "^14.9", "ext-simplexml": "*", - "ext-dom": "*" + "ext-dom": "*", + "phpcompatibility/php-compatibility": "^9.3" }, "require-dev": { "phpunit/phpunit": "^9.5.8" diff --git a/composer.lock b/composer.lock index 8346f504..b8be775a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,70 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ccc9b708a197fb981876af4623ec26a3", + "content-hash": "a726e6e7caa0f654b55b3a78d8ea170b", "packages": [ + { + "name": "phpcompatibility/php-compatibility", + "version": "9.3.5", + "source": { + "type": "git", + "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", + "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", + "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" + }, + "conflict": { + "squizlabs/php_codesniffer": "2.6.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" + }, + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "homepage": "https://github.com/wimg", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" + } + ], + "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", + "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", + "keywords": [ + "compatibility", + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", + "source": "https://github.com/PHPCompatibility/PHPCompatibility" + }, + "time": "2019-12-27T09:44:58+00:00" + }, { "name": "squizlabs/php_codesniffer", "version": "3.6.1", @@ -1501,16 +1563,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", "shasum": "" }, "require": { @@ -1559,14 +1621,14 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" }, "funding": [ { @@ -1574,7 +1636,7 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2021-11-11T14:18:36+00:00" }, { "name": "sebastian/global-state", From 1d3fa20c044c2cc0811af0f071ff93eb40d752db Mon Sep 17 00:00:00 2001 From: Sergio Vera Date: Mon, 15 Nov 2021 14:24:23 +0100 Subject: [PATCH 2/5] AC-1059: Move PHPCompatibility rules from Magento tests --- Magento2/ruleset.xml | 6 ------ PHPCompatibilityMagento/ruleset.xml | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 PHPCompatibilityMagento/ruleset.xml diff --git a/Magento2/ruleset.xml b/Magento2/ruleset.xml index 0ea74416..c200c35e 100644 --- a/Magento2/ruleset.xml +++ b/Magento2/ruleset.xml @@ -738,9 +738,3 @@ 0 - - Magento 2 specific ruleset which checks for PHP cross version compatibility. - - - - diff --git a/PHPCompatibilityMagento/ruleset.xml b/PHPCompatibilityMagento/ruleset.xml new file mode 100644 index 00000000..b69dae75 --- /dev/null +++ b/PHPCompatibilityMagento/ruleset.xml @@ -0,0 +1,16 @@ + + + + Magento 2 specific ruleset which checks for PHP cross version compatibility. + + + + + + + From c01fed6617e16df5b23d4995360331e57d3e19cd Mon Sep 17 00:00:00 2001 From: Sergio Vera Date: Tue, 16 Nov 2021 12:59:44 +0100 Subject: [PATCH 3/5] AC-1059: Move PHPCompatibility rules from Magento tests --- Magento2/ruleset.xml | 13 + ...ionalToRequiredFunctionParametersSniff.php | 270 ++++++++++ ...uiredToOptionalFunctionParametersSniff.php | 485 ++++++++++++++++++ PHPCompatibilityMagento/ruleset.xml | 7 + composer.lock | 12 +- 5 files changed, 781 insertions(+), 6 deletions(-) create mode 100644 PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php create mode 100644 PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php diff --git a/Magento2/ruleset.xml b/Magento2/ruleset.xml index c200c35e..bc732d71 100644 --- a/Magento2/ruleset.xml +++ b/Magento2/ruleset.xml @@ -737,4 +737,17 @@ 0 + + + + + + + + diff --git a/PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php b/PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php new file mode 100644 index 00000000..cee82cae --- /dev/null +++ b/PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php @@ -0,0 +1,270 @@ + [ + 1 => [ + 'name' => 'salt', + '5.6' => false, + '8.0' => true, + ], + ], + 'gmmktime' => [ + 1 => [ + 'name' => 'hour', + '8.0' => true, + ], + ], + 'mb_parse_str' => [ + 1 => [ + 'name' => 'result', + '8.0' => true, + ], + ], + 'mktime' => [ + 0 => [ + 'name' => 'hour', + '5.1' => false, + '8.0' => true, + ], + ], + 'openssl_seal' => [ + 4 => [ + 'name' => 'method', + '8.0' => true, + ], + ], + 'openssl_open' => [ + 4 => [ + 'name' => 'method', + '8.0' => true, + ], + ], + 'parse_str' => [ + 1 => [ + 'name' => 'result', + '7.2' => false, + '8.0' => true, + ], + ], + ]; + + + /** + * Bowing out early is not applicable to this sniff. + * + * @since 10.0.0 + * + * @return bool + */ + protected function bowOutEarly() + { + return false; + } + + /** + * Process the parameters of a matched function. + * + * @since 10.0.0 Part of the logic in this method was previously contained in the + * parent sniff `process()` method (now removed). + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the stack. + * @param string $functionName The token content (function name) which was matched. + * @param array $parameters Array with information about the parameters. + * + * @return int|void Integer stack pointer to skip forward or void to continue + * normal file processing. + */ + public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) + { + $functionLc = \strtolower($functionName); + $parameterCount = \count($parameters); + $parameterOffsetFound = $parameterCount - 1; + + foreach ($this->targetFunctions[$functionLc] as $offset => $parameterDetails) { + if ($offset > $parameterOffsetFound) { + $itemInfo = [ + 'name' => $functionName, + 'nameLc' => $functionLc, + 'offset' => $offset, + ]; + $this->handleFeature($phpcsFile, $stackPtr, $itemInfo); + } + } + } + + /** + * Process the function if no parameters were found. + * + * @since 10.0.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the stack. + * @param string $functionName The token content (function name) which was matched. + * + * @return int|void Integer stack pointer to skip forward or void to continue + * normal file processing. + */ + public function processNoParameters(File $phpcsFile, $stackPtr, $functionName) + { + $this->processParameters($phpcsFile, $stackPtr, $functionName, []); + } + + /** + * Retrieve the relevant detail (version) information for use in an error message. + * + * @since 8.1.0 + * @since 10.0.0 - Method renamed from `getErrorInfo()` to `getVersionInfo(). + * - Second function parameter `$itemInfo` removed. + * - Method visibility changed from `public` to `protected`. + * + * @param array $itemArray Version and other information about the item. + * + * @return array + */ + protected function getVersionInfo(array $itemArray) + { + $versionInfo = [ + 'optionalDeprecated' => '', + 'optionalRemoved' => '', + 'error' => false, + ]; + + foreach ($itemArray as $version => $required) { + if (\preg_match('`^\d\.\d(\.\d{1,2})?$`', $version) !== 1) { + // Not a version key. + continue; + } + + if ($this->supportsAbove($version) === true) { + if ($required === true && $versionInfo['optionalRemoved'] === '') { + $versionInfo['optionalRemoved'] = $version; + $versionInfo['error'] = true; + } elseif ($versionInfo['optionalDeprecated'] === '') { + $versionInfo['optionalDeprecated'] = $version; + } + } + } + + return $versionInfo; + } + + /** + * Handle the retrieval of relevant information and - if necessary - throwing of an + * error for a matched item. + * + * @since 10.0.0 This was previously handled via a similar method in the `AbstractComplexVersionSniff`. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the relevant token in + * the stack. + * @param array $itemInfo Base information about the item. + * + * @return void + */ + protected function handleFeature(File $phpcsFile, $stackPtr, array $itemInfo) + { + $itemArray = $this->targetFunctions[$itemInfo['nameLc']][$itemInfo['offset']]; + $versionInfo = $this->getVersionInfo($itemArray); + + if (empty($versionInfo['optionalDeprecated']) && empty($versionInfo['optionalRemoved'])) { + return; + } + + $this->addError($phpcsFile, $stackPtr, $itemInfo, $itemArray, $versionInfo); + } + + /** + * Generates the error or warning for this item. + * + * @since 8.1.0 + * @since 10.0.0 - Method visibility changed from `public` to `protected`. + * - Introduced $itemArray parameter. + * - Renamed the last parameter from `$errorInfo` to `$versionInfo`. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the relevant token in + * the stack. + * @param array $itemInfo Base information about the item. + * @param array $itemArray The sub-array with all the details about + * this item. + * @param array $versionInfo Array with detail (version) information + * relevant to the item. + * + * @return void + */ + protected function addError(File $phpcsFile, $stackPtr, array $itemInfo, array $itemArray, array $versionInfo) + { + $error = 'The "%s" parameter for function %s() is missing. Passing this parameter is no longer optional. The optional nature of the parameter is '; + $errorCode = $this->stringToErrorCode($itemInfo['name'] . '_' . $itemArray['name']); + $codeSuffix = ''; + $data = [ + $itemArray['name'], + $itemInfo['name'], + ]; + + if ($versionInfo['optionalDeprecated'] !== '') { + $error .= 'deprecated since PHP %s and '; + $codeSuffix = 'Soft'; + $data[] = $versionInfo['optionalDeprecated']; + } + + if ($versionInfo['optionalRemoved'] !== '') { + $error .= 'removed since PHP %s and '; + $codeSuffix = 'Hard'; + $data[] = $versionInfo['optionalRemoved']; + } + + // Remove the last 'and' from the message. + $error = \substr($error, 0, (\strlen($error) - 5)); + $errorCode .= $codeSuffix . 'Required'; + + $this->addMessage($phpcsFile, $error, $stackPtr, $versionInfo['error'], $errorCode, $data); + } +} \ No newline at end of file diff --git a/PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php b/PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php new file mode 100644 index 00000000..f4755bab --- /dev/null +++ b/PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php @@ -0,0 +1,485 @@ + [ + 1 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_diff_key' => [ + 1 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_diff_uassoc' => [ + /* + * $array2 is actually at position 1, but has another required parameter after it, + * so we need to detect on the last parameter. + */ + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_diff_ukey' => [ + // Note from array_diff_uassoc applies here too. + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_diff' => [ + 1 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_intersect_assoc' => [ + 1 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_intersect_key' => [ + 1 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_intersect_uassoc' => [ + // Note from array_diff_uassoc applies here too. + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_intersect_ukey' => [ + // Note from array_diff_uassoc applies here too. + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_intersect' => [ + 1 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_merge' => [ + 0 => [ + 'name' => 'array(s) to merge', + '7.3' => true, + '7.4' => false, + ], + ], + 'array_merge_recursive' => [ + 0 => [ + 'name' => 'array(s) to merge', + '7.3' => true, + '7.4' => false, + ], + ], + 'array_push' => [ + 1 => [ + 'name' => 'element to push', + '7.2' => true, + '7.3' => false, + ], + ], + 'array_udiff_assoc' => [ + // Note from array_diff_uassoc applies here too. + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_udiff_uassoc' => [ + // Note from array_diff_uassoc applies here too. + 3 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_udiff' => [ + // Note from array_diff_uassoc applies here too. + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_uintersect_assoc' => [ + // Note from array_diff_uassoc applies here too. + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_uintersect_uassoc' => [ + // Note from array_diff_uassoc applies here too. + 3 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_uintersect' => [ + // Note from array_diff_uassoc applies here too. + 2 => [ + 'name' => 'array2', + '7.4' => true, + '8.0' => false, + ], + ], + 'array_unshift' => [ + 1 => [ + 'name' => 'element to prepend', + '7.2' => true, + '7.3' => false, + ], + ], + 'bcscale' => [ + 0 => [ + 'name' => 'scale', + '7.2' => true, + '7.3' => false, + ], + ], + 'fgetcsv' => [ + 1 => [ + 'name' => 'length', + '5.0' => true, + '5.1' => false, + ], + ], + 'ftp_fget' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'ftp_fput' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'ftp_get' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'ftp_nb_fget' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'ftp_nb_fput' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'ftp_nb_get' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'ftp_nb_put' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'ftp_put' => [ + 3 => [ + 'name' => 'mode', + '7.2' => true, + '7.3' => false, + ], + ], + 'getenv' => [ + 0 => [ + 'name' => 'varname', + '7.0' => true, + '7.1' => false, + ], + ], + 'imagepolygon' => [ + /* + * $num_points is actually at position 2, but has another required parameter after it, + * so we need to detect on the last parameter. + */ + 3 => [ + 'name' => 'num_points', + '7.4' => true, + '8.0' => false, + ], + ], + 'imageopenpolygon' => [ + // Note from imagepolygon applies here too. + 3 => [ + 'name' => 'num_points', + '7.4' => true, + '8.0' => false, + ], + ], + 'imagefilledpolygon' => [ + // Note from imagepolygon applies here too. + 3 => [ + 'name' => 'num_points', + '7.4' => true, + '8.0' => false, + ], + ], + 'preg_match_all' => [ + 2 => [ + 'name' => 'matches', + '5.3' => true, + '5.4' => false, + ], + ], + 'stream_socket_enable_crypto' => [ + 2 => [ + 'name' => 'crypto_type', + '5.5' => true, + '5.6' => false, + ], + ], + 'xmlwriter_write_element' => [ + 2 => [ + 'name' => 'content', + '5.2.2' => true, + '5.2.3' => false, + ], + ], + 'xmlwriter_write_element_ns' => [ + 4 => [ + 'name' => 'content', + '5.2.2' => true, + '5.2.3' => false, + ], + ], + ]; + + + /** + * Bowing out early is not applicable to this sniff. + * + * @since 10.0.0 + * + * @return bool + */ + protected function bowOutEarly() + { + return false; + } + + /** + * Process the parameters of a matched function. + * + * @since 10.0.0 Part of the logic in this method was previously contained in the + * `process()` method (now removed). + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the stack. + * @param string $functionName The token content (function name) which was matched. + * @param array $parameters Array with information about the parameters. + * + * @return void + */ + public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) + { + $functionLc = \strtolower($functionName); + $parameterCount = \count($parameters); + $parameterOffsetFound = $parameterCount - 1; + + foreach ($this->targetFunctions[$functionLc] as $offset => $parameterDetails) { + if ($offset > $parameterOffsetFound) { + $itemInfo = [ + 'name' => $functionName, + 'nameLc' => $functionLc, + 'offset' => $offset, + ]; + $this->handleFeature($phpcsFile, $stackPtr, $itemInfo); + } + } + } + + /** + * Process the function if no parameters were found. + * + * @since 10.0.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the stack. + * @param string $functionName The token content (function name) which was matched. + * + * @return void + */ + public function processNoParameters(File $phpcsFile, $stackPtr, $functionName) + { + $this->processParameters($phpcsFile, $stackPtr, $functionName, []); + } + + /** + * Retrieve the relevant detail (version) information for use in an error message. + * + * @since 7.1.0 + * @since 10.0.0 - Method renamed from `getErrorInfo()` to `getVersionInfo(). + * - Second function parameter `$itemInfo` removed. + * - Method visibility changed from `public` to `protected`. + * + * @param array $itemArray Version and other information about the item. + * + * @return array + */ + protected function getVersionInfo(array $itemArray) + { + $versionInfo = [ + 'requiredVersion' => '', + ]; + + foreach ($itemArray as $version => $required) { + if (\preg_match('`^\d\.\d(\.\d{1,2})?$`', $version) !== 1) { + // Not a version key. + continue; + } + + if ($required === true && $this->supportsBelow($version) === true) { + $versionInfo['requiredVersion'] = $version; + } + } + + return $versionInfo; + } + + /** + * Handle the retrieval of relevant information and - if necessary - throwing of an + * error for a matched item. + * + * @since 10.0.0 This was previously handled via a similar method in the `AbstractComplexVersionSniff`. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the relevant token in + * the stack. + * @param array $itemInfo Base information about the item. + * + * @return void + */ + protected function handleFeature(File $phpcsFile, $stackPtr, array $itemInfo) + { + $itemArray = $this->targetFunctions[$itemInfo['nameLc']][$itemInfo['offset']]; + $versionInfo = $this->getVersionInfo($itemArray); + + if (empty($versionInfo['requiredVersion'])) { + return; + } + + $this->addError($phpcsFile, $stackPtr, $itemInfo, $itemArray, $versionInfo); + } + + /** + * Generates the error for this item. + * + * @since 7.1.0 + * @since 10.0.0 - Method visibility changed from `public` to `protected`. + * - Introduced $itemArray parameter. + * - Renamed the last parameter from `$errorInfo` to `$versionInfo`. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the relevant token in + * the stack. + * @param array $itemInfo Base information about the item. + * @param array $itemArray The sub-array with all the details about + * this item. + * @param array $versionInfo Array with detail (version) information + * relevant to the item. + * + * @return void + */ + protected function addError(File $phpcsFile, $stackPtr, array $itemInfo, array $itemArray, array $versionInfo) + { + $error = 'The "%s" parameter for function %s() is missing, but was required for PHP version %s and lower'; + $errorCode = $this->stringToErrorCode($itemInfo['name'] . '_' . $itemArray['name']) . 'Missing'; + $data = [ + $itemArray['name'], + $itemInfo['name'], + $versionInfo['requiredVersion'], + ]; + + $phpcsFile->addError($error, $stackPtr, $errorCode, $data); + } +} \ No newline at end of file diff --git a/PHPCompatibilityMagento/ruleset.xml b/PHPCompatibilityMagento/ruleset.xml index b69dae75..601ae60c 100644 --- a/PHPCompatibilityMagento/ruleset.xml +++ b/PHPCompatibilityMagento/ruleset.xml @@ -13,4 +13,11 @@ + + diff --git a/composer.lock b/composer.lock index b8be775a..46bc7eca 100644 --- a/composer.lock +++ b/composer.lock @@ -126,16 +126,16 @@ }, { "name": "webonyx/graphql-php", - "version": "v14.11.0", + "version": "v14.11.1", "source": { "type": "git", "url": "https://github.com/webonyx/graphql-php.git", - "reference": "d191b0c34365c025c6cd953b5a63aa62946c7060" + "reference": "8f3e584335696c2eb8d307019f0afdff64fc0e35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/d191b0c34365c025c6cd953b5a63aa62946c7060", - "reference": "d191b0c34365c025c6cd953b5a63aa62946c7060", + "url": "https://api.github.com/repos/webonyx/graphql-php/zipball/8f3e584335696c2eb8d307019f0afdff64fc0e35", + "reference": "8f3e584335696c2eb8d307019f0afdff64fc0e35", "shasum": "" }, "require": { @@ -180,7 +180,7 @@ ], "support": { "issues": "https://github.com/webonyx/graphql-php/issues", - "source": "https://github.com/webonyx/graphql-php/tree/v14.11.0" + "source": "https://github.com/webonyx/graphql-php/tree/v14.11.1" }, "funding": [ { @@ -188,7 +188,7 @@ "type": "open_collective" } ], - "time": "2021-10-29T13:08:08+00:00" + "time": "2021-11-15T10:25:57+00:00" } ], "packages-dev": [ From 7059a4b6bd29e247f7615e22c7ce5eb5727893f7 Mon Sep 17 00:00:00 2001 From: Sergio Vera Date: Tue, 16 Nov 2021 16:25:06 +0100 Subject: [PATCH 4/5] AC-1059: Move PHPCompatibility rules from Magento tests --- Magento2/ruleset.xml | 12 +- ...ionalToRequiredFunctionParametersSniff.php | 270 ---------- ...uiredToOptionalFunctionParametersSniff.php | 485 ------------------ PHPCompatibilityMagento/ruleset.xml | 23 - composer.json | 8 +- composer.lock | 2 +- 6 files changed, 6 insertions(+), 794 deletions(-) delete mode 100644 PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php delete mode 100644 PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php delete mode 100644 PHPCompatibilityMagento/ruleset.xml diff --git a/Magento2/ruleset.xml b/Magento2/ruleset.xml index bc732d71..b6b9ab27 100644 --- a/Magento2/ruleset.xml +++ b/Magento2/ruleset.xml @@ -737,17 +737,7 @@ 0 - + - - - - - diff --git a/PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php b/PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php deleted file mode 100644 index cee82cae..00000000 --- a/PHPCompatibilityMagento/Sniffs/FunctionUse/OptionalToRequiredFunctionParametersSniff.php +++ /dev/null @@ -1,270 +0,0 @@ - [ - 1 => [ - 'name' => 'salt', - '5.6' => false, - '8.0' => true, - ], - ], - 'gmmktime' => [ - 1 => [ - 'name' => 'hour', - '8.0' => true, - ], - ], - 'mb_parse_str' => [ - 1 => [ - 'name' => 'result', - '8.0' => true, - ], - ], - 'mktime' => [ - 0 => [ - 'name' => 'hour', - '5.1' => false, - '8.0' => true, - ], - ], - 'openssl_seal' => [ - 4 => [ - 'name' => 'method', - '8.0' => true, - ], - ], - 'openssl_open' => [ - 4 => [ - 'name' => 'method', - '8.0' => true, - ], - ], - 'parse_str' => [ - 1 => [ - 'name' => 'result', - '7.2' => false, - '8.0' => true, - ], - ], - ]; - - - /** - * Bowing out early is not applicable to this sniff. - * - * @since 10.0.0 - * - * @return bool - */ - protected function bowOutEarly() - { - return false; - } - - /** - * Process the parameters of a matched function. - * - * @since 10.0.0 Part of the logic in this method was previously contained in the - * parent sniff `process()` method (now removed). - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * @param array $parameters Array with information about the parameters. - * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. - */ - public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) - { - $functionLc = \strtolower($functionName); - $parameterCount = \count($parameters); - $parameterOffsetFound = $parameterCount - 1; - - foreach ($this->targetFunctions[$functionLc] as $offset => $parameterDetails) { - if ($offset > $parameterOffsetFound) { - $itemInfo = [ - 'name' => $functionName, - 'nameLc' => $functionLc, - 'offset' => $offset, - ]; - $this->handleFeature($phpcsFile, $stackPtr, $itemInfo); - } - } - } - - /** - * Process the function if no parameters were found. - * - * @since 10.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. - */ - public function processNoParameters(File $phpcsFile, $stackPtr, $functionName) - { - $this->processParameters($phpcsFile, $stackPtr, $functionName, []); - } - - /** - * Retrieve the relevant detail (version) information for use in an error message. - * - * @since 8.1.0 - * @since 10.0.0 - Method renamed from `getErrorInfo()` to `getVersionInfo(). - * - Second function parameter `$itemInfo` removed. - * - Method visibility changed from `public` to `protected`. - * - * @param array $itemArray Version and other information about the item. - * - * @return array - */ - protected function getVersionInfo(array $itemArray) - { - $versionInfo = [ - 'optionalDeprecated' => '', - 'optionalRemoved' => '', - 'error' => false, - ]; - - foreach ($itemArray as $version => $required) { - if (\preg_match('`^\d\.\d(\.\d{1,2})?$`', $version) !== 1) { - // Not a version key. - continue; - } - - if ($this->supportsAbove($version) === true) { - if ($required === true && $versionInfo['optionalRemoved'] === '') { - $versionInfo['optionalRemoved'] = $version; - $versionInfo['error'] = true; - } elseif ($versionInfo['optionalDeprecated'] === '') { - $versionInfo['optionalDeprecated'] = $version; - } - } - } - - return $versionInfo; - } - - /** - * Handle the retrieval of relevant information and - if necessary - throwing of an - * error for a matched item. - * - * @since 10.0.0 This was previously handled via a similar method in the `AbstractComplexVersionSniff`. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the relevant token in - * the stack. - * @param array $itemInfo Base information about the item. - * - * @return void - */ - protected function handleFeature(File $phpcsFile, $stackPtr, array $itemInfo) - { - $itemArray = $this->targetFunctions[$itemInfo['nameLc']][$itemInfo['offset']]; - $versionInfo = $this->getVersionInfo($itemArray); - - if (empty($versionInfo['optionalDeprecated']) && empty($versionInfo['optionalRemoved'])) { - return; - } - - $this->addError($phpcsFile, $stackPtr, $itemInfo, $itemArray, $versionInfo); - } - - /** - * Generates the error or warning for this item. - * - * @since 8.1.0 - * @since 10.0.0 - Method visibility changed from `public` to `protected`. - * - Introduced $itemArray parameter. - * - Renamed the last parameter from `$errorInfo` to `$versionInfo`. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the relevant token in - * the stack. - * @param array $itemInfo Base information about the item. - * @param array $itemArray The sub-array with all the details about - * this item. - * @param array $versionInfo Array with detail (version) information - * relevant to the item. - * - * @return void - */ - protected function addError(File $phpcsFile, $stackPtr, array $itemInfo, array $itemArray, array $versionInfo) - { - $error = 'The "%s" parameter for function %s() is missing. Passing this parameter is no longer optional. The optional nature of the parameter is '; - $errorCode = $this->stringToErrorCode($itemInfo['name'] . '_' . $itemArray['name']); - $codeSuffix = ''; - $data = [ - $itemArray['name'], - $itemInfo['name'], - ]; - - if ($versionInfo['optionalDeprecated'] !== '') { - $error .= 'deprecated since PHP %s and '; - $codeSuffix = 'Soft'; - $data[] = $versionInfo['optionalDeprecated']; - } - - if ($versionInfo['optionalRemoved'] !== '') { - $error .= 'removed since PHP %s and '; - $codeSuffix = 'Hard'; - $data[] = $versionInfo['optionalRemoved']; - } - - // Remove the last 'and' from the message. - $error = \substr($error, 0, (\strlen($error) - 5)); - $errorCode .= $codeSuffix . 'Required'; - - $this->addMessage($phpcsFile, $error, $stackPtr, $versionInfo['error'], $errorCode, $data); - } -} \ No newline at end of file diff --git a/PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php b/PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php deleted file mode 100644 index f4755bab..00000000 --- a/PHPCompatibilityMagento/Sniffs/FunctionUse/RequiredToOptionalFunctionParametersSniff.php +++ /dev/null @@ -1,485 +0,0 @@ - [ - 1 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_diff_key' => [ - 1 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_diff_uassoc' => [ - /* - * $array2 is actually at position 1, but has another required parameter after it, - * so we need to detect on the last parameter. - */ - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_diff_ukey' => [ - // Note from array_diff_uassoc applies here too. - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_diff' => [ - 1 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_intersect_assoc' => [ - 1 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_intersect_key' => [ - 1 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_intersect_uassoc' => [ - // Note from array_diff_uassoc applies here too. - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_intersect_ukey' => [ - // Note from array_diff_uassoc applies here too. - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_intersect' => [ - 1 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_merge' => [ - 0 => [ - 'name' => 'array(s) to merge', - '7.3' => true, - '7.4' => false, - ], - ], - 'array_merge_recursive' => [ - 0 => [ - 'name' => 'array(s) to merge', - '7.3' => true, - '7.4' => false, - ], - ], - 'array_push' => [ - 1 => [ - 'name' => 'element to push', - '7.2' => true, - '7.3' => false, - ], - ], - 'array_udiff_assoc' => [ - // Note from array_diff_uassoc applies here too. - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_udiff_uassoc' => [ - // Note from array_diff_uassoc applies here too. - 3 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_udiff' => [ - // Note from array_diff_uassoc applies here too. - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_uintersect_assoc' => [ - // Note from array_diff_uassoc applies here too. - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_uintersect_uassoc' => [ - // Note from array_diff_uassoc applies here too. - 3 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_uintersect' => [ - // Note from array_diff_uassoc applies here too. - 2 => [ - 'name' => 'array2', - '7.4' => true, - '8.0' => false, - ], - ], - 'array_unshift' => [ - 1 => [ - 'name' => 'element to prepend', - '7.2' => true, - '7.3' => false, - ], - ], - 'bcscale' => [ - 0 => [ - 'name' => 'scale', - '7.2' => true, - '7.3' => false, - ], - ], - 'fgetcsv' => [ - 1 => [ - 'name' => 'length', - '5.0' => true, - '5.1' => false, - ], - ], - 'ftp_fget' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'ftp_fput' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'ftp_get' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'ftp_nb_fget' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'ftp_nb_fput' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'ftp_nb_get' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'ftp_nb_put' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'ftp_put' => [ - 3 => [ - 'name' => 'mode', - '7.2' => true, - '7.3' => false, - ], - ], - 'getenv' => [ - 0 => [ - 'name' => 'varname', - '7.0' => true, - '7.1' => false, - ], - ], - 'imagepolygon' => [ - /* - * $num_points is actually at position 2, but has another required parameter after it, - * so we need to detect on the last parameter. - */ - 3 => [ - 'name' => 'num_points', - '7.4' => true, - '8.0' => false, - ], - ], - 'imageopenpolygon' => [ - // Note from imagepolygon applies here too. - 3 => [ - 'name' => 'num_points', - '7.4' => true, - '8.0' => false, - ], - ], - 'imagefilledpolygon' => [ - // Note from imagepolygon applies here too. - 3 => [ - 'name' => 'num_points', - '7.4' => true, - '8.0' => false, - ], - ], - 'preg_match_all' => [ - 2 => [ - 'name' => 'matches', - '5.3' => true, - '5.4' => false, - ], - ], - 'stream_socket_enable_crypto' => [ - 2 => [ - 'name' => 'crypto_type', - '5.5' => true, - '5.6' => false, - ], - ], - 'xmlwriter_write_element' => [ - 2 => [ - 'name' => 'content', - '5.2.2' => true, - '5.2.3' => false, - ], - ], - 'xmlwriter_write_element_ns' => [ - 4 => [ - 'name' => 'content', - '5.2.2' => true, - '5.2.3' => false, - ], - ], - ]; - - - /** - * Bowing out early is not applicable to this sniff. - * - * @since 10.0.0 - * - * @return bool - */ - protected function bowOutEarly() - { - return false; - } - - /** - * Process the parameters of a matched function. - * - * @since 10.0.0 Part of the logic in this method was previously contained in the - * `process()` method (now removed). - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * @param array $parameters Array with information about the parameters. - * - * @return void - */ - public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters) - { - $functionLc = \strtolower($functionName); - $parameterCount = \count($parameters); - $parameterOffsetFound = $parameterCount - 1; - - foreach ($this->targetFunctions[$functionLc] as $offset => $parameterDetails) { - if ($offset > $parameterOffsetFound) { - $itemInfo = [ - 'name' => $functionName, - 'nameLc' => $functionLc, - 'offset' => $offset, - ]; - $this->handleFeature($phpcsFile, $stackPtr, $itemInfo); - } - } - } - - /** - * Process the function if no parameters were found. - * - * @since 10.0.0 - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the current token in the stack. - * @param string $functionName The token content (function name) which was matched. - * - * @return void - */ - public function processNoParameters(File $phpcsFile, $stackPtr, $functionName) - { - $this->processParameters($phpcsFile, $stackPtr, $functionName, []); - } - - /** - * Retrieve the relevant detail (version) information for use in an error message. - * - * @since 7.1.0 - * @since 10.0.0 - Method renamed from `getErrorInfo()` to `getVersionInfo(). - * - Second function parameter `$itemInfo` removed. - * - Method visibility changed from `public` to `protected`. - * - * @param array $itemArray Version and other information about the item. - * - * @return array - */ - protected function getVersionInfo(array $itemArray) - { - $versionInfo = [ - 'requiredVersion' => '', - ]; - - foreach ($itemArray as $version => $required) { - if (\preg_match('`^\d\.\d(\.\d{1,2})?$`', $version) !== 1) { - // Not a version key. - continue; - } - - if ($required === true && $this->supportsBelow($version) === true) { - $versionInfo['requiredVersion'] = $version; - } - } - - return $versionInfo; - } - - /** - * Handle the retrieval of relevant information and - if necessary - throwing of an - * error for a matched item. - * - * @since 10.0.0 This was previously handled via a similar method in the `AbstractComplexVersionSniff`. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the relevant token in - * the stack. - * @param array $itemInfo Base information about the item. - * - * @return void - */ - protected function handleFeature(File $phpcsFile, $stackPtr, array $itemInfo) - { - $itemArray = $this->targetFunctions[$itemInfo['nameLc']][$itemInfo['offset']]; - $versionInfo = $this->getVersionInfo($itemArray); - - if (empty($versionInfo['requiredVersion'])) { - return; - } - - $this->addError($phpcsFile, $stackPtr, $itemInfo, $itemArray, $versionInfo); - } - - /** - * Generates the error for this item. - * - * @since 7.1.0 - * @since 10.0.0 - Method visibility changed from `public` to `protected`. - * - Introduced $itemArray parameter. - * - Renamed the last parameter from `$errorInfo` to `$versionInfo`. - * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The position of the relevant token in - * the stack. - * @param array $itemInfo Base information about the item. - * @param array $itemArray The sub-array with all the details about - * this item. - * @param array $versionInfo Array with detail (version) information - * relevant to the item. - * - * @return void - */ - protected function addError(File $phpcsFile, $stackPtr, array $itemInfo, array $itemArray, array $versionInfo) - { - $error = 'The "%s" parameter for function %s() is missing, but was required for PHP version %s and lower'; - $errorCode = $this->stringToErrorCode($itemInfo['name'] . '_' . $itemArray['name']) . 'Missing'; - $data = [ - $itemArray['name'], - $itemInfo['name'], - $versionInfo['requiredVersion'], - ]; - - $phpcsFile->addError($error, $stackPtr, $errorCode, $data); - } -} \ No newline at end of file diff --git a/PHPCompatibilityMagento/ruleset.xml b/PHPCompatibilityMagento/ruleset.xml deleted file mode 100644 index 601ae60c..00000000 --- a/PHPCompatibilityMagento/ruleset.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - Magento 2 specific ruleset which checks for PHP cross version compatibility. - - - - - - - - - diff --git a/composer.json b/composer.json index cf6dd7e4..3ad22f70 100644 --- a/composer.json +++ b/composer.json @@ -9,11 +9,11 @@ "version": "15", "require": { "php": ">=7.3", - "squizlabs/php_codesniffer": "^3.6", "webonyx/graphql-php": "^14.9", "ext-simplexml": "*", "ext-dom": "*", - "phpcompatibility/php-compatibility": "^9.3" + "phpcompatibility/php-compatibility": "^9.3", + "squizlabs/php_codesniffer": "^3.6" }, "require-dev": { "phpunit/phpunit": "^9.5.8" @@ -33,7 +33,7 @@ } }, "scripts": { - "post-install-cmd": "vendor/bin/phpcs --config-set installed_paths ../../..", - "post-update-cmd": "vendor/bin/phpcs --config-set installed_paths ../../.." + "post-install-cmd": "vendor/bin/phpcs --config-set installed_paths ../../..,../../phpcompatibility/php-compatibility/PHPCompatibility", + "post-update-cmd": "vendor/bin/phpcs --config-set installed_paths ../../..,../../phpcompatibility/php-compatibility/PHPCompatibility" } } diff --git a/composer.lock b/composer.lock index 46bc7eca..47559dbd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a726e6e7caa0f654b55b3a78d8ea170b", + "content-hash": "2e8abe33e655572c04bb6cdc53f88626", "packages": [ { "name": "phpcompatibility/php-compatibility", From 168882eac64fa22a717bd3a138f4856450ee66bf Mon Sep 17 00:00:00 2001 From: Sergio Vera Date: Thu, 18 Nov 2021 16:51:43 +0100 Subject: [PATCH 5/5] AC-1059: Added minimal supported PHP version to PHPCompatibility --- Magento2/ruleset.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Magento2/ruleset.xml b/Magento2/ruleset.xml index b6b9ab27..6cf906ec 100644 --- a/Magento2/ruleset.xml +++ b/Magento2/ruleset.xml @@ -739,5 +739,7 @@ + +