Skip to content

Commit bd13e87

Browse files
author
dereuromark
committed
Add NotJustNullSniff.
1 parent 9aa8056 commit bd13e87

File tree

4 files changed

+164
-58
lines changed

4 files changed

+164
-58
lines changed

PSR2R/Sniffs/Commenting/DocBlockParamAllowDefaultValueSniff.php

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHP_CodeSniffer_File;
66
use PSR2R\Tools\AbstractSniff;
77
use PSR2R\Tools\Traits\CommentingTrait;
8+
use PSR2R\Tools\Traits\SignatureTrait;
89

910
/**
1011
* Makes sure doc block param types allow `|null`, `|array` etc, when those are used
@@ -16,6 +17,7 @@
1617
class DocBlockParamAllowDefaultValueSniff extends AbstractSniff {
1718

1819
use CommentingTrait;
20+
use SignatureTrait;
1921

2022
/**
2123
* @inheritDoc
@@ -118,62 +120,4 @@ public function process(PHP_CodeSniffer_File $phpCsFile, $stackPointer) {
118120
}
119121
}
120122

121-
/**
122-
* @param \PHP_CodeSniffer_File $phpCsFile
123-
* @param int $stackPtr
124-
* @return array
125-
*/
126-
protected function getMethodSignature(PHP_CodeSniffer_File $phpCsFile, $stackPtr) {
127-
$tokens = $phpCsFile->getTokens();
128-
129-
$startIndex = $phpCsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr + 1);
130-
$endIndex = $tokens[$startIndex]['parenthesis_closer'];
131-
132-
$arguments = [];
133-
$i = $startIndex;
134-
while ($nextVariableIndex = $phpCsFile->findNext(T_VARIABLE, $i + 1, $endIndex)) {
135-
$typehintIndex = $defaultIndex = $default = null;
136-
$possibleTypeHint = $phpCsFile->findPrevious([T_ARRAY_HINT, T_CALLABLE], $nextVariableIndex - 1, $nextVariableIndex - 3);
137-
if ($possibleTypeHint) {
138-
$typehintIndex = $possibleTypeHint;
139-
}
140-
141-
$possibleEqualIndex = $phpCsFile->findNext([T_EQUAL], $nextVariableIndex + 1, $nextVariableIndex + 3);
142-
if ($possibleEqualIndex) {
143-
$whitelist = [T_CONSTANT_ENCAPSED_STRING, T_TRUE, T_FALSE, T_NULL, T_OPEN_SHORT_ARRAY, T_LNUMBER, T_DNUMBER];
144-
$possibleDefaultValue = $phpCsFile->findNext($whitelist, $possibleEqualIndex + 1, $possibleEqualIndex + 3);
145-
if ($possibleDefaultValue) {
146-
$defaultIndex = $possibleDefaultValue;
147-
//$default = $tokens[$defaultIndex]['content'];
148-
if ($tokens[$defaultIndex]['code'] === T_CONSTANT_ENCAPSED_STRING) {
149-
$default = 'string';
150-
} elseif ($tokens[$defaultIndex]['code'] === T_OPEN_SHORT_ARRAY) {
151-
$default = 'array';
152-
} elseif ($tokens[$defaultIndex]['code'] === T_FALSE || $tokens[$defaultIndex]['code'] === T_TRUE) {
153-
$default = 'bool';
154-
} elseif ($tokens[$defaultIndex]['code'] === T_LNUMBER) {
155-
$default = 'int';
156-
} elseif ($tokens[$defaultIndex]['code'] === T_DNUMBER) {
157-
$default = 'float';
158-
} elseif ($tokens[$defaultIndex]['code'] === T_NULL) {
159-
$default = 'null';
160-
} else {
161-
//die('Invalid default type: ' . $default);
162-
}
163-
}
164-
}
165-
166-
$arguments[] = [
167-
'variable' => $nextVariableIndex,
168-
'typehintIndex' => $typehintIndex,
169-
'defaultIndex' => $defaultIndex,
170-
'default' => $default,
171-
];
172-
173-
$i = $nextVariableIndex;
174-
}
175-
176-
return $arguments;
177-
}
178-
179123
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace PSR2R\Sniffs\Commenting;
4+
5+
use PHP_CodeSniffer_File;
6+
use PSR2R\Tools\AbstractSniff;
7+
use PSR2R\Tools\Traits\CommentingTrait;
8+
use PSR2R\Tools\Traits\SignatureTrait;
9+
10+
/**
11+
* Makes sure doc block param types are never just `null`, but always another type and optionally nullable on top.
12+
*
13+
* @author Mark Scherer
14+
* @license MIT
15+
*/
16+
class DocBlockParamNotJustNullSniff extends AbstractSniff {
17+
18+
use CommentingTrait;
19+
use SignatureTrait;
20+
21+
/**
22+
* @inheritDoc
23+
*/
24+
public function register() {
25+
return [
26+
T_FUNCTION,
27+
];
28+
}
29+
30+
/**
31+
* @inheritDoc
32+
*/
33+
public function process(PHP_CodeSniffer_File $phpCsFile, $stackPointer) {
34+
$tokens = $phpCsFile->getTokens();
35+
36+
$docBlockEndIndex = $this->findRelatedDocBlock($phpCsFile, $stackPointer);
37+
38+
if (!$docBlockEndIndex) {
39+
return;
40+
}
41+
42+
$methodSignature = $this->getMethodSignature($phpCsFile, $stackPointer);
43+
if (!$methodSignature) {
44+
return;
45+
}
46+
47+
$docBlockStartIndex = $tokens[$docBlockEndIndex]['comment_opener'];
48+
49+
$paramCount = 0;
50+
for ($i = $docBlockStartIndex + 1; $i < $docBlockEndIndex; $i++) {
51+
if ($tokens[$i]['type'] !== 'T_DOC_COMMENT_TAG') {
52+
continue;
53+
}
54+
if (!in_array($tokens[$i]['content'], ['@param'])) {
55+
continue;
56+
}
57+
58+
if (empty($methodSignature[$paramCount])) {
59+
continue;
60+
}
61+
$methodSignatureValue = $methodSignature[$paramCount];
62+
$paramCount++;
63+
64+
$classNameIndex = $i + 2;
65+
66+
if ($tokens[$classNameIndex]['type'] !== 'T_DOC_COMMENT_STRING') {
67+
// Let another sniffer take care of the missing type
68+
continue;
69+
}
70+
71+
$content = $tokens[$classNameIndex]['content'];
72+
73+
$appendix = '';
74+
$spaceIndex = strpos($content, ' ');
75+
if ($spaceIndex) {
76+
$appendix = substr($content, $spaceIndex);
77+
$content = substr($content, 0, $spaceIndex);
78+
}
79+
if (empty($content) || $content !== 'null') {
80+
continue;
81+
}
82+
83+
$phpCsFile->addError('"null" as only param type does not make sense', $classNameIndex, 'NotJustNull');
84+
}
85+
}
86+
87+
}

