From 8a71fc68028d60104e019c4b1d05acd326442236 Mon Sep 17 00:00:00 2001 From: yCodeTech Date: Thu, 26 Mar 2026 05:20:15 +0000 Subject: [PATCH] feat: implement `DisallowVoidType` sniff and related tests - Add `DisallowVoidTypeSniff` to disallow explicit `: void` return types. - Create documentation for the disallowed void type standard. - Add unit tests to verify detection of explicit void return types. - Update existing test files to remove explicit void return types. - Update README with the new sniff documentation. --- README.md | 50 ++++++ test_utils/TestFile.php | 10 +- test_utils/TestFile_WithErrors_DoNotFix.php | 10 +- .../Docs/Types/DisallowVoidTypeStandard.xml | 28 ++++ .../Sniffs/Types/DisallowVoidTypeSniff.php | 144 ++++++++++++++++++ .../Tests/Types/DisallowVoidTypeUnitTest.inc | 40 +++++ .../Types/DisallowVoidTypeUnitTest.inc.fixed | 40 +++++ .../Tests/Types/DisallowVoidTypeUnitTest.php | 51 +++++++ 8 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 yCodeTech/Docs/Types/DisallowVoidTypeStandard.xml create mode 100644 yCodeTech/Sniffs/Types/DisallowVoidTypeSniff.php create mode 100644 yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.inc create mode 100644 yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.inc.fixed create mode 100644 yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.php diff --git a/README.md b/README.md index 9c5fba7..54f2696 100644 --- a/README.md +++ b/README.md @@ -579,6 +579,56 @@ $bar = (integer) $count; +### yCodeTech.Types.DisallowVoidType + +Explicit `void` return type declarations are disallowed on functions, methods, and closures. The absence of a return type already implies void. + + + + + + + + + + +
RulesFixable?
Explicit : void return type declarations must be removed.✔️
+ +#### Violation Codes: + +`yCodeTech.Types.DisallowVoidType.Found` + +#### Examples: + + + + + + + + + + +
✔️ Valid: No return type (implicitly void)❌ Invalid: Explicit void return type
+ +```php +function doSomething() +{ + echo "Hello"; +} +``` + + + +```php +function doSomething(): void +{ + echo "Hello"; +} +``` + +
+ ## Testing To test the standard against the provided comprehensive test file, please see [the specific instructions](./test_utils/README.md). diff --git a/test_utils/TestFile.php b/test_utils/TestFile.php index 44326a1..ad842b9 100644 --- a/test_utils/TestFile.php +++ b/test_utils/TestFile.php @@ -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 */ @@ -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 */ diff --git a/test_utils/TestFile_WithErrors_DoNotFix.php b/test_utils/TestFile_WithErrors_DoNotFix.php index 44326a1..ad842b9 100644 --- a/test_utils/TestFile_WithErrors_DoNotFix.php +++ b/test_utils/TestFile_WithErrors_DoNotFix.php @@ -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 */ @@ -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 */ diff --git a/yCodeTech/Docs/Types/DisallowVoidTypeStandard.xml b/yCodeTech/Docs/Types/DisallowVoidTypeStandard.xml new file mode 100644 index 0000000..2185019 --- /dev/null +++ b/yCodeTech/Docs/Types/DisallowVoidTypeStandard.xml @@ -0,0 +1,28 @@ + + + + + + + + + + : void +{ + echo "Hello"; +} + ]]> + + + diff --git a/yCodeTech/Sniffs/Types/DisallowVoidTypeSniff.php b/yCodeTech/Sniffs/Types/DisallowVoidTypeSniff.php new file mode 100644 index 0000000..ee1105f --- /dev/null +++ b/yCodeTech/Sniffs/Types/DisallowVoidTypeSniff.php @@ -0,0 +1,144 @@ + + */ + 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(); + } +} diff --git a/yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.inc b/yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.inc new file mode 100644 index 0000000..686154a --- /dev/null +++ b/yCodeTech/Tests/Types/DisallowVoidTypeUnitTest.inc @@ -0,0 +1,40 @@ + + */ + public function getErrorList() + { + return [ + 14 => 1, // explicitVoidMethod(): void + 19 => 1, // explicitVoidWithParam(): void + 37 => 1, // explicitVoidFunction(): void + ]; + } + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @return array + */ + public function getWarningList() + { + return []; + } +}