/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$tokens[$index]->equals('(') || !$tokens[$tokens->getNextMeaningfulToken($index)]->equals(array(T_NEW))) { return; } $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index); if (!$tokens[$tokens->getNextMeaningfulToken($closeIndex)]->isGivenKind(array(T_OBJECT_OPERATOR, T_DOUBLE_COLON))) { return; } $tokens[$index]->override(array(CT_BRACE_CLASS_INSTANTIATION_OPEN, '(')); $tokens[$closeIndex]->override(array(CT_BRACE_CLASS_INSTANTIATION_CLOSE, ')')); }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { // Checks if specific statements are set and uses them in this case. $loops = array_intersect_key(self::$loops, array_flip($this->controlStatements)); foreach ($tokens as $index => $token) { if (!$token->equals('(')) { continue; } $blockStartIndex = $index; $index = $tokens->getPrevMeaningfulToken($index); $token = $tokens[$index]; foreach ($loops as $loop) { if (!$token->isGivenKind($loop['lookupTokens'])) { continue; } $blockEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $blockStartIndex); $blockEndNextIndex = $tokens->getNextMeaningfulToken($blockEndIndex); if (!$tokens[$blockEndNextIndex]->equalsAny($loop['neededSuccessors'])) { continue; } if ($tokens[$blockStartIndex - 1]->isWhitespace() || $tokens[$blockStartIndex - 1]->isComment()) { $this->clearParenthesis($tokens, $blockStartIndex); } else { // Adds a space to prevent broken code like `return2`. $tokens->overrideAt($blockStartIndex, array(T_WHITESPACE, ' ')); } $this->clearParenthesis($tokens, $blockEndIndex); } } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { foreach ($tokens as $index => $token) { if (!$token->isGivenKind(T_ECHO)) { continue; } $nextTokenIndex = $tokens->getNextMeaningfulToken($index); $endTokenIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG))); $canBeConverted = true; for ($i = $nextTokenIndex; $i < $endTokenIndex; ++$i) { if ($tokens[$i]->equalsAny(array('(', array(CT_ARRAY_SQUARE_BRACE_OPEN)))) { $blockType = $tokens->detectBlockType($tokens[$i]); $i = $tokens->findBlockEnd($blockType['type'], $i); } if ($tokens[$i]->equals(',')) { $canBeConverted = false; break; } } if (false === $canBeConverted) { continue; } $tokens->overrideAt($index, array(T_PRINT, 'print')); } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { foreach ($tokens as $index => $token) { if (!$token->isGivenKind(T_ECHO)) { continue; } /* * HHVM parses '<?=' as T_ECHO instead of T_OPEN_TAG_WITH_ECHO * * @see https://github.com/facebook/hhvm/issues/4809 * @see https://github.com/facebook/hhvm/issues/7161 */ if (defined('HHVM_VERSION') && 0 === strpos($token->getContent(), '<?=')) { continue; } $nextTokenIndex = $tokens->getNextMeaningfulToken($index); $endTokenIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG))); $canBeConverted = true; for ($i = $nextTokenIndex; $i < $endTokenIndex; ++$i) { if ($tokens[$i]->equalsAny(array('(', array(CT_ARRAY_SQUARE_BRACE_OPEN)))) { $blockType = Tokens::detectBlockType($tokens[$i]); $i = $tokens->findBlockEnd($blockType['type'], $i); } if ($tokens[$i]->equals(',')) { $canBeConverted = false; break; } } if (false === $canBeConverted) { continue; } $tokens->overrideAt($index, array(T_PRINT, 'print')); } }
/** * Replace all `else if` (T_ELSE T_IF) with `elseif` (T_ELSEIF). * * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { foreach ($tokens as $index => $token) { if (!$token->isGivenKind(T_ELSE)) { continue; } $ifTokenIndex = $tokens->getNextMeaningfulToken($index); $beforeIfTokenIndex = $tokens->getPrevNonWhitespace($ifTokenIndex); // if next meaning token is not T_IF - continue searching, this is not the case for fixing if (!$tokens[$ifTokenIndex]->isGivenKind(T_IF)) { continue; } // now we have T_ELSE following by T_IF so we could fix this // 1. clear whitespaces between T_ELSE and T_IF $tokens[$index + 1]->clear(); // 2. change token from T_ELSE into T_ELSEIF $tokens->overrideAt($index, array(T_ELSEIF, 'elseif')); // 3. clear succeeding T_IF $tokens[$ifTokenIndex]->clear(); // 4. clear extra whitespace after T_IF in T_COMMENT,T_WHITESPACE?,T_IF,T_WHITESPACE sequence if ($tokens[$beforeIfTokenIndex]->isComment() && $tokens[$ifTokenIndex + 1]->isWhitespace()) { $tokens[$ifTokenIndex + 1]->clear(); } } // handle `T_ELSE T_WHITESPACE T_IF` treated as single `T_ELSEIF` by HHVM // see https://github.com/facebook/hhvm/issues/4796 if (defined('HHVM_VERSION')) { foreach ($tokens->findGivenKind(T_ELSEIF) as $token) { $token->setContent('elseif'); } } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $namespace = false; $classyName = null; $classyIndex = 0; foreach ($tokens as $index => $token) { if ($token->isGivenKind(T_NAMESPACE)) { if (false !== $namespace) { return; } $namespace = true; } elseif ($token->isClassy()) { if (null !== $classyName) { return; } $classyIndex = $tokens->getNextMeaningfulToken($index); $classyName = $tokens[$classyIndex]->getContent(); } } if (null === $classyName) { return; } if (false !== $namespace) { $filename = basename(str_replace('\\', '/', $file->getRealPath()), '.php'); if ($classyName !== $filename) { $tokens[$classyIndex]->setContent($filename); } } else { $normClass = str_replace('_', '/', $classyName); $filename = substr(str_replace('\\', '/', $file->getRealPath()), -strlen($normClass) - 4, -4); if ($normClass !== $filename && strtolower($normClass) === strtolower($filename)) { $tokens[$classyIndex]->setContent(str_replace('/', '_', $filename)); } } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) { $token = $tokens[$index]; if (!$token->isGivenKind(T_DOC_COMMENT)) { continue; } if (1 === preg_match('/inheritdoc/i', $token->getContent())) { continue; } $index = $tokens->getNextMeaningfulToken($index); if (null === $index) { return; } while ($tokens[$index]->isGivenKind(array(T_ABSTRACT, T_FINAL, T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STATIC, T_VAR))) { $index = $tokens->getNextMeaningfulToken($index); } if (!$tokens[$index]->isGivenKind(T_FUNCTION)) { continue; } $openIndex = $tokens->getNextTokenOfKind($index, array('(')); $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex); $arguments = array(); foreach ($this->getArguments($tokens, $openIndex, $index) as $start => $end) { $argumentInfo = $this->prepareArgumentInformation($tokens, $start, $end); if (!$this->configuration['only_untyped'] || '' === $argumentInfo['type']) { $arguments[$argumentInfo['name']] = $argumentInfo; } } if (!count($arguments)) { continue; } $doc = new DocBlock($token->getContent()); $lastParamLine = null; foreach ($doc->getAnnotationsOfType('param') as $annotation) { $pregMatched = preg_match('/^[^$]+(\\$\\w+).*$/s', $annotation->getContent(), $matches); if (1 === $pregMatched) { unset($arguments[$matches[1]]); } $lastParamLine = max($lastParamLine, $annotation->getEnd()); } if (!count($arguments)) { continue; } $lines = $doc->getLines(); $linesCount = count($lines); preg_match('/^(\\s*).*$/', $lines[$linesCount - 1]->getContent(), $matches); $indent = $matches[1]; $newLines = array(); foreach ($arguments as $argument) { $type = $argument['type'] ?: 'mixed'; if ('?' !== $type[0] && 'null' === strtolower($argument['default'])) { $type = 'null|' . $type; } $newLines[] = new Line(sprintf('%s* @param %s %s%s', $indent, $type, $argument['name'], $this->whitespacesConfig->getLineEnding())); } array_splice($lines, $lastParamLine ? $lastParamLine + 1 : $linesCount - 1, 0, $newLines); $token->setContent(implode('', $lines)); } }
/** * Replace all `else if` (T_ELSE T_IF) with `elseif` (T_ELSEIF). * * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { foreach ($tokens as $index => $token) { if (!$token->isGivenKind(T_ELSE)) { continue; } $ifTokenIndex = $tokens->getNextMeaningfulToken($index); $beforeIfTokenIndex = $tokens->getPrevNonWhitespace($ifTokenIndex); // if next meaning token is not T_IF - continue searching, this is not the case for fixing if (!$tokens[$ifTokenIndex]->isGivenKind(T_IF)) { continue; } // now we have T_ELSE following by T_IF so we could fix this // 1. clear whitespaces between T_ELSE and T_IF $tokens[$index + 1]->clear(); // 2. change token from T_ELSE into T_ELSEIF $tokens->overrideAt($index, array(T_ELSEIF, 'elseif')); // 3. clear succeeding T_IF $tokens[$ifTokenIndex]->clear(); // 4. clear extra whitespace after T_IF in T_COMMENT,T_WHITESPACE?,T_IF,T_WHITESPACE sequence if ($tokens[$beforeIfTokenIndex]->isComment() && $tokens[$ifTokenIndex + 1]->isWhitespace()) { $tokens[$ifTokenIndex + 1]->clear(); } } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { /** @var $token \PhpCsFixer\Tokenizer\Token */ foreach ($tokens->findGivenKind(T_STRING) as $index => $token) { // skip expressions without parameters list $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)]; if (!$nextToken->equals('(')) { continue; } // skip expressions which are not function reference $prevTokenIndex = $tokens->getPrevMeaningfulToken($index); $prevToken = $tokens[$prevTokenIndex]; if ($prevToken->isGivenKind(array(T_DOUBLE_COLON, T_NEW, T_OBJECT_OPERATOR, T_FUNCTION))) { continue; } // handle function reference with namespaces if ($prevToken->isGivenKind(array(T_NS_SEPARATOR))) { $twicePrevTokenIndex = $tokens->getPrevMeaningfulToken($prevTokenIndex); $twicePrevToken = $tokens[$twicePrevTokenIndex]; if ($twicePrevToken->isGivenKind(array(T_DOUBLE_COLON, T_NEW, T_OBJECT_OPERATOR, T_FUNCTION, T_STRING, CT::T_NAMESPACE_OPERATOR))) { continue; } } // check mapping hit $tokenContent = strtolower($token->getContent()); if (!isset(self::$aliases[$tokenContent])) { continue; } $token->setContent(self::$aliases[$tokenContent]); } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { static $nativeFunctionNames = null; if (null === $nativeFunctionNames) { $nativeFunctionNames = $this->getNativeFunctionNames(); } for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) { // test if we are at a function all if (!$tokens[$index]->isGivenKind(T_STRING)) { continue; } $next = $tokens->getNextMeaningfulToken($index); if (!$tokens[$next]->equals('(')) { $index = $next; continue; } $functionNamePrefix = $tokens->getPrevMeaningfulToken($index); if ($tokens[$functionNamePrefix]->isGivenKind(array(T_DOUBLE_COLON, T_NEW, T_OBJECT_OPERATOR, T_FUNCTION))) { continue; } // do not though the function call if it is to a function in a namespace other than the default if ($tokens[$functionNamePrefix]->isGivenKind(T_NS_SEPARATOR) && $tokens[$tokens->getPrevMeaningfulToken($functionNamePrefix)]->isGivenKind(T_STRING)) { continue; } // test if the function call is to a native PHP function $lower = strtolower($tokens[$index]->getContent()); if (!array_key_exists($lower, $nativeFunctionNames)) { continue; } $tokens[$index]->setContent($nativeFunctionNames[$lower]); $index = $next; } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $functionyTokens = $this->getFunctionyTokenKinds(); $languageConstructionTokens = $this->getLanguageConstructionTokenKinds(); foreach ($tokens as $index => $token) { // looking for start brace if (!$token->equals('(')) { continue; } // last non-whitespace token $lastTokenIndex = $tokens->getPrevNonWhitespace($index); if (null === $lastTokenIndex) { continue; } // check for ternary operator $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index); $nextNonWhiteSpace = $tokens->getNextMeaningfulToken($endParenthesisIndex); if (null !== $nextNonWhiteSpace && $tokens[$nextNonWhiteSpace]->equals('?') && $tokens[$lastTokenIndex]->isGivenKind($languageConstructionTokens)) { continue; } // check if it is a function call if ($tokens[$lastTokenIndex]->isGivenKind($functionyTokens)) { $this->fixFunctionCall($tokens, $index); } elseif ($tokens[$lastTokenIndex]->isGivenKind(T_STRING)) { // for real function calls or definitions $possibleDefinitionIndex = $tokens->getPrevMeaningfulToken($lastTokenIndex); if (!$tokens[$possibleDefinitionIndex]->isGivenKind(T_FUNCTION)) { $this->fixFunctionCall($tokens, $index); } } } }
/** * Replace occurrences of the name of the classy element by "self" (if possible). * * @param Tokens $tokens * @param string $name * @param int $startIndex * @param int $endIndex */ private function replaceNameOccurrences(Tokens $tokens, $name, $startIndex, $endIndex) { $tokensAnalyzer = new TokensAnalyzer($tokens); for ($i = $startIndex; $i < $endIndex; ++$i) { $token = $tokens[$i]; // skip lambda functions (PHP < 5.4 compatibility) if ($token->isGivenKind(T_FUNCTION) && $tokensAnalyzer->isLambda($i)) { $i = $tokens->getNextTokenOfKind($i, array('{')); $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i); continue; } if (!$token->equals(array(T_STRING, $name), false)) { continue; } $prevToken = $tokens[$tokens->getPrevMeaningfulToken($i)]; $nextToken = $tokens[$tokens->getNextMeaningfulToken($i)]; // skip tokens that are part of a fully qualified name if ($prevToken->isGivenKind(T_NS_SEPARATOR) || $nextToken->isGivenKind(T_NS_SEPARATOR)) { continue; } if ($prevToken->isGivenKind(array(T_INSTANCEOF, T_NEW)) || $nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) { $token->setContent('self'); } } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $tokensAnalyzer = new TokensAnalyzer($tokens); foreach ($tokensAnalyzer->getImportUseIndexes() as $index) { $indent = ''; // if previous line ends with comment and current line starts with whitespace, use current indent if ($tokens[$index - 1]->isWhitespace(" \t") && $tokens[$index - 2]->isGivenKind(T_COMMENT)) { $indent = $tokens[$index - 1]->getContent(); } elseif ($tokens[$index - 1]->isWhitespace()) { $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]); } $newline = "\n"; // Handle insert index for inline T_COMMENT with whitespace after semicolon $semicolonIndex = $tokens->getNextTokenOfKind($index, array(';', '{')); $insertIndex = $semicolonIndex + 1; if ($tokens[$insertIndex]->isWhitespace(" \t") && $tokens[$insertIndex + 1]->isComment()) { ++$insertIndex; } // Increment insert index for inline T_COMMENT or T_DOC_COMMENT if ($tokens[$insertIndex]->isComment()) { ++$insertIndex; } $afterSemicolon = $tokens->getNextMeaningfulToken($semicolonIndex); if (!$tokens[$afterSemicolon]->isGivenKind(T_USE)) { $newline .= "\n"; } if ($tokens[$insertIndex]->isWhitespace()) { $nextToken = $tokens[$insertIndex]; $nextToken->setContent($newline . $indent . ltrim($nextToken->getContent())); } elseif ($newline && $indent) { $tokens->insertAt($insertIndex, new Token(array(T_WHITESPACE, $newline . $indent))); } } }
/** * @param Tokens $tokens * @param int $start Token index of the opening brace token of the function. * @param int $end Token index of the closing brace token of the function. */ private function fixFunction(Tokens $tokens, $start, $end) { for ($index = $end; $index > $start; --$index) { if (!$tokens[$index]->isGivenKind(T_RETURN)) { continue; } $nextAt = $tokens->getNextMeaningfulToken($index); if (!$tokens[$nextAt]->equals(';')) { continue; } if ($tokens->getNextMeaningfulToken($nextAt) !== $end) { continue; } $tokens->clearTokenAndMergeSurroundingWhitespace($index); $tokens->clearTokenAndMergeSurroundingWhitespace($nextAt); } }
private function transformIntoDestructuringSquareBrace(Tokens $tokens, Token $token, $index) { if (null === $this->cacheOfArraySquareBraceCloseIndex || !$tokens[$tokens->getNextMeaningfulToken($this->cacheOfArraySquareBraceCloseIndex)]->equals('=')) { return; } $token->override(array(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[')); $tokens[$this->cacheOfArraySquareBraceCloseIndex]->override(array(CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']')); }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->isGivenKind(T_NAMESPACE)) { return; } $nextIndex = $tokens->getNextMeaningfulToken($index); $nextToken = $tokens[$nextIndex]; if ($nextToken->isGivenKind(T_NS_SEPARATOR)) { $token->override(array(CT::T_NAMESPACE_OPERATOR, $token->getContent())); } }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->isGivenKind(T_ARRAY)) { return; } $nextIndex = $tokens->getNextMeaningfulToken($index); $nextToken = $tokens[$nextIndex]; if (!$nextToken->equals('(')) { $token->override(array(CT_ARRAY_TYPEHINT, $token->getContent())); } }
private function removeBetweenUse($index) { $next = $this->tokens->getNextTokenOfKind($index, array(';', T_CLOSE_TAG)); if (null === $next || $this->tokens[$next]->isGivenKind(T_CLOSE_TAG)) { return; } $nextUseCandidate = $this->tokens->getNextMeaningfulToken($next); if (null === $nextUseCandidate || 1 === $nextUseCandidate - $next || !$this->tokens[$nextUseCandidate]->isGivenKind($this->tokens[$index]->getId())) { return; } return $this->removeEmptyLinesAfterLineWithTokenAt($next); }
/** * Does the return statement located at a given index need fixing? * * @param Tokens $tokens * @param int $index * * @return bool */ private function needFixing(Tokens $tokens, $index) { $content = ''; while (!$tokens[$index]->equals(';')) { $index = $tokens->getNextMeaningfulToken($index); $content .= $tokens[$index]->getContent(); } $content = rtrim($content, ';'); $content = ltrim($content, '('); $content = rtrim($content, ')'); return 'null' === strtolower($content); }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $limit = $tokens->count(); for ($index = 0; $index < $limit; ++$index) { $token = $tokens[$index]; // skip T_FOR parenthesis to ignore duplicated `;` like `for ($i = 1; ; ++$i) {...}` if ($token->isGivenKind(T_FOR)) { $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($index)) + 1; continue; } if (!$token->equals(';') || !$tokens[$tokens->getPrevMeaningfulToken($index)]->equals(';')) { continue; } $tokens->removeLeadingWhitespace($index); $token->clear(); } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $end = $tokens->count() - 1; foreach (self::$functions as $map) { // the sequence is the function name, followed by "(" and a quoted string $seq = array(array(T_STRING, $map[0]), '(', array(T_CONSTANT_ENCAPSED_STRING)); $currIndex = 0; while (null !== $currIndex) { $match = $tokens->findSequence($seq, $currIndex, $end, false); // did we find a match? if (null === $match) { break; } // findSequence also returns the tokens, but we're only interested in the indexes, i.e.: // 0 => function name, // 1 => bracket "(" // 2 => quoted string passed as 1st parameter $match = array_keys($match); // advance tokenizer cursor $currIndex = $match[2]; // ensure it's a function call (not a method / static call) $prev = $tokens->getPrevMeaningfulToken($match[0]); if (null === $prev || $tokens[$prev]->isGivenKind(array(T_OBJECT_OPERATOR, T_DOUBLE_COLON))) { continue; } // ensure the first parameter is just a string (e.g. has nothing appended) $next = $tokens->getNextMeaningfulToken($match[2]); if (null === $next || !$tokens[$next]->equalsAny(array(',', ')'))) { continue; } // convert to PCRE $string = substr($tokens[$match[2]]->getContent(), 1, -1); $quote = substr($tokens[$match[2]]->getContent(), 0, 1); $delim = $this->getBestDelimiter($string); $preg = $delim . addcslashes($string, $delim) . $delim . 'D' . $map[2]; // check if the preg is valid if (!$this->checkPreg($preg)) { continue; } // modify function and argument $tokens[$match[2]]->setContent($quote . $preg . $quote); $tokens[$match[0]]->setContent($map[1]); } } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { // check if the declaration is already done $searchIndex = $tokens->getNextMeaningfulToken(0); if (null === $searchIndex) { $this->insertSequence($tokens); // declaration not found, insert one return; } $sequence = $this->getDeclareStrictTypeSequence(); $sequenceLocation = $tokens->findSequence($sequence, $searchIndex, null, false); if (null === $sequenceLocation) { $this->insertSequence($tokens); // declaration not found, insert one return; } $this->fixStrictTypesCasing($tokens, $sequenceLocation); }
private function removeBetweenUse($index) { $tokenCount = count($this->tokens); for ($i = $index; $i < $tokenCount; ++$i) { if (!$this->tokens[$i]->equals(';')) { continue; } $next = $this->tokens->getNextMeaningfulToken($i); if (!$this->tokens[$next]->isGivenKind(T_USE)) { continue; } for ($i = $next; $i > $index; --$i) { if ($this->tokens[$i]->isWhitespace() && substr_count($this->tokens[$i]->getContent(), "\n") > 1) { $this->tokens[$i]->setContent("\n"); } } break; } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { static $nextTokenKinds = null; if (null === $nextTokenKinds) { $nextTokenKinds = array('?', ';', ',', '(', ')', '[', ']', ':', '<', '>', '+', '-', '*', '/', '%', '&', '^', '|', array(T_CLASS), array(T_IS_SMALLER_OR_EQUAL), array(T_IS_GREATER_OR_EQUAL), array(T_IS_EQUAL), array(T_IS_NOT_EQUAL), array(T_IS_IDENTICAL), array(T_IS_NOT_IDENTICAL), array(T_CLOSE_TAG), array(T_LOGICAL_AND), array(T_LOGICAL_OR), array(T_LOGICAL_XOR), array(T_BOOLEAN_AND), array(T_BOOLEAN_OR), array(T_SL), array(T_SR), array(T_INSTANCEOF), array(T_AS), array(T_DOUBLE_ARROW), array(CT_ARRAY_SQUARE_BRACE_OPEN), array(CT_ARRAY_SQUARE_BRACE_CLOSE), array(CT_BRACE_CLASS_INSTANTIATION_OPEN), array(CT_BRACE_CLASS_INSTANTIATION_CLOSE)); if (defined('T_POW')) { $nextTokenKinds[] = array(T_POW); } if (defined('T_SPACESHIP')) { $nextTokenKinds[] = array(T_SPACESHIP); } } for ($index = $tokens->count() - 3; $index > 0; --$index) { $token = $tokens[$index]; if (!$token->isGivenKind(T_NEW)) { continue; } $nextIndex = $tokens->getNextTokenOfKind($index, $nextTokenKinds); $nextToken = $tokens[$nextIndex]; // new anonymous class definition if ($nextToken->isGivenKind(T_CLASS)) { if (!$tokens[$tokens->getNextMeaningfulToken($nextIndex)]->equals('(')) { $this->insertBracesAfter($tokens, $nextIndex); } continue; } // entrance into array index syntax - need to look for exit while ($nextToken->equals('[')) { $nextIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $nextIndex) + 1; $nextToken = $tokens[$nextIndex]; } // new statement has a gap in it - advance to the next token if ($nextToken->isWhitespace()) { $nextIndex = $tokens->getNextNonWhitespace($nextIndex); $nextToken = $tokens[$nextIndex]; } // new statement with () - nothing to do if ($nextToken->equals('(')) { continue; } $this->insertBracesAfter($tokens, $tokens->getPrevMeaningfulToken($nextIndex)); } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $tokensAnalyzer = new TokensAnalyzer($tokens); for ($index = $tokens->count() - 1; 0 <= $index; --$index) { $token = $tokens[$index]; if (!$token->isGivenKind(array(T_INC, T_DEC)) || !$tokensAnalyzer->isUnarySuccessorOperator($index)) { continue; } $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)]; if (!$nextToken->equalsAny(array(';', ')'))) { continue; } $startIndex = $this->findStart($tokens, $index); $prevToken = $tokens[$tokens->getPrevMeaningfulToken($startIndex)]; if ($prevToken->equalsAny(array(';', '{', '}', array(T_OPEN_TAG)))) { $tokens->insertAt($startIndex, clone $token); $token->clear(); } } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { for ($index = $tokens->count() - 1; $index >= 0; --$index) { $token = $tokens[$index]; if (!$token->isGivenKind(T_LIST)) { continue; } $openIndex = $tokens->getNextMeaningfulToken($index); $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex); $markIndex = null; $prevIndex = $tokens->getPrevNonWhitespace($closeIndex); while ($tokens[$prevIndex]->equals(',')) { $markIndex = $prevIndex; $prevIndex = $tokens->getPrevNonWhitespace($prevIndex); } if (null !== $markIndex) { $tokens->clearRange($tokens->getPrevNonWhitespace($markIndex) + 1, $closeIndex - 1); } } }
private function findIncludies(Tokens $tokens) { static $includyTokenKinds = array(T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE); $includies = array(); foreach ($tokens->findGivenKind($includyTokenKinds) as $includyTokens) { foreach ($includyTokens as $index => $token) { $includy = array('begin' => $index, 'braces' => null, 'end' => $tokens->getNextTokenOfKind($index, array(';'))); $nextTokenIndex = $tokens->getNextMeaningfulToken($index); $nextToken = $tokens[$nextTokenIndex]; if ($nextToken->equals('(')) { // Don't remove braces when the statement is wrapped. // Include is also legal as function parameter or condition statement but requires being wrapped then. $braceCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextTokenIndex); if ($tokens[$tokens->getNextMeaningfulToken($braceCloseIndex)]->equals(';')) { $includy['braces'] = array('open' => $nextTokenIndex, 'close' => $braceCloseIndex); } } $includies[] = $includy; } } return $includies; }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) { // skip T_FOR parenthesis to ignore duplicated `;` like `for ($i = 1; ; ++$i) {...}` if ($tokens[$index]->isGivenKind(T_FOR)) { $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($index)) + 1; continue; } if (!$tokens[$index]->equals(';')) { continue; } $previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($index); // A semicolon can always be removed if it follows a semicolon, '{' or opening tag. if ($tokens[$previousMeaningfulIndex]->equalsAny(array('{', ';', array(T_OPEN_TAG)))) { $tokens->clearTokenAndMergeSurroundingWhitespace($index); continue; } // A semicolon might be removed if it follows a '}' but only if the brace is part of certain structures. if ($tokens[$previousMeaningfulIndex]->equals('}')) { $this->fixSemicolonAfterCurlyBraceClose($tokens, $index, $previousMeaningfulIndex); } } }
/** * Method to trim leading/trailing whitespace within single line arrays. * * @param Tokens $tokens * @param int $index */ private static function fixArray(Tokens $tokens, $index) { $startIndex = $index; if ($tokens[$startIndex]->isGivenKind(T_ARRAY)) { $startIndex = $tokens->getNextMeaningfulToken($startIndex); $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex); } else { $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex); } $nextToken = $tokens[$startIndex + 1]; $nextNonWhitespaceIndex = $tokens->getNextNonWhitespace($startIndex); $nextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex]; $tokenAfterNextNonWhitespaceToken = $tokens[$nextNonWhitespaceIndex + 1]; $prevToken = $tokens[$endIndex - 1]; $prevNonWhitespaceIndex = $tokens->getPrevNonWhitespace($endIndex); $prevNonWhitespaceToken = $tokens[$prevNonWhitespaceIndex]; if ($nextToken->isWhitespace(" \t") && (!$nextNonWhitespaceToken->isComment() || $nextNonWhitespaceIndex === $prevNonWhitespaceIndex || $tokenAfterNextNonWhitespaceToken->isWhitespace(" \t") || '/*' === substr($nextNonWhitespaceToken->getContent(), 0, 2))) { $nextToken->clear(); } if ($prevToken->isWhitespace(" \t") && !$prevNonWhitespaceToken->equals(',')) { $prevToken->clear(); } }
/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { foreach ($tokens as $index => $token) { if (!$token->isGivenKind(T_DOC_COMMENT)) { continue; } $nextIndex = $tokens->getNextMeaningfulToken($index); // skip if there is no next token or if next token is block end `}` if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) { continue; } $prevToken = $tokens[$index - 1]; // ignore inline docblocks if ($prevToken->isGivenKind(T_OPEN_TAG) || $prevToken->isWhitespace(" \t") && !$tokens[$index - 2]->isGivenKind(T_OPEN_TAG) || $prevToken->equalsAny(array(';', '{'))) { continue; } $indent = ''; if ($tokens[$nextIndex - 1]->isWhitespace()) { $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$nextIndex - 1]); } $prevToken->setContent($this->fixWhitespaceBefore($prevToken->getContent(), $indent)); $token->setContent($this->fixDocBlock($token->getContent(), $indent)); } }