Skip to content
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
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,56 @@ $bar = (integer) $count;
</tr>
</table>

### yCodeTech.Types.DisallowVoidType

Explicit `void` return type declarations are disallowed on functions, methods, and closures. The absence of a return type already implies void.

<table>
<tr>
<th>Rules</th>
<th>Fixable?</th>
</tr>
<tr>
<td>Explicit <code>: void</code> return type declarations must be removed.</td>
<td>✔️</td>
</tr>
</table>

#### Violation Codes:

`yCodeTech.Types.DisallowVoidType.Found`

#### Examples:

<table>
<tr>
<th>✔️ Valid: No return type (implicitly void)</th>
<th>❌ Invalid: Explicit void return type</th>
</tr>
<tr>
<td>

```php
function doSomething()
{
echo "Hello";
}
```

</td>
<td>

```php
function doSomething(): void
{
echo "Hello";
}
```

</td>
</tr>
</table>

## Testing

To test the standard against the provided comprehensive test file, please see [the specific instructions](./test_utils/README.md).
Expand Down
10 changes: 7 additions & 3 deletions test_utils/TestFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,14 @@ public function testMissingGeneratorReturn()
***********************/

/**
* Function that returns void with an explicit `void` typing
* (should NOT be flagged for missing `@return` tag).
* Function that returns void with an explicit `void` typing
* (should be flagged for explicit void type, but NOT for missing `@return` tag).
*
* The following should be fixed:
* - The explicit `: void` return type should be removed.
*
* The following should NOT be fixed:
* - A `@return` tag should not be added for an explicit `void` return.
* - A `@return` tag should not be added.
*
* @param string $message Message to display
*/
Expand Down Expand Up @@ -360,6 +363,7 @@ function testVoidFunctionWithAnonymousFunction()
*
* The following should be fixed:
* - The `@return` tag should be removed.
* - The explicit `: void` return type should be removed.
*
* @return void
*/
Expand Down
10 changes: 7 additions & 3 deletions test_utils/TestFile_WithErrors_DoNotFix.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,14 @@ public function testMissingGeneratorReturn()
***********************/

/**
* Function that returns void with an explicit `void` typing
* (should NOT be flagged for missing `@return` tag).
* Function that returns void with an explicit `void` typing
* (should be flagged for explicit void type, but NOT for missing `@return` tag).
*
* The following should be fixed:
* - The explicit `: void` return type should be removed.
*
* The following should NOT be fixed:
* - A `@return` tag should not be added for an explicit `void` return.
* - A `@return` tag should not be added.
*
* @param string $message Message to display
*/
Expand Down Expand Up @@ -360,6 +363,7 @@ function testVoidFunctionWithAnonymousFunction()
*
* The following should be fixed:
* - The `@return` tag should be removed.
* - The explicit `: void` return type should be removed.
*
* @return void
*/
Expand Down
28 changes: 28 additions & 0 deletions yCodeTech/Docs/Types/DisallowVoidTypeStandard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<documentation title="Disallow Void Type">
<standard>
<![CDATA[
Explicit void return type declarations are disallowed. The absence of a return type already implies void.

---

]]>
</standard>
<code_comparison>
<code title="✔️ Valid: No return type (implicitly void)">
<![CDATA[
function doSomething()
{
echo "Hello";
}
]]>
</code>
<code title="❌ Invalid: Explicit void return type">
<![CDATA[
function doSomething()<em>: void</em>
{
echo "Hello";
}
]]>
</code>
</code_comparison>
</documentation>
144 changes: 144 additions & 0 deletions yCodeTech/Sniffs/Types/DisallowVoidTypeSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

