?????????? ????????? - ??????????????? - /opt/cpanel/ea-wappspector/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/UselessParenthesesSniff.php
???????
<?php declare(strict_types = 1); namespace SlevomatCodingStandard\Sniffs\PHP; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; use SlevomatCodingStandard\Helpers\FixerHelper; use SlevomatCodingStandard\Helpers\IdentificatorHelper; use SlevomatCodingStandard\Helpers\TokenHelper; use function array_key_exists; use function array_map; use function array_merge; use function count; use function in_array; use const T_ANON_CLASS; use const T_ARRAY_CAST; use const T_BITWISE_AND; use const T_BITWISE_NOT; use const T_BITWISE_OR; use const T_BITWISE_XOR; use const T_BOOL_CAST; use const T_BOOLEAN_NOT; use const T_CASE; use const T_CLONE; use const T_CLOSE_PARENTHESIS; use const T_CLOSE_SHORT_ARRAY; use const T_CLOSURE; use const T_COALESCE; use const T_COLON; use const T_COMMA; use const T_CONSTANT_ENCAPSED_STRING; use const T_DIVIDE; use const T_DNUMBER; use const T_DOLLAR; use const T_DOUBLE_CAST; use const T_EMPTY; use const T_EQUAL; use const T_EVAL; use const T_EXIT; use const T_FN; use const T_INCLUDE; use const T_INCLUDE_ONCE; use const T_INLINE_THEN; use const T_INT_CAST; use const T_ISSET; use const T_LIST; use const T_LNUMBER; use const T_LOGICAL_AND; use const T_LOGICAL_OR; use const T_LOGICAL_XOR; use const T_MATCH; use const T_MINUS; use const T_MODULUS; use const T_MULTIPLY; use const T_NEW; use const T_OBJECT_CAST; use const T_OPEN_PARENTHESIS; use const T_PARENT; use const T_PLUS; use const T_POW; use const T_REQUIRE; use const T_REQUIRE_ONCE; use const T_SELF; use const T_SEMICOLON; use const T_SL; use const T_SR; use const T_STATIC; use const T_STRING_CAST; use const T_STRING_CONCAT; use const T_UNSET; use const T_UNSET_CAST; use const T_USE; use const T_VARIABLE; use const T_WHITESPACE; use const T_YIELD; use const T_YIELD_FROM; class UselessParenthesesSniff implements Sniff { public const CODE_USELESS_PARENTHESES = 'UselessParentheses'; private const OPERATORS = [ T_POW, T_MULTIPLY, T_DIVIDE, T_MODULUS, T_PLUS, T_MINUS, T_STRING_CONCAT, ]; private const OPERATOR_GROUPS = [ T_POW => 1, T_MULTIPLY => 2, T_DIVIDE => 2, T_MODULUS => 3, T_PLUS => 4, T_MINUS => 4, T_STRING_CONCAT => 5, ]; public bool $ignoreComplexTernaryConditions = false; /** * @return array<int, (int|string)> */ public function register(): array { return [ T_OPEN_PARENTHESIS, ]; } /** * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint * @param int $parenthesisOpenerPointer */ public function process(File $phpcsFile, $parenthesisOpenerPointer): void { $tokens = $phpcsFile->getTokens(); if (array_key_exists('parenthesis_owner', $tokens[$parenthesisOpenerPointer])) { return; } if (!array_key_exists('parenthesis_closer', $tokens[$parenthesisOpenerPointer])) { return; } /** @var int $pointerBeforeParenthesisOpener */ $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); if (in_array($tokens[$pointerBeforeParenthesisOpener]['code'], [ ...TokenHelper::NAME_TOKEN_CODES, T_VARIABLE, T_ISSET, T_UNSET, T_EMPTY, T_CLOSURE, T_FN, T_USE, T_ANON_CLASS, T_NEW, T_SELF, T_STATIC, T_PARENT, T_EXIT, T_CLOSE_PARENTHESIS, T_EVAL, T_LIST, T_INCLUDE, T_INCLUDE_ONCE, T_REQUIRE, T_REQUIRE_ONCE, T_INT_CAST, T_DOUBLE_CAST, T_STRING_CAST, T_ARRAY_CAST, T_OBJECT_CAST, T_BOOL_CAST, T_UNSET_CAST, T_MATCH, T_BITWISE_NOT, ], true,)) { return; } /** @var int $pointerAfterParenthesisOpener */ $pointerAfterParenthesisOpener = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); if (in_array( $tokens[$pointerAfterParenthesisOpener]['code'], [T_CLONE, T_YIELD, T_YIELD_FROM, T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE, T_ARRAY_CAST], true, )) { return; } if (TokenHelper::findNext( $phpcsFile, T_EQUAL, $parenthesisOpenerPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'], ) !== null) { return; } $pointerAfterParenthesisCloser = TokenHelper::findNextEffective( $phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1, ); if ( $pointerAfterParenthesisCloser !== null && $tokens[$pointerAfterParenthesisCloser]['code'] === T_OPEN_PARENTHESIS ) { return; } if (IdentificatorHelper::findStartPointer($phpcsFile, $pointerBeforeParenthesisOpener) !== null) { return; } $this->checkParenthesesAroundConditionInTernaryOperator($phpcsFile, $parenthesisOpenerPointer); $this->checkParenthesesAroundCaseInSwitch($phpcsFile, $parenthesisOpenerPointer); $this->checkParenthesesAroundVariableOrFunctionCall($phpcsFile, $parenthesisOpenerPointer); $this->checkParenthesesAroundString($phpcsFile, $parenthesisOpenerPointer); $this->checkParenthesesAroundOperators($phpcsFile, $parenthesisOpenerPointer); $this->checkParenthesesAroundNew($phpcsFile, $parenthesisOpenerPointer); } private function checkParenthesesAroundConditionInTernaryOperator(File $phpcsFile, int $parenthesisOpenerPointer): void { $tokens = $phpcsFile->getTokens(); $parenthesisCloserPointer = $tokens[$parenthesisOpenerPointer]['parenthesis_closer']; $ternaryOperatorPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisCloserPointer + 1); if ($tokens[$ternaryOperatorPointer]['code'] !== T_INLINE_THEN) { return; } if (TokenHelper::findNext( $phpcsFile, [T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR], $parenthesisOpenerPointer + 1, $parenthesisCloserPointer, ) !== null) { return; } $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); if ($tokens[$pointerBeforeParenthesisOpener]['code'] === T_BOOLEAN_NOT) { return; } if (in_array($tokens[$pointerBeforeParenthesisOpener]['code'], Tokens::$comparisonTokens, true)) { return; } if (in_array($tokens[$pointerBeforeParenthesisOpener]['code'], Tokens::$booleanOperators, true)) { return; } if ($this->ignoreComplexTernaryConditions) { if (TokenHelper::findNext( $phpcsFile, Tokens::$booleanOperators, $parenthesisOpenerPointer + 1, $parenthesisCloserPointer, ) !== null) { return; } if (TokenHelper::findNextContent( $phpcsFile, T_WHITESPACE, $phpcsFile->eolChar, $parenthesisOpenerPointer + 1, $parenthesisCloserPointer, ) !== null) { return; } } $contentStartPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); $contentEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisCloserPointer - 1); for ($i = $contentStartPointer; $i <= $contentEndPointer; $i++) { if ($tokens[$i]['code'] === T_INLINE_THEN) { return; } } $fix = $phpcsFile->addFixableError('Useless parentheses.', $parenthesisOpenerPointer, self::CODE_USELESS_PARENTHESES); if (!$fix) { return; } $phpcsFile->fixer->beginChangeset(); FixerHelper::removeBetweenIncluding($phpcsFile, $parenthesisOpenerPointer, $contentStartPointer - 1); FixerHelper::removeBetweenIncluding($phpcsFile, $contentEndPointer + 1, $parenthesisCloserPointer); $phpcsFile->fixer->endChangeset(); } private function checkParenthesesAroundCaseInSwitch(File $phpcsFile, int $parenthesisOpenerPointer): void { $tokens = $phpcsFile->getTokens(); $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); if ($tokens[$pointerBeforeParenthesisOpener]['code'] !== T_CASE) { return; } $pointerAfterParenthesisCloser = TokenHelper::findNextEffective( $phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1, ); if ($tokens[$pointerAfterParenthesisCloser]['code'] !== T_COLON) { return; } $fix = $phpcsFile->addFixableError('Useless parentheses.', $parenthesisOpenerPointer, self::CODE_USELESS_PARENTHESES); if (!$fix) { return; } $contentStartPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); $contentEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] - 1); $phpcsFile->fixer->beginChangeset(); FixerHelper::removeBetweenIncluding($phpcsFile, $parenthesisOpenerPointer, $contentStartPointer - 1); FixerHelper::removeBetweenIncluding($phpcsFile, $contentEndPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer']); $phpcsFile->fixer->endChangeset(); } private function checkParenthesesAroundVariableOrFunctionCall(File $phpcsFile, int $parenthesisOpenerPointer): void { $tokens = $phpcsFile->getTokens(); $pointerAfterParenthesis = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); if ($tokens[$pointerAfterParenthesis]['code'] === T_NEW) { // Check in other method return; } if ($tokens[$pointerAfterParenthesis]['code'] === T_OPEN_PARENTHESIS) { return; } $operatorsPointers = TokenHelper::findNextAll( $phpcsFile, self::OPERATORS, $parenthesisOpenerPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'], ); if ($operatorsPointers !== []) { return; } $casePointer = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); if ($tokens[$casePointer]['code'] === T_CASE) { return; } $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); if (in_array($tokens[$pointerBeforeParenthesisOpener]['code'], Tokens::$booleanOperators, true)) { return; } $pointerAfterParenthesisCloser = TokenHelper::findNextEffective( $phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1, ); if (in_array($tokens[$pointerAfterParenthesisCloser]['code'], [T_INLINE_THEN, T_OPEN_PARENTHESIS, T_SR], true)) { return; } /** @var int $contentStartPointer */ $contentStartPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); if ($tokens[$contentStartPointer]['code'] === T_CONSTANT_ENCAPSED_STRING) { return; } $notBooleanNotOperatorPointer = $contentStartPointer; if ($tokens[$contentStartPointer]['code'] === T_BOOLEAN_NOT) { /** @var int $notBooleanNotOperatorPointer */ $notBooleanNotOperatorPointer = TokenHelper::findNextEffective($phpcsFile, $contentStartPointer + 1); } if (in_array( $tokens[$notBooleanNotOperatorPointer]['code'], [T_SELF, T_STATIC, T_PARENT, T_VARIABLE, T_DOLLAR, ...TokenHelper::NAME_TOKEN_CODES], true, )) { $contentEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $notBooleanNotOperatorPointer); if ( $contentEndPointer === null && in_array($tokens[$notBooleanNotOperatorPointer]['code'], TokenHelper::NAME_TOKEN_CODES, true) ) { $nextPointer = TokenHelper::findNextEffective($phpcsFile, $contentStartPointer + 1); if ($tokens[$nextPointer]['code'] === T_OPEN_PARENTHESIS) { $contentEndPointer = $contentStartPointer; } } do { $nextPointer = TokenHelper::findNextEffective($phpcsFile, $contentEndPointer + 1); if ($tokens[$nextPointer]['code'] !== T_OPEN_PARENTHESIS) { break; } $contentEndPointer = $tokens[$nextPointer]['parenthesis_closer']; } while (true); } else { $nextPointer = TokenHelper::findNext($phpcsFile, T_OPEN_PARENTHESIS, $notBooleanNotOperatorPointer + 1); if ($nextPointer === null || !isset($tokens[$nextPointer]['parenthesis_closer'])) { return; } $contentEndPointer = $tokens[$nextPointer]['parenthesis_closer']; } $pointerAfterContent = TokenHelper::findNextEffective($phpcsFile, $contentEndPointer + 1); if ($pointerAfterContent !== $tokens[$parenthesisOpenerPointer]['parenthesis_closer']) { return; } $fix = $phpcsFile->addFixableError('Useless parentheses.', $parenthesisOpenerPointer, self::CODE_USELESS_PARENTHESES); if (!$fix) { return; } $phpcsFile->fixer->beginChangeset(); FixerHelper::removeBetweenIncluding($phpcsFile, $parenthesisOpenerPointer, $contentStartPointer - 1); FixerHelper::removeBetweenIncluding($phpcsFile, $contentEndPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer']); $phpcsFile->fixer->endChangeset(); } private function checkParenthesesAroundString(File $phpcsFile, int $parenthesisOpenerPointer): void { $tokens = $phpcsFile->getTokens(); /** @var int $stringPointer */ $stringPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); if ($tokens[$stringPointer]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } $pointerAfterString = TokenHelper::findNextEffective($phpcsFile, $stringPointer + 1); if ($pointerAfterString !== $tokens[$parenthesisOpenerPointer]['parenthesis_closer']) { return; } $fix = $phpcsFile->addFixableError('Useless parentheses.', $parenthesisOpenerPointer, self::CODE_USELESS_PARENTHESES); if (!$fix) { return; } $phpcsFile->fixer->beginChangeset(); FixerHelper::removeBetweenIncluding($phpcsFile, $parenthesisOpenerPointer, $stringPointer - 1); FixerHelper::removeBetweenIncluding($phpcsFile, $stringPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer']); $phpcsFile->fixer->endChangeset(); } private function checkParenthesesAroundOperators(File $phpcsFile, int $parenthesisOpenerPointer): void { $tokens = $phpcsFile->getTokens(); $newPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); if ($tokens[$newPointer]['code'] === T_NEW) { // Check in other method return; } $pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1); $pointerAfterParenthesisCloser = TokenHelper::findNextEffective( $phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1, ); if ($tokens[$pointerBeforeParenthesisOpener]['code'] === T_MINUS) { $pointerBeforeMinus = TokenHelper::findPreviousEffective($phpcsFile, $pointerBeforeParenthesisOpener - 1); if (!in_array($tokens[$pointerBeforeMinus]['code'], [T_DNUMBER, T_LNUMBER], true)) { return; } } if ( in_array($tokens[$pointerBeforeParenthesisOpener]['code'], Tokens::$booleanOperators, true) || in_array($tokens[$pointerAfterParenthesisCloser]['code'], Tokens::$booleanOperators, true) || $tokens[$pointerBeforeParenthesisOpener]['code'] === T_BOOLEAN_NOT ) { return; } $complicatedOperators = [T_INLINE_THEN, T_COALESCE, T_BITWISE_AND, T_BITWISE_OR, T_BITWISE_XOR, T_SL, T_SR]; $operatorsPointers = []; $actualStartPointer = $parenthesisOpenerPointer + 1; while (true) { $pointer = TokenHelper::findNext( $phpcsFile, array_merge( [ ...self::OPERATORS, T_OPEN_PARENTHESIS, ...$complicatedOperators, ], Tokens::$comparisonTokens, ), $actualStartPointer, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'], ); if ($pointer === null) { break; } if (in_array($tokens[$pointer]['code'], $complicatedOperators, true)) { return; } if (in_array($tokens[$pointer]['code'], Tokens::$comparisonTokens, true)) { return; } if ($tokens[$pointer]['code'] === T_OPEN_PARENTHESIS) { $actualStartPointer = $tokens[$pointer]['parenthesis_closer'] + 1; continue; } $operatorsPointers[] = $pointer; $actualStartPointer = $pointer + 1; } if (count($operatorsPointers) === 0) { return; } if ( $tokens[$pointerBeforeParenthesisOpener]['code'] !== T_EQUAL || $tokens[$pointerAfterParenthesisCloser]['code'] !== T_SEMICOLON ) { $operatorsGroups = array_map( static fn (int $operatorPointer): int => self::OPERATOR_GROUPS[$tokens[$operatorPointer]['code']], $operatorsPointers, ); if (count($operatorsGroups) > 1) { return; } } $firstOperatorPointer = $operatorsPointers[0]; if (in_array($tokens[$pointerBeforeParenthesisOpener]['code'], self::OPERATORS, true)) { if (self::OPERATOR_GROUPS[$tokens[$firstOperatorPointer]['code']] !== self::OPERATOR_GROUPS[$tokens[$pointerBeforeParenthesisOpener]['code']]) { return; } if ( $tokens[$pointerBeforeParenthesisOpener]['code'] === T_MINUS && in_array($tokens[$firstOperatorPointer]['code'], [T_PLUS, T_MINUS], true) ) { return; } if ( $tokens[$pointerBeforeParenthesisOpener]['code'] === T_DIVIDE && in_array($tokens[$firstOperatorPointer]['code'], [T_DIVIDE, T_MULTIPLY], true) ) { return; } if ( $tokens[$pointerBeforeParenthesisOpener]['code'] === T_MODULUS && $tokens[$firstOperatorPointer]['code'] === T_MODULUS ) { return; } } $lastOperatorPointer = $operatorsPointers[count($operatorsPointers) - 1]; if ( in_array($tokens[$pointerAfterParenthesisCloser]['code'], self::OPERATORS, true) && self::OPERATOR_GROUPS[$tokens[$lastOperatorPointer]['code']] !== self::OPERATOR_GROUPS[$tokens[$pointerAfterParenthesisCloser]['code']] ) { return; } $fix = $phpcsFile->addFixableError('Useless parentheses.', $parenthesisOpenerPointer, self::CODE_USELESS_PARENTHESES); if (!$fix) { return; } $contentStartPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); $contentEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] - 1); $phpcsFile->fixer->beginChangeset(); FixerHelper::removeBetweenIncluding($phpcsFile, $parenthesisOpenerPointer, $contentStartPointer - 1); FixerHelper::removeBetweenIncluding($phpcsFile, $contentEndPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer']); $phpcsFile->fixer->endChangeset(); } private function checkParenthesesAroundNew(File $phpcsFile, int $parenthesisOpenerPointer): void { $tokens = $phpcsFile->getTokens(); $newPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); if ($tokens[$newPointer]['code'] !== T_NEW) { return; } $pointerAfterParenthesisCloser = TokenHelper::findNextEffective( $phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1, ); if (!in_array($tokens[$pointerAfterParenthesisCloser]['code'], [T_COMMA, T_SEMICOLON, T_CLOSE_SHORT_ARRAY], true)) { return; } $fix = $phpcsFile->addFixableError('Useless parentheses.', $parenthesisOpenerPointer, self::CODE_USELESS_PARENTHESES); if (!$fix) { return; } $contentStartPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1); $contentEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] - 1); $phpcsFile->fixer->beginChangeset(); FixerHelper::removeBetweenIncluding($phpcsFile, $parenthesisOpenerPointer, $contentStartPointer - 1); FixerHelper::removeBetweenIncluding($phpcsFile, $contentEndPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer']); $phpcsFile->fixer->endChangeset(); } }
| ver. 1.6 |
Github
|
.
| PHP 8.2.30 | ??????????? ?????????: 0 |
proxy
|
phpinfo
|
???????????