PSR2R/Sniffs/Commenting/DocBlockParamSniff.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHP_CodeSniffer_File;
66
use PSR2R\Tools\AbstractSniff;
77
use PSR2R\Tools\Traits\CommentingTrait;
8+
use PSR2R\Tools\Traits\SignatureTrait;
89

910
/**
1011
* Makes sure doc block param types match the variable name of the method signature.
@@ -15,6 +16,7 @@
1516
class DocBlockParamSniff extends AbstractSniff {
1617

1718
use CommentingTrait;
19+
use SignatureTrait;
1820

1921
/**
2022
* @inheritDoc
@@ -122,6 +124,8 @@ public function process(PHP_CodeSniffer_File $phpCsFile, $stackPointer) {
122124
}
123125

124126
/**
127+
* //TODO: Replace with SignatureTrait
128+
*
125129
* @param \PHP_CodeSniffer_File $phpCsFile
126130
* @param int $stackPtr
127131
* @return array

PSR2R/Tools/Traits/SignatureTrait.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace PSR2R\Tools\Traits;
4+
5+
use PHP_CodeSniffer_File;
6+
7+
/**
8+
* Method signature functionality.
9+
*/
10+
trait SignatureTrait {
11+
12+
/**
13+
* @param \PHP_CodeSniffer_File $phpCsFile
14+
* @param int $stackPtr
15+
*
16+
* @return array
17+
*/
18+
protected function getMethodSignature(PHP_CodeSniffer_File $phpCsFile, $stackPtr) {
19+
$tokens = $phpCsFile->getTokens();
20+
21+
$startIndex = $phpCsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr + 1);
22+
$endIndex = $tokens[$startIndex]['parenthesis_closer'];
23+
24+
$arguments = [];
25+
$i = $startIndex;
26+
while ($nextVariableIndex = $phpCsFile->findNext(T_VARIABLE, $i + 1, $endIndex)) {
27+
$typehintIndex = $defaultIndex = $default = null;
28+
$possibleTypeHint = $phpCsFile->findPrevious([T_ARRAY_HINT, T_CALLABLE], $nextVariableIndex - 1, $nextVariableIndex - 3);
29+
if ($possibleTypeHint) {
30+
$typehintIndex = $possibleTypeHint;
31+
}
32+
33+
$possibleEqualIndex = $phpCsFile->findNext([T_EQUAL], $nextVariableIndex + 1, $nextVariableIndex + 3);
34+
if ($possibleEqualIndex) {
35+
$whitelist = [T_CONSTANT_ENCAPSED_STRING, T_TRUE, T_FALSE, T_NULL, T_OPEN_SHORT_ARRAY, T_LNUMBER, T_DNUMBER];
36+
$possibleDefaultValue = $phpCsFile->findNext($whitelist, $possibleEqualIndex + 1, $possibleEqualIndex + 3);
37+
if ($possibleDefaultValue) {
38+
$defaultIndex = $possibleDefaultValue;
39+
//$default = $tokens[$defaultIndex]['content'];
40+
if ($tokens[$defaultIndex]['code'] === T_CONSTANT_ENCAPSED_STRING) {
41+
$default = 'string';
42+
} elseif ($tokens[$defaultIndex]['code'] === T_OPEN_SHORT_ARRAY) {
43+
$default = 'array';
44+
} elseif ($tokens[$defaultIndex]['code'] === T_FALSE || $tokens[$defaultIndex]['code'] === T_TRUE) {
45+
$default = 'bool';
46+
} elseif ($tokens[$defaultIndex]['code'] === T_LNUMBER) {
47+
$default = 'int';
48+
} elseif ($tokens[$defaultIndex]['code'] === T_DNUMBER) {
49+
$default = 'float';
50+
} elseif ($tokens[$defaultIndex]['code'] === T_NULL) {
51+
$default = 'null';
52+
} else {
53+
//die('Invalid default type: ' . $default);
54+
}
55+
}
56+
}
57+
58+
$arguments[] = [
59+
'variable' => $nextVariableIndex,
60+
'typehintIndex' => $typehintIndex,
61+
'defaultIndex' => $defaultIndex,
62+
'default' => $default,
63+
];
64+
65+
$i = $nextVariableIndex;
66+
}
67+
68+
return $arguments;
69+
}
70+
71+
}

0 commit comments

Comments
 (0)