/**
* DisallowVoidType sniff for yCodeTech PHPCS Standard.
*
* Disallows explicit void return type declarations on functions and methods.
*
* @category PHP
* @package PHP_CodeSniffer
* @author yCodeTech
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/

namespace yCodeTech\Sniffs\Types;

use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;

/**
* DisallowVoidType sniff.
*
* Disallows explicit `: void` return type declarations on functions, methods,
* and closures. The absence of a return type already implies void.
*/
class DisallowVoidTypeSniff implements Sniff
{
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array<int>
*/
public function register()
{
return [T_FUNCTION, T_CLOSURE];
}

/**
* 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.
*/
public function process(File $phpcsFile, $stackPtr)
{
$voidPtr = $this->getExplicitVoidTypePtr($phpcsFile, $stackPtr);
if ($voidPtr === false) {
return;
}

$error = 'Explicit void return type is not allowed and should be removed';
$fix = $phpcsFile->addFixableError($error, $voidPtr, 'Found');
if ($fix === true) {
$this->removeExplicitVoidType($phpcsFile, $stackPtr);
}
}

/**
* Get the position of the explicit `void` return type token, if present.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the function token.
*
* @return int|false The position of the void token, or false if not found.
*/
private function getExplicitVoidTypePtr(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();

$openParen = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr);
if ($openParen === false) {
return false;
}

$closeParen = $tokens[$openParen]['parenthesis_closer'] ?? null;
if ($closeParen === null) {
return false;
}

$scopeOpener = $tokens[$stackPtr]['scope_opener'] ?? null;
$semicolonPtr = $phpcsFile->findNext(T_SEMICOLON, $closeParen + 1);
$searchEnd = $scopeOpener ?? ($semicolonPtr !== false ? $semicolonPtr + 1 : null);

$colonPtr = $phpcsFile->findNext(T_COLON, $closeParen + 1, $searchEnd);
if ($colonPtr === false) {
return false;
}

$returnTypePtr = $phpcsFile->findNext(T_WHITESPACE, $colonPtr + 1, null, true);
if ($returnTypePtr === false) {
return false;
}

if ($tokens[$returnTypePtr]['code'] === T_STRING && $tokens[$returnTypePtr]['content'] === 'void') {
return $returnTypePtr;
}

return false;
}

/**
* Remove explicit `: void` return type from a function signature.
*
* Removes the colon, any whitespace between colon and void, and the `void`
* token itself, leaving the rest of the signature intact.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the function token.
*/
private function removeExplicitVoidType(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();

$openParen = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr);
if ($openParen === false) {
return;
}

$closeParen = $tokens[$openParen]['parenthesis_closer'] ?? null;
if ($closeParen === null) {
return;
}

$scopeOpener = $tokens[$stackPtr]['scope_opener'] ?? null;
$semicolonPtr = $phpcsFile->findNext(T_SEMICOLON, $closeParen + 1);
$searchEnd = $scopeOpener ?? ($semicolonPtr !== false ? $semicolonPtr + 1 : null);

$colonPtr = $phpcsFile->findNext(T_COLON, $closeParen + 1, $searchEnd);
if ($colonPtr === false) {
return;
}

$voidPtr = $phpcsFile->findNext(T_WHITESPACE, $colonPtr + 1, null, true);
if ($voidPtr === false || $tokens[$voidPtr]['content'] !== 'void') {
return;
}

$phpcsFile->fixer->beginChangeset();
for ($i = $colonPtr; $i <= $voidPtr; $i++) {
$phpcsFile->fixer->replaceToken($i, '');
}
$phpcsFile->fixer->endChangeset();
}
}
40 changes: 40 additions & 0 deletions yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

// @phpcs:disable yCodeTech.Commenting.FunctionComment
// We're not concerned with docblocks here.

/**
* Test file for DisallowVoidTypeSniff.
*
* Tests detection of explicit void return type declarations.
*/

class TestClass
{
public function explicitVoidMethod(): void
{
echo "Hello";
}

public function explicitVoidWithParam(string $message): void
{
echo $message;
}

// Should not flag - no void type
public function regularMethod(): string
{
return "Hello";
}

// Should not flag - no return type
public function noReturnType()
{
echo "Hello";
}
}

function explicitVoidFunction(): void
{
echo "Hello";
}
40 changes: 40 additions & 0 deletions yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.inc.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

// @phpcs:disable yCodeTech.Commenting.FunctionComment
// We're not concerned with docblocks here.

/**
* Test file for DisallowVoidTypeSniff.
*
* Tests detection of explicit void return type declarations.
*/

class TestClass
{
public function explicitVoidMethod()
{
echo "Hello";
}

public function explicitVoidWithParam(string $message)
{
echo $message;
}

// Should not flag - no void type
public function regularMethod(): string
{
return "Hello";
}

// Should not flag - no return type
public function noReturnType()
{
echo "Hello";
}
}

function explicitVoidFunction()
{
echo "Hello";
}
Loading