Skip to content

AC-1059: Move PHPCompatibility rules from Magento tests #332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
AC-1059: Move PHPCompatibility rules from Magento tests
  • Loading branch information
svera committed Nov 16, 2021
commit c01fed6617e16df5b23d4995360331e57d3e19cd
13 changes: 13 additions & 0 deletions Magento2/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -737,4 +737,17 @@
<rule ref="Internal.NoCodeFound">
<severity>0</severity>
</rule>
<rule ref="../vendor/phpcompatibility/php-compatibility/PHPCompatibility">
<exclude name="PHPCompatibility.Miscellaneous.RemovedAlternativePHPTags.MaybeASPOpenTagFound" />
<exclude name="PHPCompatibility.FunctionUse.RequiredToOptionalFunctionParameters" />
<exclude name="PHPCompatibility.ParameterValues.RemovedPCREModifiers" />
<exclude name="PHPCompatibility.InitialValue.NewConstantScalarExpressions" />
</rule>
<!--
These sniffs are copied from latest development version of PHPCompatibility, and are included here due to bug
in version 9.3 of PHPCompatibility. Once version 10 is released, this hack must me removed.

See https://github.com/PHPCompatibility/PHPCompatibility/issues/793 form more information
-->
<rule ref="../PHPCompatibilityMagento/Sniffs/FunctionUse" />
</ruleset>
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
<?php
/**
* PHPCompatibility, an external standard for PHP_CodeSniffer.
*
* @package PHPCompatibility
* @copyright 2012-2020 PHPCompatibility Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCompatibility/PHPCompatibility
*/

namespace PHPCompatibilityMagento\Sniffs\FunctionUse;

use PHPCompatibility\AbstractFunctionCallParameterSniff;
use PHP_CodeSniffer\Files\File;

/**
* Detect missing required function parameters in calls to native PHP functions.
*
* Specifically when those function parameters used to be optional in older PHP versions.
*
* PHP version All
*
* @link https://www.php.net/manual/en/doc.changelog.php
*
* @since 8.1.0
* @since 9.0.0 Renamed from `OptionalRequiredFunctionParametersSniff` to `OptionalToRequiredFunctionParametersSniff`.
* @since 10.0.0 Now extends the base `AbstractFunctionCallParameterSniff` class.
* Previously the sniff extended the sister-sniff `RequiredToOptionalFunctionParametersSniff`.
* Methods which were previously required due to the extending of the (grand-parent)
* `AbstractComplexVersionSniff` have been removed.
*/
class OptionalToRequiredFunctionParametersSniff extends AbstractFunctionCallParameterSniff
{

/**
* A list of function parameters, which were optional in older versions and became required later on.
*
* The array lists : version number with true (required) and false (optional use deprecated).
*
* The index is the location of the parameter in the parameter list, starting at 0 !
* If's sufficient to list the last version in which the parameter was not yet required.
*
* @since 8.1.0
* @since 10.0.0 Parameter renamed from `$functionParameters` to `$targetFunctions` for
* compatibility with the `AbstractFunctionCallParameterSniff` class.
*
* @var array
*/
protected $targetFunctions = [
'crypt' => [
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);
}
}
Loading