Skip to content

Commit b1bd09a

Browse files
authored
Merge pull request #327 from cakephp/function-attribute
Allow attribute between docblock and function.
2 parents 6ad8574 + 9128bba commit b1bd09a

File tree

5 files changed

+164
-3
lines changed

5 files changed

+164
-3
lines changed

CakePHP/Sniffs/Commenting/FunctionCommentSniff.php

Lines changed: 134 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
namespace CakePHP\Sniffs\Commenting;
1616

1717
use PHP_CodeSniffer\Files\File;
18-
use PHP_CodeSniffer\Standards\PEAR\Sniffs\Commenting\FunctionCommentSniff as PearFunctionCommentSniff;
18+
use PHP_CodeSniffer\Sniffs\Sniff;
1919
use PHP_CodeSniffer\Util\Common;
20+
use PHP_CodeSniffer\Util\Tokens;
2021

2122
/**
2223
* Parses and verifies the doc comments for functions.
@@ -47,8 +48,139 @@
4748
* @version Release: @package_version@
4849
* @link http://pear.php.net/package/PHP_CodeSniffer
4950
*/
50-
class FunctionCommentSniff extends PearFunctionCommentSniff
51+
class FunctionCommentSniff implements Sniff
5152
{
53+
/**
54+
* Disable the check for functions with a lower visibility than the value given.
55+
*
56+
* Allowed values are public, protected, and private.
57+
*
58+
* @var string
59+
*/
60+
public $minimumVisibility = 'private';
61+
62+
/**
63+
* Array of methods which do not require a return type.
64+
*
65+
* @var array
66+
*/
67+
public $specialMethods = [
68+
'__construct',
69+
'__destruct',
70+
];
71+
72+
/**
73+
* Returns an array of tokens this test wants to listen for.
74+
*
75+
* @return array
76+
*/
77+
public function register()
78+
{
79+
return [T_FUNCTION];
80+
}
81+
82+
/**
83+
* Processes this test, when one of its tokens is encountered.
84+
*
85+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
86+
* @param int $stackPtr The position of the current token in the stack passed in $tokens.
87+
* @return void
88+
*/
89+
public function process(File $phpcsFile, $stackPtr)
90+
{
91+
$scopeModifier = $phpcsFile->getMethodProperties($stackPtr)['scope'];
92+
if (
93+
$scopeModifier === 'protected'
94+
&& $this->minimumVisibility === 'public'
95+
|| $scopeModifier === 'private'
96+
&& ($this->minimumVisibility === 'public' || $this->minimumVisibility === 'protected')
97+
) {
98+
return;
99+
}
100+
101+
$tokens = $phpcsFile->getTokens();
102+
$ignore = Tokens::$methodPrefixes;
103+
$ignore[] = T_WHITESPACE;
104+
105+
$commentEnd = $phpcsFile->findPrevious($ignore, $stackPtr - 1, null, true);
106+
if ($tokens[$commentEnd]['code'] === T_COMMENT) {
107+
// Inline comments might just be closing comments for
108+
// control structures or functions instead of function comments
109+
// using the wrong comment type. If there is other code on the line,
110+
// assume they relate to that code.
111+
$prev = $phpcsFile->findPrevious($ignore, $commentEnd - 1, null, true);
112+
if ($prev !== false && $tokens[$prev]['line'] === $tokens[$commentEnd]['line']) {
113+
$commentEnd = $prev;
114+
}
115+
}
116+
117+
if (
118+
$tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG
119+
&& $tokens[$commentEnd]['code'] !== T_COMMENT
120+
) {
121+
$previous = $commentEnd;
122+
if (
123+
$tokens[$commentEnd]['type'] === 'T_ATTRIBUTE_END'
124+
|| $tokens[$commentEnd]['type'] === 'T_ATTRIBUTE'
125+
) {
126+
while ($tokens[$previous]['type'] !== 'T_ATTRIBUTE') {
127+
$previous--;
128+
}
129+
$previous--;
130+
131+
$commentEnd = $phpcsFile->findPrevious($ignore, $previous, null, true);
132+
if ($tokens[$commentEnd]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
133+
if ($tokens[$commentEnd]['line'] !== $tokens[$previous]['line'] - 1) {
134+
$error = 'There must be no blank lines after the function comment';
135+
$phpcsFile->addError($error, $commentEnd, 'SpacingAfter');
136+
}
137+
138+
return;
139+
}
140+
}
141+
142+
$function = $phpcsFile->getDeclarationName($stackPtr);
143+
$phpcsFile->addError(
144+
'Missing doc comment for function %s()',
145+
$stackPtr,
146+
'Missing',
147+
[$function]
148+
);
149+
$phpcsFile->recordMetric($stackPtr, 'Function has doc comment', 'no');
150+
151+
return;
152+
} else {
153+
$phpcsFile->recordMetric($stackPtr, 'Function has doc comment', 'yes');
154+
}
155+
156+
if ($tokens[$commentEnd]['code'] === T_COMMENT) {
157+
$phpcsFile->addError('You must use "/**" style comments for a function comment', $stackPtr, 'WrongStyle');
158+
159+
return;
160+
}
161+
162+
if ($tokens[$commentEnd]['line'] !== $tokens[$stackPtr]['line'] - 1) {
163+
$error = 'There must be no blank lines after the function comment';
164+
$phpcsFile->addError($error, $commentEnd, 'SpacingAfter');
165+
}
166+
167+
$commentStart = $tokens[$commentEnd]['comment_opener'];
168+
foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
169+
if ($tokens[$tag]['content'] === '@see') {
170+
// Make sure the tag isn't empty.
171+
$string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
172+
if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) {
173+
$error = 'Content missing for @see tag in function comment';
174+
$phpcsFile->addError($error, $tag, 'EmptySees');
175+
}
176+
}
177+
}
178+
179+
$this->processReturn($phpcsFile, $stackPtr, $commentStart);
180+
$this->processThrows($phpcsFile, $stackPtr, $commentStart);
181+
$this->processParams($phpcsFile, $stackPtr, $commentStart);
182+
}
183+
52184
/**
53185
* Checks if the doc comment is an inheritDoc comment.
54186
*

CakePHP/Sniffs/WhiteSpace/FunctionSpacingSniff.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ protected function assertNewLineAtTheBeginning(File $phpCsFile, $stackPointer)
134134
}
135135

136136
$prevContentIndex = $phpCsFile->findPrevious(T_WHITESPACE, $firstTokenInLineIndex - 1, null, true);
137+
138+
if ($tokens[$prevContentIndex]['type'] === 'T_ATTRIBUTE_END') {
139+
return;
140+
}
141+
137142
if ($tokens[$prevContentIndex]['type'] === 'T_DOC_COMMENT_CLOSE_TAG') {
138143
$firstTokenInLineIndex = $tokens[$prevContentIndex]['comment_opener'];
139144
while ($tokens[$firstTokenInLineIndex - 1]['line'] === $line) {

CakePHP/Tests/Commenting/FunctionCommentUnitTest.inc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,16 @@ class Foo
227227
public function withInheritDocIncompleteTags($param)
228228
{
229229
}
230+
231+
/**
232+
* Some sentence.
233+
*
234+
* @param integer $param Some Param.
235+
* @param boolean $otherParam Some Other Param.
236+
* @return string Something.
237+
*/
238+
#[ReturnTypeWillChange]
239+
public function returnWillChange($param, $otherParam)
240+
{
241+
}
230242
}

CakePHP/Tests/Commenting/FunctionCommentUnitTest.inc.fixed

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,16 @@ class Foo
227227
public function withInheritDocIncompleteTags($param)
228228
{
229229
}
230+
231+
/**
232+
* Some sentence.
233+
*
234+
* @param integer $param Some Param.
235+
* @param boolean $otherParam Some Other Param.
236+
* @return string Something.
237+
*/
238+
#[ReturnTypeWillChange]
239+
public function returnWillChange($param, $otherParam)
240+
{
241+
}
230242
}

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"require": {
2121
"php": ">=7.2.0",
2222
"slevomat/coding-standard": "^6.3.6 || ^7.0",
23-
"squizlabs/php_codesniffer": "^3.5.5"
23+
"squizlabs/php_codesniffer": "^3.6"
2424
},
2525
"require-dev": {
2626
"phpunit/phpunit": "^7.1"

0 commit comments

Comments
 (0)