diff --git a/build/code_sniffer/phpbb/Sniffs/CodeLayout/UnionTypesCheckSniff.php b/build/code_sniffer/phpbb/Sniffs/CodeLayout/UnionTypesCheckSniff.php new file mode 100644 index 0000000000..c74ec56128 --- /dev/null +++ b/build/code_sniffer/phpbb/Sniffs/CodeLayout/UnionTypesCheckSniff.php @@ -0,0 +1,96 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\Sniffs\CodeLayout; + +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; + +/** + * Checks that union type declarations follows the coding guidelines. + */ +class UnionTypesCheckSniff implements Sniff +{ + /** + * {@inheritdoc} + */ + public function register() + { + return [ + T_TYPE_UNION, + T_NULLABLE, + ]; + } + + /** + * {@inheritdoc} + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check if nullable type shortcut syntax ('?typehint') is used + if ($tokens[$stackPtr]['type'] === 'T_NULLABLE') + { + $type = $tokens[$stackPtr + 1]['content']; + $error = 'Nullable shortcut syntax must not be used. Use union type instead: %2$s|null; found %1$s%2$s'; + $data = [trim($tokens[$stackPtr]['content']), $type]; + $phpcsFile->addError($error, $stackPtr, 'ShortNullableSyntax', $data); + } + + // Get the entry before the 1st '|' and all entries after it untill the end of union type declaration + if ($tokens[$stackPtr]['type'] === 'T_TYPE_UNION' && $tokens[$stackPtr - 2]['type'] !== 'T_TYPE_UNION') + { + // Get all the types within the union type declaration + $types_array = []; + for ($i = $stackPtr - 2; $i++;) + { + if (in_array($tokens[$i]['type'], ['T_TYPE_UNION', 'T_STRING', 'T_NULL'])) + { + if ($tokens[$i]['type'] != 'T_TYPE_UNION') + { + $types_array[] = $tokens[$i]['content']; + } + } + else + { + break; + } + } + + $types_array_sorted = $types_array_null_less = $types_array; + + // Check 'null' to be the last element + $null_position = array_search('null', $types_array); + if ($null_position !== false && $null_position != array_key_last($types_array)) + { + $error = 'The "null" type hint must be the last of the union type elements; found %s'; + $data = [implode('|', $types_array)]; + $phpcsFile->addError($error, $stackPtr, 'NullAlwaysLast', $data); + } + + // Check types excepting 'null' to follow alphabetical order + if ($null_position !== false) + { + array_splice($types_array_null_less, $null_position, 1); + } + sort($types_array_sorted); + if (!empty(array_diff_assoc($types_array_null_less, $types_array_sorted))) + { + $error = 'Union type elements must be sorted alphabetically excepting the "null" type hint must be the last if any; found %s'; + $data = [implode('|', $types_array)]; + $phpcsFile->addError($error, $stackPtr, 'AlphabeticalSort', $data); + } + } + } +} diff --git a/build/code_sniffer/ruleset-php-strict.xml b/build/code_sniffer/ruleset-php-strict.xml index 9e2f0664d8..58fe270021 100644 --- a/build/code_sniffer/ruleset-php-strict.xml +++ b/build/code_sniffer/ruleset-php-strict.xml @@ -45,4 +45,8 @@ + + +