Merge pull request 'adds sniff to find @return void' (#1) from feature/return-void into master
All checks were successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/code-style Pipeline was successful

Reviewed-on: #1
This commit is contained in:
Ferdinand Kuhl 2023-01-29 14:59:10 +01:00
commit ef0ac65a4f
4 changed files with 119 additions and 0 deletions

View 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();
}
}
}
}
}

View file

@ -13,6 +13,7 @@
<property name="spacing" value="0"/>
</properties>
</rule>
<rule ref="DigiComp.Annotations.ReturnIsNotVoid" />
<rule ref="DigiComp.Commenting.VariableComment.Missing">
<type>error</type>
<severity>6</severity>

View file

@ -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());
}
}

View 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
{
}
}