Skip to content

Commit c01fed6

Browse files
committed
AC-1059: Move PHPCompatibility rules from Magento tests
1 parent 1d3fa20 commit c01fed6

File tree

5 files changed

+781
-6
lines changed

5 files changed

+781
-6
lines changed

Magento2/ruleset.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,4 +737,17 @@
737737
<rule ref="Internal.NoCodeFound">
738738
<severity>0</severity>
739739
</rule>
740+
<rule ref="../vendor/phpcompatibility/php-compatibility/PHPCompatibility">
741+
<exclude name="PHPCompatibility.Miscellaneous.RemovedAlternativePHPTags.MaybeASPOpenTagFound" />
742+
<exclude name="PHPCompatibility.FunctionUse.RequiredToOptionalFunctionParameters" />
743+
<exclude name="PHPCompatibility.ParameterValues.RemovedPCREModifiers" />
744+
<exclude name="PHPCompatibility.InitialValue.NewConstantScalarExpressions" />
745+
</rule>
746+
<!--
747+
These sniffs are copied from latest development version of PHPCompatibility, and are included here due to bug
748+
in version 9.3 of PHPCompatibility. Once version 10 is released, this hack must me removed.
749+
750+
See https://github.com/PHPCompatibility/PHPCompatibility/issues/793 form more information
751+
-->
752+
<rule ref="../PHPCompatibilityMagento/Sniffs/FunctionUse" />
740753
</ruleset>
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
<?php
2+
/**
3+
* PHPCompatibility, an external standard for PHP_CodeSniffer.
4+
*
5+
* @package PHPCompatibility
6+
* @copyright 2012-2020 PHPCompatibility Contributors
7+
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
8+
* @link https://github.com/PHPCompatibility/PHPCompatibility
9+
*/
10+
11+
namespace PHPCompatibilityMagento\Sniffs\FunctionUse;
12+
13+
use PHPCompatibility\AbstractFunctionCallParameterSniff;
14+
use PHP_CodeSniffer\Files\File;
15+
16+
/**
17+
* Detect missing required function parameters in calls to native PHP functions.
18+
*
19+
* Specifically when those function parameters used to be optional in older PHP versions.
20+
*
21+
* PHP version All
22+
*
23+
* @link https://www.php.net/manual/en/doc.changelog.php
24+
*
25+
* @since 8.1.0
26+
* @since 9.0.0 Renamed from `OptionalRequiredFunctionParametersSniff` to `OptionalToRequiredFunctionParametersSniff`.
27+
* @since 10.0.0 Now extends the base `AbstractFunctionCallParameterSniff` class.
28+
* Previously the sniff extended the sister-sniff `RequiredToOptionalFunctionParametersSniff`.
29+
* Methods which were previously required due to the extending of the (grand-parent)
30+
* `AbstractComplexVersionSniff` have been removed.
31+
*/
32+
class OptionalToRequiredFunctionParametersSniff extends AbstractFunctionCallParameterSniff
33+
{
34+
35+
/**
36+
* A list of function parameters, which were optional in older versions and became required later on.
37+
*
38+
* The array lists : version number with true (required) and false (optional use deprecated).
39+
*
40+
* The index is the location of the parameter in the parameter list, starting at 0 !
41+
* If's sufficient to list the last version in which the parameter was not yet required.
42+
*
43+
* @since 8.1.0
44+
* @since 10.0.0 Parameter renamed from `$functionParameters` to `$targetFunctions` for
45+
* compatibility with the `AbstractFunctionCallParameterSniff` class.
46+
*
47+
* @var array
48+
*/
49+
protected $targetFunctions = [
50+
'crypt' => [
51+
1 => [
52+
'name' => 'salt',
53+
'5.6' => false,
54+
'8.0' => true,
55+
],
56+
],
57+
'gmmktime' => [
58+
1 => [
59+
'name' => 'hour',
60+
'8.0' => true,
61+
],
62+
],
63+
'mb_parse_str' => [
64+
1 => [
65+
'name' => 'result',
66+
'8.0' => true,
67+
],
68+
],
69+
'mktime' => [
70+
0 => [
71+
'name' => 'hour',
72+
'5.1' => false,
73+
'8.0' => true,
74+
],
75+
],
76+
'openssl_seal' => [
77+
4 => [
78+
'name' => 'method',
79+
'8.0' => true,
80+
],
81+
],
82+
'openssl_open' => [
83+
4 => [
84+
'name' => 'method',
85+
'8.0' => true,
86+
],
87+
],
88+
'parse_str' => [
89+
1 => [
90+
'name' => 'result',
91+
'7.2' => false,
92+
'8.0' => true,
93+
],
94+
],
95+
];
96+
97+
98+
/**
99+
* Bowing out early is not applicable to this sniff.
100+
*
101+
* @since 10.0.0
102+
*
103+
* @return bool
104+
*/
105+
protected function bowOutEarly()
106+
{
107+
return false;
108+
}
109+
110+
/**
111+
* Process the parameters of a matched function.
112+
*
113+
* @since 10.0.0 Part of the logic in this method was previously contained in the
114+
* parent sniff `process()` method (now removed).
115+
*
116+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
117+
* @param int $stackPtr The position of the current token in the stack.
118+
* @param string $functionName The token content (function name) which was matched.
119+
* @param array $parameters Array with information about the parameters.
120+
*
121+
* @return int|void Integer stack pointer to skip forward or void to continue
122+
* normal file processing.
123+
*/
124+
public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters)
125+
{
126+
$functionLc = \strtolower($functionName);
127+
$parameterCount = \count($parameters);
128+
$parameterOffsetFound = $parameterCount - 1;
129+
130+
foreach ($this->targetFunctions[$functionLc] as $offset => $parameterDetails) {
131+
if ($offset > $parameterOffsetFound) {
132+
$itemInfo = [
133+
'name' => $functionName,
134+
'nameLc' => $functionLc,
135+
'offset' => $offset,
136+
];
137+
$this->handleFeature($phpcsFile, $stackPtr, $itemInfo);
138+
}
139+
}
140+
}
141+
142+
/**
143+
* Process the function if no parameters were found.
144+
*
145+
* @since 10.0.0
146+
*
147+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
148+
* @param int $stackPtr The position of the current token in the stack.
149+
* @param string $functionName The token content (function name) which was matched.
150+
*
151+
* @return int|void Integer stack pointer to skip forward or void to continue
152+
* normal file processing.
153+
*/
154+
public function processNoParameters(File $phpcsFile, $stackPtr, $functionName)
155+
{
156+
$this->processParameters($phpcsFile, $stackPtr, $functionName, []);
157+
}
158+
159+
/**
160+
* Retrieve the relevant detail (version) information for use in an error message.
161+
*
162+
* @since 8.1.0
163+
* @since 10.0.0 - Method renamed from `getErrorInfo()` to `getVersionInfo().
164+
* - Second function parameter `$itemInfo` removed.
165+
* - Method visibility changed from `public` to `protected`.
166+
*
167+
* @param array $itemArray Version and other information about the item.
168+
*
169+
* @return array
170+
*/
171+
protected function getVersionInfo(array $itemArray)
172+
{
173+
$versionInfo = [
174+
'optionalDeprecated' => '',
175+
'optionalRemoved' => '',
176+
'error' => false,
177+
];
178+
179+
foreach ($itemArray as $version => $required) {
180+
if (\preg_match('`^\d\.\d(\.\d{1,2})?$`', $version) !== 1) {
181+
// Not a version key.
182+
continue;
183+
}
184+
185+
if ($this->supportsAbove($version) === true) {
186+
if ($required === true && $versionInfo['optionalRemoved'] === '') {
187+
$versionInfo['optionalRemoved'] = $version;
188+
$versionInfo['error'] = true;
189+
} elseif ($versionInfo['optionalDeprecated'] === '') {
190+
$versionInfo['optionalDeprecated'] = $version;
191+
}
192+
}
193+
}
194+
195+
return $versionInfo;
196+
}
197+
198+
/**
199+
* Handle the retrieval of relevant information and - if necessary - throwing of an
200+
* error for a matched item.
201+
*
202+
* @since 10.0.0 This was previously handled via a similar method in the `AbstractComplexVersionSniff`.
203+
*
204+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
205+
* @param int $stackPtr The position of the relevant token in
206+
* the stack.
207+
* @param array $itemInfo Base information about the item.
208+
*
209+
* @return void
210+
*/
211+
protected function handleFeature(File $phpcsFile, $stackPtr, array $itemInfo)
212+
{
213+
$itemArray = $this->targetFunctions[$itemInfo['nameLc']][$itemInfo['offset']];
214+
$versionInfo = $this->getVersionInfo($itemArray);
215+
216+
if (empty($versionInfo['optionalDeprecated']) && empty($versionInfo['optionalRemoved'])) {
217+
return;
218+
}
219+
220+
$this->addError($phpcsFile, $stackPtr, $itemInfo, $itemArray, $versionInfo);
221+
}
222+
223+
/**
224+
* Generates the error or warning for this item.
225+
*
226+
* @since 8.1.0
227+
* @since 10.0.0 - Method visibility changed from `public` to `protected`.
228+
* - Introduced $itemArray parameter.
229+
* - Renamed the last parameter from `$errorInfo` to `$versionInfo`.
230+
*
231+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
232+
* @param int $stackPtr The position of the relevant token in
233+
* the stack.
234+
* @param array $itemInfo Base information about the item.
235+
* @param array $itemArray The sub-array with all the details about
236+
* this item.
237+
* @param array $versionInfo Array with detail (version) information
238+
* relevant to the item.
239+
*
240+
* @return void
241+
*/
242+
protected function addError(File $phpcsFile, $stackPtr, array $itemInfo, array $itemArray, array $versionInfo)
243+
{
244+
$error = 'The "%s" parameter for function %s() is missing. Passing this parameter is no longer optional. The optional nature of the parameter is ';
245+
$errorCode = $this->stringToErrorCode($itemInfo['name'] . '_' . $itemArray['name']);
246+
$codeSuffix = '';
247+
$data = [
248+
$itemArray['name'],
249+
$itemInfo['name'],
250+
];
251+
252+
if ($versionInfo['optionalDeprecated'] !== '') {
253+
$error .= 'deprecated since PHP %s and ';
254+
$codeSuffix = 'Soft';
255+
$data[] = $versionInfo['optionalDeprecated'];
256+
}
257+
258+
if ($versionInfo['optionalRemoved'] !== '') {
259+
$error .= 'removed since PHP %s and ';
260+
$codeSuffix = 'Hard';
261+
$data[] = $versionInfo['optionalRemoved'];
262+
}
263+
264+
// Remove the last 'and' from the message.
265+
$error = \substr($error, 0, (\strlen($error) - 5));
266+
$errorCode .= $codeSuffix . 'Required';
267+
268+
$this->addMessage($phpcsFile, $error, $stackPtr, $versionInfo['error'], $errorCode, $data);
269+
}
270+
}

0 commit comments

Comments
 (0)