/** * {@inheritdoc} */ public function fix(\SplFileInfo $file, Tokens $tokens) { $tokensAnalyzer = new TokensAnalyzer($tokens); $classes = array_keys($tokens->findGivenKind(T_CLASS)); $numClasses = count($classes); for ($i = 0; $i < $numClasses; ++$i) { $index = $classes[$i]; // is it an an anonymous class definition? if ($tokensAnalyzer->isAnonymousClass($index)) { continue; } // is it inside a namespace? $nspIndex = $tokens->getPrevTokenOfKind($index, array(array(T_NAMESPACE, 'namespace'))); if (null !== $nspIndex) { $nspIndex = $tokens->getNextMeaningfulToken($nspIndex); // make sure it's not the global namespace, as PHP4 constructors are allowed in there if (!$tokens[$nspIndex]->equals('{')) { // unless it's the global namespace, the index currently points to the name $nspIndex = $tokens->getNextTokenOfKind($nspIndex, array(';', '{')); if ($tokens[$nspIndex]->equals(';')) { // the class is inside a (non-block) namespace, no PHP4-code should be in there break; } // the index points to the { of a block-namespace $nspEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nspIndex); if ($index < $nspEnd) { // the class is inside a block namespace, skip other classes that might be in it for ($j = $i + 1; $j < $numClasses; ++$j) { if ($classes[$j] < $nspEnd) { ++$i; } } // and continue checking the classes that might follow continue; } } } $classNameIndex = $tokens->getNextMeaningfulToken($index); $className = $tokens[$classNameIndex]->getContent(); $classStart = $tokens->getNextTokenOfKind($classNameIndex, array('{')); $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart); $this->fixConstructor($tokens, $className, $classStart, $classEnd); $this->fixParent($tokens, $classStart, $classEnd); } }
/** * @param Tokens $tokens * @param int $index Index of "=" * * @return bool */ private function isTypehintedNullableVariable(Tokens $tokens, $index) { $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)]; if (!$nextToken->equals(array(T_STRING, 'null'), false)) { return false; } $variableIndex = $tokens->getPrevMeaningfulToken($index); $searchTokens = array(',', '(', array(T_STRING), array(CT::T_ARRAY_TYPEHINT)); $typehintKinds = array(T_STRING, CT::T_ARRAY_TYPEHINT); if (defined('T_CALLABLE')) { $searchTokens[] = array(T_CALLABLE); $typehintKinds[] = T_CALLABLE; } $prevIndex = $tokens->getPrevTokenOfKind($variableIndex, $searchTokens); return $tokens[$prevIndex]->isGivenKind($typehintKinds); }
/** * @param Tokens $tokens * @param int $startIndex * @param int $endIndex */ private function makeClassyInheritancePartMultiLine(Tokens $tokens, $startIndex, $endIndex) { for ($i = $endIndex; $i > $startIndex; --$i) { $previousInterfaceImplementingIndex = $tokens->getPrevTokenOfKind($i, array(',', array(T_IMPLEMENTS), array(T_EXTENDS))); $breakAtIndex = $tokens->getNextMeaningfulToken($previousInterfaceImplementingIndex); // make the part of a ',' or 'implements' single line $this->makeClassyDefinitionSingleLine($tokens, $breakAtIndex, $i); // make sure the part is on its own line $isOnOwnLine = false; for ($j = $breakAtIndex; $j > $previousInterfaceImplementingIndex; --$j) { if (false !== strpos($tokens[$j]->getContent(), "\n")) { $isOnOwnLine = true; break; } } if (!$isOnOwnLine) { if ($tokens[$breakAtIndex - 1]->isWhitespace()) { $tokens[$breakAtIndex - 1]->setContent($this->whitespacesConfig->getLineEnding() . $this->whitespacesConfig->getIndent()); } else { $tokens->insertAt($breakAtIndex, new Token(array(T_WHITESPACE, $this->whitespacesConfig->getLineEnding() . $this->whitespacesConfig->getIndent()))); } } $i = $previousInterfaceImplementingIndex + 1; } }
/** * @param Tokens $tokens * @param int $index */ private function fixPropertyVisibility(Tokens $tokens, $index) { $prevIndex = $tokens->getPrevTokenOfKind($index, array(';', ',', '{')); if (null === $prevIndex || !$tokens[$prevIndex]->equals(',')) { $this->overrideAttribs($tokens, $index, $this->grabAttribsBeforePropertyToken($tokens, $index)); } }
/** * @param Tokens $tokens * @param int $index Index of the token to check * @param int $lowerLimitIndex Lower limit index. Since the token to check will always be in a conditional we must stop checking at this index * * @return bool */ private function isInConditional(Tokens $tokens, $index, $lowerLimitIndex) { $candidateIndex = $tokens->getPrevTokenOfKind($index, array(')', ';', ':')); if ($tokens[$candidateIndex]->equals(':')) { return true; } if (!$tokens[$candidateIndex]->equals(')')) { return false; // token is ';' or close tag } // token is always ')' here. // If it is part of the condition the token is always in, return false. // If it is not it is a nested condition so return true $open = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $candidateIndex, false); return $tokens->getPrevMeaningfulToken($open) > $lowerLimitIndex; }
/** * Return the first and last token index of the previous block. * * [0] First is either T_IF, T_ELSE or T_ELSEIF * [1] Last is either '}' or ';' / T_CLOSE_TAG for short notation blocks * * @param Tokens $tokens * @param int $index T_IF, T_ELSE, T_ELSEIF * * @return int[] */ private function getPreviousBlock(Tokens $tokens, $index) { $close = $previous = $tokens->getPrevMeaningfulToken($index); // short 'if' detection if ($tokens[$close]->equals('}')) { $previous = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $close, false); } $open = $tokens->getPrevTokenOfKind($previous, array(array(T_IF), array(T_ELSE), array(T_ELSEIF))); if ($tokens[$open]->isGivenKind(T_IF)) { $elseCandidate = $tokens->getPrevMeaningfulToken($open); if ($tokens[$elseCandidate]->isGivenKind(T_ELSE)) { $open = $elseCandidate; } } return array($open, $close); }
/** * @param Tokens $tokens * @param int $index * * @return string */ private function detectIndent(Tokens $tokens, $index) { while (true) { $whitespaceIndex = $tokens->getPrevTokenOfKind($index, array(array(T_WHITESPACE))); if (null === $whitespaceIndex) { return ''; } $whitespaceToken = $tokens[$whitespaceIndex]; if (false !== strpos($whitespaceToken->getContent(), "\n")) { break; } $prevToken = $tokens[$whitespaceIndex - 1]; if ($prevToken->isGivenKind(array(T_OPEN_TAG, T_COMMENT)) && "\n" === substr($prevToken->getContent(), -1)) { break; } $index = $whitespaceIndex; } $explodedContent = explode("\n", $whitespaceToken->getContent()); return end($explodedContent); }
/** * @param Tokens $tokens * @param int $index */ private function fixElement(Tokens $tokens, $index) { $tokensAnalyzer = new TokensAnalyzer($tokens); $repeatIndex = $index; while (true) { $repeatIndex = $tokens->getNextMeaningfulToken($repeatIndex); $repeatToken = $tokens[$repeatIndex]; if ($tokensAnalyzer->isArray($repeatIndex)) { if ($repeatToken->isGivenKind(T_ARRAY)) { $repeatIndex = $tokens->getNextTokenOfKind($repeatIndex, array('(')); $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $repeatIndex); } else { $repeatIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $repeatIndex); } continue; } if ($repeatToken->equals(';')) { return; // no repeating found, no fixing needed } if ($repeatToken->equals(',')) { break; } } $start = $tokens->getPrevTokenOfKind($index, array(';', '{', '}')); $this->expandElement($tokens, $tokens->getNextMeaningfulToken($start), $tokens->getNextTokenOfKind($index, array(';'))); }