<?php /* * This file is part of PHP CS Fixer. * * (c) Fabien Potencier <fabien@symfony.com> * Dariusz Rumiński <dariusz.ruminski@gmail.com> * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace Symfony\CS\Fixer\PSR2; use Symfony\CS\AbstractFixer; use Symfony\CS\Tokenizer\Token; use Symfony\CS\Tokenizer\Tokens; /** * Fixer for rules defined in PSR2 ¶3. * * @author Dariusz Rumiński <dariusz.ruminski@gmail.com> * @author SpacePossum */ class MultipleUseFixer extends AbstractFixer { /** * {@inheritdoc} */ public function fix(\SplFileInfo $file, $content) { $tokens = Tokens::fromCode($content); $uses = array_reverse($tokens->getImportUseIndexes()); foreach ($uses as $index) { $endIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG))); $groupClose = $tokens->getPrevMeaningfulToken($endIndex); $tokens[$groupClose]->equals('}') ? $this->fixGroupUse($tokens, $index, $endIndex) : $this->fixMultipleUse($tokens, $index, $endIndex) ; } return $tokens->generateCode(); } /** * {@inheritdoc} */ public function getDescription() { return 'There MUST be one use keyword per declaration.'; } public function getPriority() { // must be run before UnusedUseFixer, OrderedUseFixer, SpacesBeforeSemicolonFixer, SpacesAfterSemicolonFixer and MultilineSpacesBeforeSemicolonFixer return 1; } /** * @param Tokens $tokens * @param int $index * * @return string */ private function detectIndent(Tokens $tokens, $index) { if (!$tokens[$index - 1]->isWhitespace()) { return ''; // cannot detect indent } $explodedContent = explode("\n", $tokens[$index - 1]->getContent()); return end($explodedContent); } /** * @param Tokens $tokens * @param int $index * * @return array */ private function getGroupDeclaration(Tokens $tokens, $index) { $groupPrefix = 'use'; $comment = ''; for ($i = $index + 1; ; ++$i) { if ($tokens[$i]->equals('{')) { $groupOpenIndex = $i; break; } if ($tokens[$i]->isComment()) { $comment .= $tokens[$i]->getContent(); if (!$tokens[$i - 1]->isWhitespace() && !$tokens[$i + 1]->isWhitespace()) { $groupPrefix .= ' '; } continue; } if ($tokens[$i]->isWhitespace()) { $groupPrefix .= ' '; continue; } $groupPrefix .= $tokens[$i]->getContent(); } return array( $groupPrefix, $groupOpenIndex, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $groupOpenIndex), $comment, ); } /** * @param Tokens $tokens * @param string $groupPrefix * @param int $groupOpenIndex * @param int $groupCloseIndex * @param string $comment * * @return string[] */ private function getGroupStatements(Tokens $tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment) { $statements = array(); $statement = $groupPrefix; for ($i = $groupOpenIndex + 1; $i <= $groupCloseIndex; ++$i) { if ($tokens[$i]->equalsAny(array(',', '}'))) { $statements[] = $statement.';'; $statement = $groupPrefix; continue; } if ($tokens[$i]->isWhitespace()) { $j = $tokens->getNextMeaningfulToken($i); if ($tokens[$j]->equals(array(T_AS))) { $statement .= ' as '; $i += 2; } continue; } $statement .= $tokens[$i]->getContent(); } if ('' !== $comment) { $statements[0] .= ' '.$comment; } return $statements; } private function fixGroupUse(Tokens $tokens, $index, $endIndex) { list($groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment) = $this->getGroupDeclaration($tokens, $index); $statements = $this->getGroupStatements($tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment); if (count($statements) < 2) { return; } $tokens->clearRange($index, $groupCloseIndex); if ($tokens[$endIndex]->equals(';')) { $tokens[$endIndex]->clear(); } $importTokens = Tokens::fromCode('<?php '.implode("\n", $statements)); $importTokens[0]->clear(); $tokens->insertAt($index, $importTokens); } private function fixMultipleUse(Tokens $tokens, $index, $endIndex) { for ($i = $endIndex - 1; $i > $index; --$i) { if (!$tokens[$i]->equals(',')) { continue; } $tokens[$i]->setContent(';'); $i = $tokens->getNextMeaningfulToken($i); $tokens->insertAt($i, new Token(array(T_USE, 'use'))); $tokens->insertAt($i + 1, new Token(array(T_WHITESPACE, ' '))); $indent = $this->detectIndent($tokens, $index); if ($tokens[$i - 1]->isWhitespace()) { $tokens[$i - 1]->setContent("\n".$indent); continue; } if (false === strpos($tokens[$i - 1]->getContent(), "\n")) { $tokens->insertAt($i, new Token(array(T_WHITESPACE, "\n".$indent))); } } } }