Skip to content

Commit 04e5251

Browse files
✨ Improve ValidScalar
1 parent c6583a3 commit 04e5251

File tree

4 files changed

+82
-106
lines changed

4 files changed

+82
-106
lines changed

SymfonyCustom/Sniffs/NamingConventions/ValidScalarTypeNameSniff.php

Lines changed: 71 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,21 @@
66

77
use PHP_CodeSniffer\Files\File;
88
use PHP_CodeSniffer\Sniffs\Sniff;
9+
use PHP_CodeSniffer\Util\Common;
910
use PHP_CodeSniffer\Util\Tokens;
11+
use SymfonyCustom\Helpers\SniffHelper;
1012

1113
/**
1214
* Throws errors if scalar type name are not valid.
1315
*/
1416
class ValidScalarTypeNameSniff implements Sniff
1517
{
16-
/**
17-
* Types to replace: key is type to replace, value is type to replace with.
18-
*
19-
* @var array
20-
*/
21-
public $types = [
22-
'boolean' => 'bool',
23-
'double' => 'float',
24-
'integer' => 'int',
25-
'real' => 'float',
26-
];
27-
2818
/**
2919
* @return array
3020
*/
3121
public function register(): array
3222
{
33-
$tokens = Tokens::$castTokens;
34-
$tokens[] = T_DOC_COMMENT_OPEN_TAG;
35-
36-
return $tokens;
23+
return [T_DOC_COMMENT_TAG];
3724
}
3825

3926
/**
@@ -43,91 +30,94 @@ public function register(): array
4330
public function process(File $phpcsFile, $stackPtr): void
4431
{
4532
$tokens = $phpcsFile->getTokens();
46-
if (T_DOC_COMMENT_OPEN_TAG === $tokens[$stackPtr]['code']) {
47-
$this->validateDocComment($phpcsFile, $stackPtr);
48-
} else {
49-
$this->validateCast($phpcsFile, $stackPtr);
50-
}
51-
}
5233

53-
/**
54-
* @param File $phpcsFile
55-
* @param int $stackPtr
56-
*/
57-
private function validateDocComment(File $phpcsFile, int $stackPtr): void
58-
{
59-
$tokens = $phpcsFile->getTokens();
60-
foreach ($tokens[$stackPtr]['comment_tags'] as $commentTag) {
61-
if (in_array(
62-
$tokens[$commentTag]['content'],
63-
['@param', '@return', '@var']
64-
)
65-
) {
66-
$docString = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $commentTag);
67-
if (false !== $docString) {
68-
$stringParts = explode(' ', $tokens[$docString]['content']);
69-
$typeName = $stringParts[0];
70-
$this->validateTypeName($phpcsFile, $docString, $typeName);
34+
if (in_array($tokens[$stackPtr]['content'], SniffHelper::TAGS_WITH_TYPE)) {
35+
preg_match(
36+
'`^((?:\|?(?:array\([^\)]*\)|[\\\\a-z0-9\[\<\,\>\]]+))*)( .*)?`i',
37+
$tokens[($stackPtr + 2)]['content'],
38+
$match
39+
);
40+
41+
if (isset($match[1]) === false) {
42+
return;
43+
}
44+
45+
// Check type (can be multiple, separated by '|').
46+
$type = $match[1];
47+
$typeNames = explode('|', $type);
48+
$suggestedNames = [];
49+
foreach ($typeNames as $i => $typeName) {
50+
$suggestedName = $this->getValidTypeName($typeName);
51+
52+
if (in_array($suggestedName, $suggestedNames, true) === false) {
53+
$suggestedNames[] = $suggestedName;
7154
}
7255
}
73-
}
74-
}
7556

76-
/**
77-
* @param File $phpcsFile
78-
* @param int $stackPtr
79-
*/
80-
private function validateCast(File $phpcsFile, int $stackPtr): void
81-
{
82-
$tokens = $phpcsFile->getTokens();
83-
preg_match('/^\(\s*(\S+)\s*\)$/', $tokens[$stackPtr]['content'], $matches);
84-
$typeName = $matches[1];
57+
$suggestedType = implode('|', $suggestedNames);
58+
if ($type !== $suggestedType) {
59+
$fix = $phpcsFile->addFixableError(
60+
'For type-hinting in PHPDocs, use %s instead of %s',
61+
$stackPtr + 2,
62+
'Invalid',
63+
[$suggestedType, $type]
64+
);
65+
66+
if ($fix) {
67+
$replacement = $suggestedType;
68+
if (isset($match[2])) {
69+
$replacement .= $match[2];
70+
}
8571

86-
$this->validateTypeName($phpcsFile, $stackPtr, $typeName);
72+
$phpcsFile->fixer->replaceToken($stackPtr + 2, $replacement);
73+
}
74+
}
75+
}
8776
}
8877

8978
/**
90-
* @param File $phpcsFile
91-
* @param int $stackPtr
9279
* @param string $typeName
80+
*
81+
* @return string
9382
*/
94-
private function validateTypeName(File $phpcsFile, int $stackPtr, string $typeName): void
83+
private function getValidTypeName(string $typeName): string
9584
{
96-
$validTypeName = $this->getValidTypeName($typeName);
97-
98-
if (null !== $validTypeName) {
99-
$needFix = $phpcsFile->addFixableError(
100-
'For type-hinting in PHPDocs and casting, use %s instead of %s',
101-
$stackPtr,
102-
'',
103-
[$validTypeName, $typeName]
104-
);
105-
if ($needFix) {
106-
$tokens = $phpcsFile->getTokens();
107-
$phpcsFile->fixer->beginChangeset();
108-
$newContent = str_replace(
109-
$typeName,
110-
$validTypeName,
111-
$tokens[$stackPtr]['content']
112-
);
113-
$phpcsFile->fixer->replaceToken($stackPtr, $newContent);
114-
$phpcsFile->fixer->endChangeset();
115-
}
85+
$parts = preg_split('/([\<\,\>])/', $typeName, -1, PREG_SPLIT_DELIM_CAPTURE);
86+
$partsNumber = count($parts) - 1;
87+
88+
$validType = '';
89+
for ($i = 0; $i < $partsNumber; $i += 2) {
90+
$validType .= $this->suggestType($parts[$i]).$parts[$i + 1];
11691
}
92+
93+
if ('' !== $parts[$partsNumber]) {
94+
$validType .= $this->suggestType($parts[$partsNumber]);
95+
}
96+
97+
return $validType;
11798
}
11899

119100
/**
120101
* @param string $typeName
121102
*
122-
* @return string|null
103+
* @return string
123104
*/
124-
private function getValidTypeName(string $typeName): ?string
105+
private function suggestType(string $typeName): string
125106
{
126-
$typeName = strtolower($typeName);
127-
if (isset($this->types[$typeName])) {
128-
return $this->types[$typeName];
107+
if ('[]' === substr($typeName, -2)) {
108+
return $this->suggestType(substr($typeName, 0, -2)).'[]';
109+
}
110+
111+
$lowerType = strtolower($typeName);
112+
switch ($lowerType) {
113+
case 'bool':
114+
case 'boolean':
115+
return 'bool';
116+
case 'int':
117+
case 'integer':
118+
return 'int';
129119
}
130120

131-
return null;
121+
return Common::suggestType($typeName);
132122
}
133123
}

SymfonyCustom/Tests/NamingConventions/ValidScalarTypeNameUnitTest.inc

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,6 @@ echo ( float ) $a;
2222
// Only PHPDoc comments are checked
2323
/* @var boolean $a */
2424

25-
26-
echo ( integer ) $a;
27-
echo (boolean) $a;
28-
echo (Boolean) $a;
29-
echo (integer) $a;
30-
echo (double) $a;
31-
echo (real) $a;
32-
3325
/**
3426
* @param boolean $a
3527
* @param Boolean $a
@@ -49,3 +41,6 @@ echo (real) $a;
4941
/** @var integer $b */
5042
/** @var double $c */
5143
/** @var real $c */
44+
45+
/** @method integer|string */
46+
/** @method array<integer,boolean>|integer[]|string */

SymfonyCustom/Tests/NamingConventions/ValidScalarTypeNameUnitTest.inc.fixed

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,6 @@ echo ( float ) $a;
2222
// Only PHPDoc comments are checked
2323
/* @var boolean $a */
2424

25-
26-
echo ( int ) $a;
27-
echo (bool) $a;
28-
echo (bool) $a;
29-
echo (int) $a;
30-
echo (float) $a;
31-
echo (float) $a;
32-
3325
/**
3426
* @param bool $a
3527
* @param bool $a
@@ -49,3 +41,6 @@ echo (float) $a;
4941
/** @var int $b */
5042
/** @var float $c */
5143
/** @var float $c */
44+
45+
/** @method int|string */
46+
/** @method array<int,bool>|int[]|string */

SymfonyCustom/Tests/NamingConventions/ValidScalarTypeNameUnitTest.php

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,18 @@ protected function getErrorList(): array
2424
28 => 1,
2525
29 => 1,
2626
30 => 1,
27-
31 => 1,
27+
32 => 1,
28+
33 => 1,
2829
34 => 1,
2930
35 => 1,
3031
36 => 1,
31-
37 => 1,
32-
38 => 1,
32+
39 => 1,
3333
40 => 1,
3434
41 => 1,
3535
42 => 1,
3636
43 => 1,
37-
44 => 1,
38-
47 => 1,
39-
48 => 1,
40-
49 => 1,
41-
50 => 1,
42-
51 => 1,
37+
45 => 1,
38+
46 => 1,
4339
];
4440
}
4541

0 commit comments

Comments
 (0)