Skip to content

Commit 5157584

Browse files
authored
AC-1060 move relevant sniffs from phpcompatibility (#130)
* AC-1060: Move relevant sniffs from PHPCompatibility
1 parent 9cc2425 commit 5157584

File tree

55 files changed

+5274
-10
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+5274
-10
lines changed

.github/workflows/php.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ jobs:
7878
rector:
7979
runs-on: ubuntu-latest
8080
name: Rector tests
81-
81+
8282
steps:
8383
- name: Setup node
8484
uses: actions/setup-node@v2
@@ -88,7 +88,7 @@ jobs:
8888
- uses: actions/checkout@v2
8989

9090
- name: Install dependencies
91-
run: composer install
92-
91+
run: composer install
92+
9393
- name: Run rector
94-
run: vendor/bin/rector process Magento2 Magento2Framework PHP_CodeSniffer --dry-run --autoload-file vendor/squizlabs/php_codesniffer/autoload.php
94+
run: vendor/bin/rector process Magento2 Magento2Framework PHP_CodeSniffer --dry-run --autoload-file vendor/squizlabs/php_codesniffer/autoload.php --autoload-file vendor/phpcompatibility/php-compatibility/PHPCSAliases.php
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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 Magento2\Sniffs\PHPCompatibility;
12+
13+
use PHPCompatibility\Sniff;
14+
use PHP_CodeSniffer\Files\File;
15+
use PHPCSUtils\BackCompat\BCTokens;
16+
use PHPCSUtils\Utils\FunctionDeclarations;
17+
use PHPCSUtils\Utils\Scopes;
18+
19+
/**
20+
* Abstract private methods are not allowed since PHP 5.1, though they are allowed in traits since PHP 8.0.
21+
*
22+
* Abstract private methods were supported between PHP 5.0.0 and PHP 5.0.4, but
23+
* were then disallowed on the grounds that the behaviours of `private` and `abstract`
24+
* are mutually exclusive.
25+
*
26+
* As of PHP 8.0, traits are allowed to declare abstract private methods.
27+
*
28+
* PHP version 5.1
29+
* PHP version 8.0
30+
*
31+
* @link https://www.php.net/manual/en/migration51.oop.php#migration51.oop-methods
32+
* @link https://wiki.php.net/rfc/abstract_trait_method_validation
33+
*
34+
* @since 9.2.0
35+
* @since 10.0.0 The sniff has been renamed from `PHPCompatibility.Classes.ForbiddenAbstractPrivateMethods`
36+
* to `PHPCompatibility.FunctionDeclarations.AbstractPrivateMethods` and now
37+
* includes detection of the PHP 8 change.
38+
*/
39+
class AbstractPrivateMethodsSniff extends Sniff
40+
{
41+
42+
/**
43+
* Returns an array of tokens this test wants to listen for.
44+
*
45+
* @since 9.2.0
46+
*
47+
* @return array
48+
*/
49+
public function register()
50+
{
51+
return [\T_FUNCTION];
52+
}
53+
54+
/**
55+
* Processes this test, when one of its tokens is encountered.
56+
*
57+
* @since 9.2.0
58+
* @since 10.0.0 New error message for abstract private methods in traits.
59+
*
60+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
61+
* @param int $stackPtr The position of the current token
62+
* in the stack passed in $tokens.
63+
*
64+
* @return void
65+
*/
66+
public function process(File $phpcsFile, $stackPtr)
67+
{
68+
if ($this->supportsAbove('5.1') === false) {
69+
return;
70+
}
71+
72+
$tokens = $phpcsFile->getTokens();
73+
$scopePtr = Scopes::validDirectScope($phpcsFile, $stackPtr, BCTokens::ooScopeTokens());
74+
if ($scopePtr === false) {
75+
// Function, not method.
76+
return;
77+
}
78+
79+
$properties = FunctionDeclarations::getProperties($phpcsFile, $stackPtr);
80+
if ($properties['scope'] !== 'private' || $properties['is_abstract'] !== true) {
81+
// Not an abstract private method.
82+
return;
83+
}
84+
85+
if ($tokens[$scopePtr]['code'] === \T_TRAIT) {
86+
if ($this->supportsBelow('7.4') === true) {
87+
$phpcsFile->addError(
88+
'Traits cannot declare "abstract private" methods in PHP 7.4 or below',
89+
$stackPtr,
90+
'InTrait'
91+
);
92+
}
93+
94+
return;
95+
}
96+
97+
// Not a trait.
98+
$phpcsFile->addError(
99+
'Abstract methods cannot be declared as private since PHP 5.1',
100+
$stackPtr,
101+
'Found'
102+
);
103+
}
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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 Magento2\Sniffs\PHPCompatibility;
12+
13+
use PHP_CodeSniffer\Files\File;
14+
use PHP_CodeSniffer\Util\Tokens;
15+
use PHPCompatibility\AbstractFunctionCallParameterSniff;
16+
use PHPCSUtils\BackCompat\BCTokens;
17+
18+
/**
19+
* Detect calls to functions where the expected type of a parameter has been changed from integer to boolean.
20+
*
21+
* Throws an error when a hard-coded numeric value is passed.
22+
*
23+
* PHP version 8.0+
24+
*
25+
* @since 10.0.0
26+
*/
27+
class ChangedIntToBoolParamTypeSniff extends AbstractFunctionCallParameterSniff
28+
{
29+
30+
/**
31+
* Functions to check for.
32+
*
33+
* @since 10.0.0
34+
*
35+
* @var array
36+
*/
37+
protected $targetFunctions = [
38+
'ob_implicit_flush' => [
39+
1 => [
40+
'name' => 'flag',
41+
'since' => '8.0',
42+
],
43+
],
44+
'sem_get' => [
45+
4 => [
46+
'name' => 'auto_release',
47+
'since' => '8.0',
48+
],
49+
],
50+
];
51+
52+
/**
53+
* Do a version check to determine if this sniff needs to run at all.
54+
*
55+
* Checks against the first PHP version listed in the above array.
56+
*
57+
* @since 10.0.0
58+
*
59+
* @return bool
60+
*/
61+
protected function bowOutEarly()
62+
{
63+
return ($this->supportsAbove('8.0') === false);
64+
}
65+
66+
/**
67+
* Process the parameters of a matched function.
68+
*
69+
* @since 10.0.0
70+
*
71+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
72+
* @param int $stackPtr The position of the current token in the stack.
73+
* @param string $functionName The token content (function name) which was matched.
74+
* @param array $parameters Array with information about the parameters.
75+
*
76+
* @return int|void Integer stack pointer to skip forward or void to continue
77+
* normal file processing.
78+
*/
79+
public function processParameters(File $phpcsFile, $stackPtr, $functionName, $parameters)
80+
{
81+
static $search;
82+
83+
if (isset($search) === false) {
84+
$search = [
85+
\T_LNUMBER => \T_LNUMBER,
86+
\T_DNUMBER => \T_DNUMBER,
87+
];
88+
$search += BCTokens::arithmeticTokens();
89+
$search += Tokens::$emptyTokens;
90+
}
91+
92+
$functionLC = \strtolower($functionName);
93+
$functionInfo = $this->targetFunctions[$functionLC];
94+
foreach ($functionInfo as $offset => $paramInfo) {
95+
if (isset($parameters[$offset]) === false) {
96+
continue;
97+
}
98+
99+
if ($this->supportsAbove($paramInfo['since']) === false) {
100+
continue;
101+
}
102+
103+
$target = $parameters[$offset];
104+
105+
$hasNonNumeric = $phpcsFile->findNext($search, $target['start'], ($target['end'] + 1), true);
106+
if ($hasNonNumeric !== false) {
107+
// Not a purely numerical value. Ignore.
108+
continue;
109+
}
110+
111+
$error = 'The $%s parameter of %s() expects a boolean value instead of an integer since PHP %s. Found: %s';
112+
$code = $this->stringToErrorCode($functionName . '_' . $paramInfo['name']) . 'NumericFound';
113+
$data = [
114+
$paramInfo['name'],
115+
$functionLC,
116+
$paramInfo['since'],
117+
$target['raw'],
118+
];
119+
120+
$phpcsFile->addError($error, $target['start'], $code, $data);
121+
}
122+
}
123+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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 Magento2\Sniffs\PHPCompatibility;
12+
13+
use PHPCompatibility\Sniff;
14+
use PHP_CodeSniffer\Files\File;
15+
use PHPCSUtils\Utils\FunctionDeclarations;
16+
use PHPCSUtils\Utils\Scopes;
17+
18+
/**
19+
* Applying the final modifier on a private method will produce a warning since PHP 8.0
20+
* unless that method is the constructor.
21+
*
22+
* Previously final private methods were allowed and overriding the method in a child class
23+
* would result in a fatal "Cannot override final method". This was inappropriate as
24+
* private methods are not inherited.
25+
*
26+
* > Due to how common the usage of `final private function __construct` is and given that
27+
* > the same results cannot be achieved with a protected visibility, an exception to this rule
28+
* > is made for constructors.
29+
*
30+
* PHP version 8.0
31+
*
32+
* @link https://wiki.php.net/rfc/inheritance_private_methods
33+
*
34+
* @since 10.0.0
35+
*/
36+
class ForbiddenFinalPrivateMethodsSniff extends Sniff
37+
{
38+
39+
/**
40+
* Returns an array of tokens this test wants to listen for.
41+
*
42+
* @since 10.0.0
43+
*
44+
* @return array
45+
*/
46+
public function register()
47+
{
48+
return [\T_FUNCTION];
49+
}
50+
51+
/**
52+
* Processes this test, when one of its tokens is encountered.
53+
*
54+
* @since 10.0.0
55+
*
56+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
57+
* @param int $stackPtr The position of the current token
58+
* in the stack passed in $tokens.
59+
*
60+
* @return void
61+
*/
62+
public function process(File $phpcsFile, $stackPtr)
63+
{
64+
if ($this->supportsAbove('8.0') === false) {
65+
return;
66+
}
67+
68+
if (Scopes::isOOMethod($phpcsFile, $stackPtr) === false) {
69+
// Function, not method.
70+
return;
71+
}
72+
73+
$name = FunctionDeclarations::getName($phpcsFile, $stackPtr);
74+
if (empty($name) === true) {
75+
// Parse error or live coding.
76+
return;
77+
}
78+
79+
if (\strtolower($name) === '__construct') {
80+
// The rule does not apply to constructors. Bow out.
81+
return;
82+
}
83+
84+
$properties = FunctionDeclarations::getProperties($phpcsFile, $stackPtr);
85+
if ($properties['scope'] !== 'private' || $properties['is_final'] === false) {
86+
// Not an private final method.
87+
return;
88+
}
89+
90+
$phpcsFile->addWarning(
91+
'Private methods should not be declared as final since PHP 8.0',
92+
$stackPtr,
93+
'Found'
94+
);
95+
}
96+
}

0 commit comments

Comments
 (0)