![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/friendsofphp/php-cs-fixer/src/Fixer/Alias/ |
<?php declare(strict_types=1); /* * This file is part of PHP CS Fixer. * * (c) Fabien Potencier <[email protected]> * Dariusz RumiĆski <[email protected]> * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Fixer\Alias; use PhpCsFixer\AbstractFunctionReferenceFixer; use PhpCsFixer\FixerDefinition\CodeSample; use PhpCsFixer\FixerDefinition\FixerDefinition; use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer; use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; final class PowToExponentiationFixer extends AbstractFunctionReferenceFixer { public function isCandidate(Tokens $tokens): bool { // minimal candidate to fix is seven tokens: pow(x,y); return $tokens->count() > 7 && $tokens->isTokenKindFound(T_STRING); } public function getDefinition(): FixerDefinitionInterface { return new FixerDefinition( 'Converts `pow` to the `**` operator.', [ new CodeSample( "<?php\n pow(\$a, 1);\n" ), ], null, 'Risky when the function `pow` is overridden.' ); } /** * {@inheritdoc} * * Must run before BinaryOperatorSpacesFixer, MethodArgumentSpaceFixer, NativeFunctionCasingFixer, NoSpacesAfterFunctionNameFixer, NoSpacesInsideParenthesisFixer, SpacesInsideParenthesesFixer. */ public function getPriority(): int { return 32; } protected function applyFix(\SplFileInfo $file, Tokens $tokens): void { $candidates = $this->findPowCalls($tokens); $argumentsAnalyzer = new ArgumentsAnalyzer(); $numberOfTokensAdded = 0; $previousCloseParenthesisIndex = \count($tokens); foreach (array_reverse($candidates) as $candidate) { // if in the previous iteration(s) tokens were added to the collection and this is done within the tokens // indices of the current candidate than the index of the close ')' of the candidate has moved and so // the index needs to be updated if ($previousCloseParenthesisIndex < $candidate[2]) { $previousCloseParenthesisIndex = $candidate[2]; $candidate[2] += $numberOfTokensAdded; } else { $previousCloseParenthesisIndex = $candidate[2]; $numberOfTokensAdded = 0; } $arguments = $argumentsAnalyzer->getArguments($tokens, $candidate[1], $candidate[2]); if (2 !== \count($arguments)) { continue; } for ($i = $candidate[1]; $i < $candidate[2]; ++$i) { if ($tokens[$i]->isGivenKind(T_ELLIPSIS)) { continue 2; } } $numberOfTokensAdded += $this->fixPowToExponentiation( $tokens, $candidate[0], // functionNameIndex, $candidate[1], // openParenthesisIndex, $candidate[2], // closeParenthesisIndex, $arguments ); } } /** * @return array<int[]> */ private function findPowCalls(Tokens $tokens): array { $candidates = []; // Minimal candidate to fix is seven tokens: pow(x,y); $end = \count($tokens) - 6; // First possible location is after the open token: 1 for ($i = 1; $i < $end; ++$i) { $candidate = $this->find('pow', $tokens, $i, $end); if (null === $candidate) { break; } $i = $candidate[1]; // proceed to openParenthesisIndex $candidates[] = $candidate; } return $candidates; } /** * @param array<int, int> $arguments * * @return int number of tokens added to the collection */ private function fixPowToExponentiation(Tokens $tokens, int $functionNameIndex, int $openParenthesisIndex, int $closeParenthesisIndex, array $arguments): int { // find the argument separator ',' directly after the last token of the first argument; // replace it with T_POW '**' $tokens[$tokens->getNextTokenOfKind(reset($arguments), [','])] = new Token([T_POW, '**']); // clean up the function call tokens prt. I $tokens->clearAt($closeParenthesisIndex); $previousIndex = $tokens->getPrevMeaningfulToken($closeParenthesisIndex); if ($tokens[$previousIndex]->equals(',')) { $tokens->clearAt($previousIndex); // trailing ',' in function call (PHP 7.3) } $added = 0; // check if the arguments need to be wrapped in parentheses foreach (array_reverse($arguments, true) as $argumentStartIndex => $argumentEndIndex) { if ($this->isParenthesisNeeded($tokens, $argumentStartIndex, $argumentEndIndex)) { $tokens->insertAt($argumentEndIndex + 1, new Token(')')); $tokens->insertAt($argumentStartIndex, new Token('(')); $added += 2; } } // clean up the function call tokens prt. II $tokens->clearAt($openParenthesisIndex); $tokens->clearAt($functionNameIndex); $prevMeaningfulTokenIndex = $tokens->getPrevMeaningfulToken($functionNameIndex); if ($tokens[$prevMeaningfulTokenIndex]->isGivenKind(T_NS_SEPARATOR)) { $tokens->clearAt($prevMeaningfulTokenIndex); } return $added; } private function isParenthesisNeeded(Tokens $tokens, int $argumentStartIndex, int $argumentEndIndex): bool { static $allowedKinds = null; if (null === $allowedKinds) { $allowedKinds = $this->getAllowedKinds(); } for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) { if ($tokens[$i]->isGivenKind($allowedKinds) || $tokens->isEmptyAt($i)) { continue; } $blockType = Tokens::detectBlockType($tokens[$i]); if (null !== $blockType) { $i = $tokens->findBlockEnd($blockType['type'], $i); continue; } if ($tokens[$i]->equals('$')) { $i = $tokens->getNextMeaningfulToken($i); if ($tokens[$i]->isGivenKind(CT::T_DYNAMIC_VAR_BRACE_OPEN)) { $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE, $i); continue; } } if ($tokens[$i]->equals('+') && $tokens->getPrevMeaningfulToken($i) < $argumentStartIndex) { continue; } return true; } return false; } /** * @return list<int> */ private function getAllowedKinds(): array { return [ T_DNUMBER, T_LNUMBER, T_VARIABLE, T_STRING, T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_CAST, T_INT_CAST, T_INC, T_DEC, T_NS_SEPARATOR, T_WHITESPACE, T_DOUBLE_COLON, T_LINE, T_COMMENT, T_DOC_COMMENT, CT::T_NAMESPACE_OPERATOR, ...Token::getObjectOperatorKinds(), ]; } }