Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow attribute between docblock and function. #327

Merged
merged 2 commits into from
Jun 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 134 additions & 2 deletions CakePHP/Sniffs/Commenting/FunctionCommentSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
namespace CakePHP\Sniffs\Commenting;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Standards\PEAR\Sniffs\Commenting\FunctionCommentSniff as PearFunctionCommentSniff;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Common;
use PHP_CodeSniffer\Util\Tokens;

/**
* Parses and verifies the doc comments for functions.
Expand Down Expand Up @@ -47,8 +48,139 @@
* @version Release: @package_version@
* @link http://pear.php.net/package/PHP_CodeSniffer
*/
class FunctionCommentSniff extends PearFunctionCommentSniff
class FunctionCommentSniff implements Sniff
{
/**
* Disable the check for functions with a lower visibility than the value given.
*
* Allowed values are public, protected, and private.
*
* @var string
*/
public $minimumVisibility = 'private';

/**
* Array of methods which do not require a return type.
*
* @var array
*/
public $specialMethods = [
'__construct',
'__destruct',
];

/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return [T_FUNCTION];
}

/**
* Processes this test, when one of its tokens is encountered.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token in the stack passed in $tokens.
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
$scopeModifier = $phpcsFile->getMethodProperties($stackPtr)['scope'];
if (
$scopeModifier === 'protected'
&& $this->minimumVisibility === 'public'
|| $scopeModifier === 'private'
&& ($this->minimumVisibility === 'public' || $this->minimumVisibility === 'protected')
) {
return;
}

$tokens = $phpcsFile->getTokens();
$ignore = Tokens::$methodPrefixes;
$ignore[] = T_WHITESPACE;

$commentEnd = $phpcsFile->findPrevious($ignore, $stackPtr - 1, null, true);
if ($tokens[$commentEnd]['code'] === T_COMMENT) {
// Inline comments might just be closing comments for
// control structures or functions instead of function comments
// using the wrong comment type. If there is other code on the line,
// assume they relate to that code.
$prev = $phpcsFile->findPrevious($ignore, $commentEnd - 1, null, true);
if ($prev !== false && $tokens[$prev]['line'] === $tokens[$commentEnd]['line']) {
$commentEnd = $prev;
}
}

if (
$tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG
&& $tokens[$commentEnd]['code'] !== T_COMMENT
) {
$previous = $commentEnd;
if (
$tokens[$commentEnd]['type'] === 'T_ATTRIBUTE_END'
|| $tokens[$commentEnd]['type'] === 'T_ATTRIBUTE'
) {
while ($tokens[$previous]['type'] !== 'T_ATTRIBUTE') {
$previous--;
}
$previous--;

$commentEnd = $phpcsFile->findPrevious($ignore, $previous, null, true);
if ($tokens[$commentEnd]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
if ($tokens[$commentEnd]['line'] !== $tokens[$previous]['line'] - 1) {
$error = 'There must be no blank lines after the function comment';
$phpcsFile->addError($error, $commentEnd, 'SpacingAfter');
}

return;
}
}

$function = $phpcsFile->getDeclarationName($stackPtr);
$phpcsFile->addError(
'Missing doc comment for function %s()',
$stackPtr,
'Missing',
[$function]
);
$phpcsFile->recordMetric($stackPtr, 'Function has doc comment', 'no');

return;
} else {
$phpcsFile->recordMetric($stackPtr, 'Function has doc comment', 'yes');
}

if ($tokens[$commentEnd]['code'] === T_COMMENT) {
$phpcsFile->addError('You must use "/**" style comments for a function comment', $stackPtr, 'WrongStyle');

return;
}

if ($tokens[$commentEnd]['line'] !== $tokens[$stackPtr]['line'] - 1) {
$error = 'There must be no blank lines after the function comment';
$phpcsFile->addError($error, $commentEnd, 'SpacingAfter');
}

$commentStart = $tokens[$commentEnd]['comment_opener'];
foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
if ($tokens[$tag]['content'] === '@see') {
// Make sure the tag isn't empty.
$string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) {
$error = 'Content missing for @see tag in function comment';
$phpcsFile->addError($error, $tag, 'EmptySees');
}
}
}

$this->processReturn($phpcsFile, $stackPtr, $commentStart);
$this->processThrows($phpcsFile, $stackPtr, $commentStart);
$this->processParams($phpcsFile, $stackPtr, $commentStart);
}

/**
* Checks if the doc comment is an inheritDoc comment.
*
Expand Down
5 changes: 5 additions & 0 deletions CakePHP/Sniffs/WhiteSpace/FunctionSpacingSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ protected function assertNewLineAtTheBeginning(File $phpCsFile, $stackPointer)
}

$prevContentIndex = $phpCsFile->findPrevious(T_WHITESPACE, $firstTokenInLineIndex - 1, null, true);

if ($tokens[$prevContentIndex]['type'] === 'T_ATTRIBUTE_END') {
return;
}

if ($tokens[$prevContentIndex]['type'] === 'T_DOC_COMMENT_CLOSE_TAG') {
$firstTokenInLineIndex = $tokens[$prevContentIndex]['comment_opener'];
while ($tokens[$firstTokenInLineIndex - 1]['line'] === $line) {
Expand Down
12 changes: 12 additions & 0 deletions CakePHP/Tests/Commenting/FunctionCommentUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,16 @@ class Foo
public function withInheritDocIncompleteTags($param)
{
}

/**
* Some sentence.
*
* @param integer $param Some Param.
* @param boolean $otherParam Some Other Param.
* @return string Something.
*/
#[ReturnTypeWillChange]
public function returnWillChange($param, $otherParam)
{
}
}
12 changes: 12 additions & 0 deletions CakePHP/Tests/Commenting/FunctionCommentUnitTest.inc.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,16 @@ class Foo
public function withInheritDocIncompleteTags($param)
{
}

/**
* Some sentence.
*
* @param integer $param Some Param.
* @param boolean $otherParam Some Other Param.
* @return string Something.
*/
#[ReturnTypeWillChange]
public function returnWillChange($param, $otherParam)
{
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"require": {
"php": ">=7.2.0",
"slevomat/coding-standard": "^6.3.6 || ^7.0",
"squizlabs/php_codesniffer": "^3.5.5"
"squizlabs/php_codesniffer": "^3.6"
},
"require-dev": {
"phpunit/phpunit": "^7.1"
Expand Down