adds sniff to find @return void #1
4 changed files with 119 additions and 0 deletions
77
src/DigiComp/Sniffs/Annotations/ReturnIsNotVoidSniff.php
Normal file
77
src/DigiComp/Sniffs/Annotations/ReturnIsNotVoidSniff.php
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DigiComp\PhpCodesniffer\DigiComp\Sniffs\Annotations;
|
||||||
|
|
||||||
|
use PHP_CodeSniffer\Files\File;
|
||||||
|
use PHP_CodeSniffer\Sniffs\Sniff;
|
||||||
|
use PHP_CodeSniffer\Util\Tokens;
|
||||||
|
|
||||||
|
class ReturnIsNotVoidSniff implements Sniff
|
||||||
|
{
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
return [\T_FUNCTION];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(File $phpcsFile, $stackPtr)
|
||||||
|
{
|
||||||
|
$tokens = $phpcsFile->getTokens();
|
||||||
|
$ignore = Tokens::$methodPrefixes;
|
||||||
|
$ignore[\T_WHITESPACE] = \T_WHITESPACE;
|
||||||
|
|
||||||
|
for ($commentEnd = ($stackPtr - 1); $commentEnd >= 0; $commentEnd--) {
|
||||||
|
if (isset($ignore[$tokens[$commentEnd]['code']]) === true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$tokens[$commentEnd]['code'] === \T_ATTRIBUTE_END
|
||||||
|
&& isset($tokens[$commentEnd]['attribute_opener']) === true
|
||||||
|
) {
|
||||||
|
$commentEnd = $tokens[$commentEnd]['attribute_opener'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$commentStart = $tokens[$commentEnd]['comment_opener'];
|
||||||
|
|
||||||
|
foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
|
||||||
|
if (($tokens[$tag]['content'] === '@return') && 'void' === $tokens[$tag + 2]['content']) {
|
||||||
|
$fix = $phpcsFile->addFixableError('Return type void must not be annotated.', $tag, 'WrongReturnType');
|
||||||
|
if ($fix) {
|
||||||
|
$nextTokenIndex = \array_search($tag, $tokens[$commentStart]['comment_tags'], true) + 1;
|
||||||
|
if (!isset($tokens[$commentStart]['comment_tags'][$nextTokenIndex])) {
|
||||||
|
$tag -= 2;
|
||||||
|
$nextToken = $commentEnd;
|
||||||
|
} else {
|
||||||
|
$nextToken = $tokens[$commentStart]['comment_tags'][$nextTokenIndex];
|
||||||
|
}
|
||||||
|
$phpcsFile->fixer->beginChangeset();
|
||||||
|
for ($tokenToDelete = $tag; $tokenToDelete < $nextToken; $tokenToDelete++) {
|
||||||
|
$phpcsFile->fixer->replaceToken($tokenToDelete, '');
|
||||||
|
}
|
||||||
|
$phpcsFile->fixer->endChangeset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@
|
||||||
<property name="spacing" value="0"/>
|
<property name="spacing" value="0"/>
|
||||||
</properties>
|
</properties>
|
||||||
</rule>
|
</rule>
|
||||||
|
<rule ref="DigiComp.Annotations.ReturnIsNotVoid" />
|
||||||
<rule ref="DigiComp.Commenting.VariableComment.Missing">
|
<rule ref="DigiComp.Commenting.VariableComment.Missing">
|
||||||
<type>error</type>
|
<type>error</type>
|
||||||
<severity>6</severity>
|
<severity>6</severity>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DigiComp\PhpCodesniffer\DigiComp\Sniffs\Annotations;
|
||||||
|
|
||||||
|
use SlevomatCodingStandard\Sniffs\TestCase;
|
||||||
|
|
||||||
|
class ReturnIsNotVoidSniffTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testErrors(): void
|
||||||
|
{
|
||||||
|
$filename = __DIR__ . '/data/VoidReturner.php';
|
||||||
|
self::assertTrue(\is_file($filename));
|
||||||
|
$report = self::checkFile($filename);
|
||||||
|
self::assertSame(1, $report->getErrorCount());
|
||||||
|
}
|
||||||
|
}
|
23
tests/DigiComp/Sniffs/Annotations/data/VoidReturner.php
Normal file
23
tests/DigiComp/Sniffs/Annotations/data/VoidReturner.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DigiComp\PhpCodesniffer\DigiComp\Sniffs\Annotations\data;
|
||||||
|
|
||||||
|
class VoidReturner
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return \stdClass
|
||||||
|
*/
|
||||||
|
public function getStdClass(): \stdClass
|
||||||
|
{
|
||||||
|
return new \stdClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function getVoid(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue