/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if ($token->isGivenKind(T_USE) && $this->isUseForLambda($tokens, $index)) { $token->override(array(CT_USE_LAMBDA, $token->getContent())); } if (!$token->isClassy()) { return; } $prevTokenIndex = $tokens->getPrevMeaningfulToken($index); $prevToken = $prevTokenIndex === null ? null : $tokens[$prevTokenIndex]; if ($prevToken->isGivenKind(T_DOUBLE_COLON)) { return; } // Skip whole class braces content. // That way we can skip whole tokens in class declaration, therefore skip `T_USE` for traits. $index = $tokens->getNextTokenOfKind($index, array('{')); $innerLimit = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index); while ($index < $innerLimit) { $token = $tokens[++$index]; if (!$token->isGivenKind(T_USE)) { continue; } if ($this->isUseForLambda($tokens, $index)) { $token->override(array(CT_USE_LAMBDA, $token->getContent())); } else { $token->override(array(CT_USE_TRAIT, $token->getContent())); } } }
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 (!$this->isShortArray($tokens, $index)) { return; } $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index); $token->override(array(CT_ARRAY_SQUARE_BRACE_OPEN, '[')); $tokens[$endIndex]->override(array(CT_ARRAY_SQUARE_BRACE_CLOSE, ']')); }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->isGivenKind(array(T_CONST, T_FUNCTION))) { return; } $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)]; if ($prevToken->isGivenKind(T_USE)) { $token->override(array($token->isGivenKind(T_FUNCTION) ? CT_FUNCTION_IMPORT : CT_CONST_IMPORT, $token->getContent())); } }
/** * Cleanup a whitespace token. * * @param Token $token */ private function fixWhitespace(Token $token) { $content = $token->getContent(); // if there is more than one new line in the whitespace, then we need to fix it if (substr_count($content, "\n") > 1) { // the final bit of the whitespace must be the next statement's indentation $lines = Utils::splitLines($content); $token->setContent("\n" . end($lines)); } }
/** * {@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->equalsAny(array(array(T_CLASS, 'class'), array(T_STRING, 'class')), false)) { return; } $prevIndex = $tokens->getPrevMeaningfulToken($index); $prevToken = $tokens[$prevIndex]; if ($prevToken->isGivenKind(T_DOUBLE_COLON)) { $token->override(array(CT::T_CLASS_CONSTANT, $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())); } }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->equals('?')) { return; } $prevIndex = $tokens->getPrevMeaningfulToken($index); $prevToken = $tokens[$prevIndex]; if ($prevToken->equalsAny(array('(', ',', array(CT::T_TYPE_COLON)))) { $token->override(array(CT::T_NULLABLE_TYPE, '?')); } }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->isGivenKind(T_CLASS)) { return; } $prevIndex = $tokens->getPrevMeaningfulToken($index); $prevToken = $tokens[$prevIndex]; if ($prevToken->isGivenKind(T_DOUBLE_COLON)) { $token->override(array(CT_CLASS_CONSTANT, $token->getContent())); } }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->equals('|')) { return; } $prevIndex = $tokens->getPrevMeaningfulToken($index); $prevToken = $tokens[$prevIndex]; if (!$prevToken->isGivenKind(T_STRING)) { return; } $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex); $prevToken = $tokens[$prevIndex]; if (!$prevToken->equalsAny(array('(', array(CT::T_TYPE_ALTERNATION)))) { return; } $token->override(array(CT::T_TYPE_ALTERNATION, '|')); }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->isComment()) { return; } $content = $token->getContent(); $trimmedContent = rtrim($content); // nothing trimmed, nothing to do if ($content === $trimmedContent) { return; } $whitespaces = substr($content, strlen($trimmedContent)); $token->setContent($trimmedContent); if (isset($tokens[$index + 1]) && $tokens[$index + 1]->isWhitespace()) { $tokens[$index + 1]->setContent($whitespaces . $tokens[$index + 1]->getContent()); } else { $tokens->insertAt($index + 1, new Token(array(T_WHITESPACE, $whitespaces))); } }
/** * {@inheritdoc} */ public function process(Tokens $tokens, Token $token, $index) { if (!$token->equals(':')) { return; } $endIndex = $tokens->getPrevMeaningfulToken($index); if (!$tokens[$endIndex]->equals(')')) { return; } $startIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $endIndex, false); $prevIndex = $tokens->getPrevMeaningfulToken($startIndex); $prevToken = $tokens[$prevIndex]; // if this could be a function name we need to take one more step if ($prevToken->isGivenKind(T_STRING)) { $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex); $prevToken = $tokens[$prevIndex]; } if ($prevToken->isGivenKind(array(T_FUNCTION, CT::T_RETURN_REF, CT::T_USE_LAMBDA))) { $token->override(array(CT::T_TYPE_COLON, ':')); } }
private function fixByToken(Token $token, $index) { foreach ($this->tokenKindCallbackMap as $kind => $callback) { if (!$token->isGivenKind($kind)) { continue; } $this->{$callback}($index); return; } foreach ($this->tokenEqualsMap as $equals => $callback) { if (!$token->equals($equals)) { continue; } $this->{$callback}($index); } }
/** * Register token as found. * * @param Token|array|string $token token prototype */ private function registerFoundToken($token) { $tokenKind = $token instanceof Token ? $token->isArray() ? $token->getId() : $token->getContent() : (is_array($token) ? $token[0] : $token); $this->foundTokenKinds[$tokenKind] = true; }
private function transformIntoDynamicVarBraces(Tokens $tokens, Token $token, $index) { if (!$token->equals('$')) { return; } $openIndex = $tokens->getNextMeaningfulToken($index); if (null === $openIndex) { return; } $openToken = $tokens[$openIndex]; if (!$openToken->equals('{')) { return; } $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openIndex); $closeToken = $tokens[$closeIndex]; $openToken->override(array(CT_DYNAMIC_VAR_BRACE_OPEN, '{')); $closeToken->override(array(CT_DYNAMIC_VAR_BRACE_CLOSE, '}')); }
private function fixByToken(Token $token, $index) { foreach ($this->tokenCallbackMap as $kind => $callback) { if (!$token->isGivenKind($kind)) { continue; } $callback = $this->tokenCallbackMap[$kind]; $this->{$callback}($index); return; } }
public function provideFindSequenceExceptions() { $emptyToken = new Token('!'); $emptyToken->clear(); return array(array('Invalid sequence', array()), array('Non-meaningful token at position: 0', array(array(T_WHITESPACE, ' '))), array('Non-meaningful token at position: 1', array('{', array(T_COMMENT, '// Foo'), '}')), array('Non-meaningful token at position: 2', array('{', '!', $emptyToken, '}'))); }
/** * Removes the token if it is single line whitespace. * * @param Token $token */ private function removeWhitespaceToken(Token $token) { if ($token->isWhitespace(" \t")) { $token->clear(); } }
/** * If given token is a single line whitespace then fix it to be a single space. * * @param Token $token */ private function fixWhitespace(Token $token) { if ($token->isWhitespace(" \t")) { $token->setContent(' '); } }
public function getClearTokenAndMergeSurroundingWhitespaceCases() { $clearToken = new Token(array(null, '')); $clearToken->clear(); return array(array('<?php if($a){}else{}', array(7, 8, 9), array(new Token(array(T_OPEN_TAG, '<?php ')), new Token(array(T_IF, 'if')), new Token('('), new Token(array(T_VARIABLE, '$a')), new Token(')'), new Token('{'), new Token('}'), $clearToken, $clearToken, $clearToken)), array('<?php $a;/**/;', array(2), array(new Token(array(T_OPEN_TAG, '<?php ')), new Token(array(T_VARIABLE, '$a')), $clearToken, new Token(array(T_COMMENT, '/**/')), new Token(';'))), array('<?php ; ; ;', array(3), array(new Token(array(T_OPEN_TAG, '<?php ')), new Token(';'), new Token(array(T_WHITESPACE, ' ')), $clearToken, $clearToken, new Token(';'))), array('<?php ; ; ;', array(1, 5), array(new Token(array(T_OPEN_TAG, '<?php ')), new Token(array(T_WHITESPACE, ' ')), $clearToken, new Token(';'), new Token(array(T_WHITESPACE, ' ')), $clearToken)), array('<?php ; ; ;', array(1, 3), array(new Token(array(T_OPEN_TAG, '<?php ')), new Token(array(T_WHITESPACE, ' ')), $clearToken, $clearToken, $clearToken, new Token(';'))), array('<?php ; ; ;', array(1), array(new Token(array(T_OPEN_TAG, '<?php ')), new Token(array(T_WHITESPACE, ' ')), $clearToken, new Token(';'), new Token(array(T_WHITESPACE, ' ')), new Token(';')))); }
/** * Calculate the trailing whitespace no_tab_indentation. * * What we're doing here is grabbing everything after the final newline. * * @param Token $token * * @return string */ public static function calculateTrailingWhitespaceIndent(Token $token) { if (!$token->isWhitespace()) { throw new \InvalidArgumentException(sprintf('The given token must be whitespace, got "%s".', $token->getName())); } return ltrim(strrchr(str_replace(array("\r\n", "\r"), "\n", $token->getContent()), 10), "\n"); }
/** * Override token. * * If called on Token inside Tokens collection please use `Tokens::overrideAt` instead. * * @param Token|array|string $other token prototype */ public function override($other) { $prototype = $other instanceof self ? $other->getPrototype() : $other; if ($this->equals($prototype)) { return; } $this->changed = true; if (is_array($prototype)) { $this->isArray = true; $this->id = $prototype[0]; $this->content = $prototype[1]; return; } $this->isArray = false; $this->id = null; $this->content = $prototype; }
/** * {@inheritdoc} */ public function isCandidate(Tokens $tokens) { return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds()); }
/** * Checks variable assignments through `list()` calls for correct docblock usage. * * @param Tokens $tokens * @param Token $docsToken docs Token * @param int $listIndex index of variable Token * * @return bool */ private function isValidList(Tokens $tokens, Token $docsToken, $listIndex) { $endIndex = $tokens->getNextTokenOfKind($listIndex, array(')')); $docsContent = $docsToken->getContent(); for ($index = $listIndex + 1; $index < $endIndex; ++$index) { $token = $tokens[$index]; if ($token->isGivenKind(T_VARIABLE) && false !== strpos($docsContent, $token->getContent())) { return true; } } return false; }
/** * @dataProvider provideIsKeyCaseSensitive */ public function testIsKeyCaseSensitive($isKeyCaseSensitive, $caseSensitive, $key) { $this->assertSame($isKeyCaseSensitive, Token::isKeyCaseSensitive($caseSensitive, $key)); }
/** * Transforms the heredoc start token to nowdoc notation. * * @param Token $token */ private function convertToNowdoc(Token $token) { $token->setContent(preg_replace('/(?<=^<<<)"?(.*?)"?$/', '\'$1\'', $token->getContent())); }
private function fixWhitespace(Token $token) { if ($token->isWhitespace() && !$token->isWhitespace(" \t")) { $token->setContent(rtrim($token->getContent()) . ' '); } }
private function fixIndents(Tokens $tokens) { $classyTokens = Token::getClassyTokenKinds(); $classyAndFunctionTokens = array_merge(array(T_FUNCTION), $classyTokens); $controlTokens = $this->getControlTokens(); $indentTokens = array_filter(array_merge($classyAndFunctionTokens, $controlTokens), function ($item) { return T_SWITCH !== $item; }); $tokensAnalyzer = new TokensAnalyzer($tokens); for ($index = 0, $limit = count($tokens); $index < $limit; ++$index) { $token = $tokens[$index]; // if token is not a structure element - continue if (!$token->isGivenKind($indentTokens)) { continue; } // do not change indent for lambda functions if ($token->isGivenKind(T_FUNCTION) && $tokensAnalyzer->isLambda($index)) { continue; } // do not change indent for `while` in `do ... while ...` if ($token->isGivenKind(T_WHILE) && $tokensAnalyzer->isWhilePartOfDoWhile($index)) { continue; } if ($token->isGivenKind($classyAndFunctionTokens)) { $startBraceIndex = $tokens->getNextTokenOfKind($index, array(';', '{')); $startBraceToken = $tokens[$startBraceIndex]; } else { $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index); $startBraceIndex = $tokens->getNextNonWhitespace($parenthesisEndIndex); $startBraceToken = $tokens[$startBraceIndex]; } // structure without braces block - nothing to do, e.g. do { } while (true); if (!$startBraceToken->equals('{')) { continue; } $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startBraceIndex); $indent = $this->detectIndent($tokens, $index); // fix indent near closing brace $tokens->ensureWhitespaceAtIndex($endBraceIndex - 1, 1, "\n" . $indent); // fix indent between braces $lastCommaIndex = $tokens->getPrevTokenOfKind($endBraceIndex - 1, array(';', '}')); $nestLevel = 1; for ($nestIndex = $lastCommaIndex; $nestIndex >= $startBraceIndex; --$nestIndex) { $nestToken = $tokens[$nestIndex]; if ($nestToken->equals(')')) { $nestIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nestIndex, false); continue; } if (1 === $nestLevel && $nestToken->equalsAny(array(';', '}'))) { $nextNonWhitespaceNestIndex = $tokens->getNextNonWhitespace($nestIndex); $nextNonWhitespaceNestToken = $tokens[$nextNonWhitespaceNestIndex]; if (!$nextNonWhitespaceNestToken->isComment() && !($nestToken->equals('}') && $nextNonWhitespaceNestToken->equalsAny(array(';', ',', ']', array(CT_ARRAY_SQUARE_BRACE_CLOSE)))) && !($nestToken->equals('}') && $nextNonWhitespaceNestToken->equals('(')) && !($nestToken->equals('}') && $tokens[$nestIndex - 1]->equalsAny(array('"', "'", array(T_CONSTANT_ENCAPSED_STRING))))) { if ($nextNonWhitespaceNestToken->isGivenKind($this->getControlContinuationTokens()) || $nextNonWhitespaceNestToken->isGivenKind(T_WHILE) && $tokensAnalyzer->isWhilePartOfDoWhile($nextNonWhitespaceNestIndex)) { $whitespace = ' '; } else { $nextToken = $tokens[$nestIndex + 1]; $nextWhitespace = ''; if ($nextToken->isWhitespace()) { $nextWhitespace = rtrim($nextToken->getContent(), " \t"); if (strlen($nextWhitespace) && "\n" === $nextWhitespace[strlen($nextWhitespace) - 1]) { $nextWhitespace = substr($nextWhitespace, 0, -1); } } $whitespace = $nextWhitespace . "\n" . $indent; if (!$nextNonWhitespaceNestToken->equals('}')) { $whitespace .= ' '; } } $tokens->ensureWhitespaceAtIndex($nestIndex + 1, 0, $whitespace); } } if ($nestToken->equals('}')) { ++$nestLevel; continue; } if ($nestToken->equals('{')) { --$nestLevel; continue; } } // fix indent near opening brace if (isset($tokens[$startBraceIndex + 2]) && $tokens[$startBraceIndex + 2]->equals('}')) { $tokens->ensureWhitespaceAtIndex($startBraceIndex + 1, 0, "\n" . $indent); } elseif (!$tokens[$index]->isClassy()) { $nextToken = $tokens[$startBraceIndex + 1]; $nextNonWhitespaceToken = $tokens[$tokens->getNextNonWhitespace($startBraceIndex)]; // set indent only if it is not a case, when comment is following { in same line if (!$nextNonWhitespaceToken->isComment() || !($nextToken->isWhitespace() && $nextToken->isWhitespace(" \t")) && substr_count($nextToken->getContent(), "\n") === 1) { $tokens->ensureWhitespaceAtIndex($startBraceIndex + 1, 0, "\n" . $indent . ' '); } } else { $nextToken = $tokens[$startBraceIndex + 1]; if (!$nextToken->isWhitespace()) { $tokens->ensureWhitespaceAtIndex($startBraceIndex + 1, 0, "\n" . $indent . ' '); } else { $tmpIndent = trim($nextToken->getContent(), " \t") . $indent . ' '; if (!isset($tmpIndent[0]) || "\n" !== $tmpIndent[0]) { $tmpIndent = "\n" . $tmpIndent; } $tokens->ensureWhitespaceAtIndex($startBraceIndex + 1, 0, $tmpIndent); } } if ($token->isGivenKind($classyTokens)) { $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, "\n" . $indent); } elseif ($token->isGivenKind(T_FUNCTION)) { $closingParenthesisIndex = $tokens->getPrevTokenOfKind($startBraceIndex, array(')')); $prevToken = $tokens[$closingParenthesisIndex - 1]; if ($prevToken->isWhitespace() && false !== strpos($prevToken->getContent(), "\n")) { $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' '); } else { $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, "\n" . $indent); } } else { $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' '); } // reset loop limit due to collection change $limit = count($tokens); } }
private function transformIntoGroupUseBraces(Tokens $tokens, Token $token, $index) { if (!$token->equals('{')) { return; } $prevIndex = $tokens->getPrevMeaningfulToken($index); if (!$tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) { return; } $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index); $closeToken = $tokens[$closeIndex]; $token->override(array(CT::T_GROUP_IMPORT_BRACE_OPEN, '{')); $closeToken->override(array(CT::T_GROUP_IMPORT_BRACE_CLOSE, '}')); }