Browse Source

Merge branch '1.12'

Conflicts:
	Symfony/CS/Fixer/Contrib/HeaderCommentFixer.php
	Symfony/CS/Fixer/Symfony/RemoveLinesBetweenUsesFixer.php
	Symfony/CS/Tests/Fixer/Symfony/RemoveLinesBetweenUsesFixerTest.php
	Symfony/CS/Tests/Tokenizer/TokensTest.php
	src/Fixer/Basic/BracesFixer.php
	src/Fixer/Import/NoUnusedImportsFixer.php
	src/Fixer/Import/OrderedImportsFixer.php
	src/Fixer/Import/SingleLineAfterImportsFixer.php
	src/Fixer/PhpTag/BlankLineAfterOpeningTagFixer.php
	src/Fixer/PhpTag/LinebreakAfterOpeningTagFixer.php
	tests/Fixer/Comment/HeaderCommentFixerTest.php
Dariusz Ruminski 8 years ago
parent
commit
e50d3896d4

+ 16 - 2
src/Fixer/Basic/BracesFixer.php

@@ -179,7 +179,18 @@ final class BracesFixer extends AbstractFixer
             }
             }
 
 
             // do not change indent for `while` in `do ... while ...`
             // do not change indent for `while` in `do ... while ...`
-            if ($token->isGivenKind(T_WHILE) && $tokensAnalyzer->isWhilePartOfDoWhile($index)) {
+            if (
+                $token->isGivenKind(T_WHILE)
+                && $tokensAnalyzer->isWhilePartOfDoWhile($index)
+            ) {
+                continue;
+            }
+
+            // do not change import of functions
+            if (
+                $token->isGivenKind(T_FUNCTION)
+                && $tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_USE)
+            ) {
                 continue;
                 continue;
             }
             }
 
 
@@ -294,8 +305,11 @@ final class BracesFixer extends AbstractFixer
                 $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, "\n".$indent);
                 $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, "\n".$indent);
             } elseif ($token->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index)) {
             } elseif ($token->isGivenKind(T_FUNCTION) && !$tokensAnalyzer->isLambda($index)) {
                 $closingParenthesisIndex = $tokens->getPrevTokenOfKind($startBraceIndex, array(')'));
                 $closingParenthesisIndex = $tokens->getPrevTokenOfKind($startBraceIndex, array(')'));
-                $prevToken = $tokens[$closingParenthesisIndex - 1];
+                if (null === $closingParenthesisIndex) {
+                    continue;
+                }
 
 
+                $prevToken = $tokens[$closingParenthesisIndex - 1];
                 if ($prevToken->isWhitespace() && false !== strpos($prevToken->getContent(), "\n")) {
                 if ($prevToken->isWhitespace() && false !== strpos($prevToken->getContent(), "\n")) {
                     $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
                     $tokens->ensureWhitespaceAtIndex($startBraceIndex - 1, 1, ' ');
                 } else {
                 } else {

+ 7 - 0
src/Fixer/ClassNotation/NoPhp4ConstructorFixer.php

@@ -15,6 +15,7 @@ namespace PhpCsFixer\Fixer\ClassNotation;
 use PhpCsFixer\AbstractFixer;
 use PhpCsFixer\AbstractFixer;
 use PhpCsFixer\Tokenizer\Token;
 use PhpCsFixer\Tokenizer\Token;
 use PhpCsFixer\Tokenizer\Tokens;
 use PhpCsFixer\Tokenizer\Tokens;
+use PhpCsFixer\Tokenizer\TokensAnalyzer;
 
 
 /**
 /**
  * @author Matteo Beccati <matteo@beccati.com>
  * @author Matteo Beccati <matteo@beccati.com>
@@ -42,12 +43,18 @@ final class NoPhp4ConstructorFixer extends AbstractFixer
      */
      */
     public function fix(\SplFileInfo $file, Tokens $tokens)
     public function fix(\SplFileInfo $file, Tokens $tokens)
     {
     {
+        $tokensAnalyzer = new TokensAnalyzer($tokens);
         $classes = array_keys($tokens->findGivenKind(T_CLASS));
         $classes = array_keys($tokens->findGivenKind(T_CLASS));
         $numClasses = count($classes);
         $numClasses = count($classes);
 
 
         for ($i = 0; $i < $numClasses; ++$i) {
         for ($i = 0; $i < $numClasses; ++$i) {
             $index = $classes[$i];
             $index = $classes[$i];
 
 
+            // is it an an anonymous class definition?
+            if ($tokensAnalyzer->isAnonymousClass($index)) {
+                continue;
+            }
+
             // is it inside a namespace?
             // is it inside a namespace?
             $nspIndex = $tokens->getPrevTokenOfKind($index, array(array(T_NAMESPACE, 'namespace')));
             $nspIndex = $tokens->getPrevTokenOfKind($index, array(array(T_NAMESPACE, 'namespace')));
             if (null !== $nspIndex) {
             if (null !== $nspIndex) {

+ 1 - 1
src/Fixer/Comment/HeaderCommentFixer.php

@@ -56,7 +56,7 @@ final class HeaderCommentFixer extends AbstractFixer
      */
      */
     public function fix(\SplFileInfo $file, Tokens $tokens)
     public function fix(\SplFileInfo $file, Tokens $tokens)
     {
     {
-        if (!$tokens->isMonolithicPhp()) {
+        if (!$tokens[0]->isGivenKind(T_OPEN_TAG) || !$tokens->isMonolithicPhp()) {
             return;
             return;
         }
         }
 
 

+ 5 - 1
src/Fixer/FunctionNotation/FunctionDeclarationFixer.php

@@ -47,7 +47,11 @@ final class FunctionDeclarationFixer extends AbstractFixer
                 continue;
                 continue;
             }
             }
 
 
-            $startParenthesisIndex = $tokens->getNextTokenOfKind($index, array('('));
+            $startParenthesisIndex = $tokens->getNextTokenOfKind($index, array('(', ';', array(T_CLOSE_TAG)));
+            if (!$tokens[$startParenthesisIndex]->equals('(')) {
+                continue;
+            }
+
             $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
             $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
             $startBraceIndex = $tokens->getNextTokenOfKind($endParenthesisIndex, array(';', '{'));
             $startBraceIndex = $tokens->getNextTokenOfKind($endParenthesisIndex, array(';', '{'));
 
 

+ 5 - 1
src/Fixer/FunctionNotation/FunctionTypehintSpaceFixer.php

@@ -41,7 +41,11 @@ final class FunctionTypehintSpaceFixer extends AbstractFixer
                 continue;
                 continue;
             }
             }
 
 
-            $startParenthesisIndex = $tokens->getNextTokenOfKind($index, array('('));
+            $startParenthesisIndex = $tokens->getNextTokenOfKind($index, array('(', ';', array(T_CLOSE_TAG)));
+            if (!$tokens[$startParenthesisIndex]->equals('(')) {
+                continue;
+            }
+
             $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
             $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
 
 
             for ($iter = $endParenthesisIndex - 1; $iter > $startParenthesisIndex; --$iter) {
             for ($iter = $endParenthesisIndex - 1; $iter > $startParenthesisIndex; --$iter) {

+ 39 - 22
src/Fixer/Import/NoUnusedImportsFixer.php

@@ -37,7 +37,13 @@ final class NoUnusedImportsFixer extends AbstractFixer
         $tokensAnalyzer = new TokensAnalyzer($tokens);
         $tokensAnalyzer = new TokensAnalyzer($tokens);
         $namespaceDeclarations = $this->getNamespaceDeclarations($tokens);
         $namespaceDeclarations = $this->getNamespaceDeclarations($tokens);
         $useDeclarationsIndexes = $tokensAnalyzer->getImportUseIndexes();
         $useDeclarationsIndexes = $tokensAnalyzer->getImportUseIndexes();
+
+        if (0 === count($useDeclarationsIndexes)) {
+            return;
+        }
+
         $useDeclarations = $this->getNamespaceUseDeclarations($tokens, $useDeclarationsIndexes);
         $useDeclarations = $this->getNamespaceUseDeclarations($tokens, $useDeclarationsIndexes);
+        $namespaceDeclarations = $this->getNamespaceDeclarations($tokens);
         $contentWithoutUseDeclarations = $this->generateCodeWithoutPartials($tokens, array_merge($namespaceDeclarations, $useDeclarations));
         $contentWithoutUseDeclarations = $this->generateCodeWithoutPartials($tokens, array_merge($namespaceDeclarations, $useDeclarations));
         $useUsages = $this->detectUseUsages($contentWithoutUseDeclarations, $useDeclarations);
         $useUsages = $this->detectUseUsages($contentWithoutUseDeclarations, $useDeclarations);
 
 
@@ -45,6 +51,14 @@ final class NoUnusedImportsFixer extends AbstractFixer
         $this->removeUsesInSameNamespace($tokens, $useDeclarations, $namespaceDeclarations);
         $this->removeUsesInSameNamespace($tokens, $useDeclarations, $namespaceDeclarations);
     }
     }
 
 
+    /**
+     * {@inheritdoc}
+     */
+    public function getDescription()
+    {
+        return 'Unused use statements must be removed.';
+    }
+
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}
      */
      */
@@ -70,13 +84,11 @@ final class NoUnusedImportsFixer extends AbstractFixer
     }
     }
 
 
     /**
     /**
-     * {@inheritdoc}
+     * @param string $content
+     * @param array  $useDeclarations
+     *
+     * @return array
      */
      */
-    public function getDescription()
-    {
-        return 'Unused use statements must be removed.';
-    }
-
     private function detectUseUsages($content, array $useDeclarations)
     private function detectUseUsages($content, array $useDeclarations)
     {
     {
         $usages = array();
         $usages = array();
@@ -88,6 +100,12 @@ final class NoUnusedImportsFixer extends AbstractFixer
         return $usages;
         return $usages;
     }
     }
 
 
+    /**
+     * @param Tokens $tokens
+     * @param array  $partials
+     *
+     * @return string
+     */
     private function generateCodeWithoutPartials(Tokens $tokens, array $partials)
     private function generateCodeWithoutPartials(Tokens $tokens, array $partials)
     {
     {
         $content = '';
         $content = '';
@@ -122,9 +140,9 @@ final class NoUnusedImportsFixer extends AbstractFixer
             $declarationEndIndex = $tokens->getNextTokenOfKind($index, array(';', '{'));
             $declarationEndIndex = $tokens->getNextTokenOfKind($index, array(';', '{'));
 
 
             $namespaces[] = array(
             $namespaces[] = array(
-                'end' => $declarationEndIndex,
                 'name' => trim($tokens->generatePartialCode($index + 1, $declarationEndIndex - 1)),
                 'name' => trim($tokens->generatePartialCode($index + 1, $declarationEndIndex - 1)),
                 'start' => $index,
                 'start' => $index,
+                'end' => $declarationEndIndex,
             );
             );
         }
         }
 
 
@@ -136,12 +154,12 @@ final class NoUnusedImportsFixer extends AbstractFixer
         $uses = array();
         $uses = array();
 
 
         foreach ($useIndexes as $index) {
         foreach ($useIndexes as $index) {
-            $declarationEndIndex = $tokens->getNextTokenOfKind($index, array(';'));
+            $declarationEndIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG)));
             $declarationContent = $tokens->generatePartialCode($index + 1, $declarationEndIndex - 1);
             $declarationContent = $tokens->generatePartialCode($index + 1, $declarationEndIndex - 1);
-
-            // ignore multiple use statements like: `use BarB, BarC as C, BarD;`
-            // that should be split into few separate statements
-            if (false !== strpos($declarationContent, ',')) {
+            if (
+                false !== strpos($declarationContent, ',')    // ignore multiple use statements that should be split into few separate statements (for example: `use BarB, BarC as C;`)
+                || false !== strpos($declarationContent, '{') // do not touch group use declarations until the logic of this is added (for example: `use some\a\{ClassD};`)
+            ) {
                 continue;
                 continue;
             }
             }
 
 
@@ -153,8 +171,7 @@ final class NoUnusedImportsFixer extends AbstractFixer
                 $shortName = end($declarationParts);
                 $shortName = end($declarationParts);
                 $aliased = false;
                 $aliased = false;
             } else {
             } else {
-                $fullName = $declarationParts[0];
-                $shortName = $declarationParts[1];
+                list($fullName, $shortName) = $declarationParts;
                 $declarationParts = explode('\\', $fullName);
                 $declarationParts = explode('\\', $fullName);
                 $aliased = $shortName !== end($declarationParts);
                 $aliased = $shortName !== end($declarationParts);
             }
             }
@@ -162,11 +179,11 @@ final class NoUnusedImportsFixer extends AbstractFixer
             $shortName = trim($shortName);
             $shortName = trim($shortName);
 
 
             $uses[$shortName] = array(
             $uses[$shortName] = array(
-                'aliased' => $aliased,
-                'end' => $declarationEndIndex,
                 'fullName' => trim($fullName),
                 'fullName' => trim($fullName),
                 'shortName' => $shortName,
                 'shortName' => $shortName,
+                'aliased' => $aliased,
                 'start' => $index,
                 'start' => $index,
+                'end' => $declarationEndIndex,
             );
             );
         }
         }
 
 
@@ -184,10 +201,14 @@ final class NoUnusedImportsFixer extends AbstractFixer
 
 
     private function removeUseDeclaration(Tokens $tokens, array $useDeclaration)
     private function removeUseDeclaration(Tokens $tokens, array $useDeclaration)
     {
     {
-        for ($index = $useDeclaration['start']; $index <= $useDeclaration['end']; ++$index) {
+        for ($index = $useDeclaration['start']; $index < $useDeclaration['end']; ++$index) {
             $tokens[$index]->clear();
             $tokens[$index]->clear();
         }
         }
 
 
+        if ($tokens[$useDeclaration['end']]->equals(';')) {
+            $tokens[$useDeclaration['end']]->clear();
+        }
+
         $prevToken = $tokens[$useDeclaration['start'] - 1];
         $prevToken = $tokens[$useDeclaration['start'] - 1];
 
 
         if ($prevToken->isWhitespace()) {
         if ($prevToken->isWhitespace()) {
@@ -219,12 +240,8 @@ final class NoUnusedImportsFixer extends AbstractFixer
 
 
     private function removeUsesInSameNamespace(Tokens $tokens, array $useDeclarations, array $namespaceDeclarations)
     private function removeUsesInSameNamespace(Tokens $tokens, array $useDeclarations, array $namespaceDeclarations)
     {
     {
-        if (empty($namespaceDeclarations)) {
-            return;
-        }
-
         // safeguard for files with multiple namespaces to avoid breaking them until we support this case
         // safeguard for files with multiple namespaces to avoid breaking them until we support this case
-        if (count($namespaceDeclarations) > 1) {
+        if (1 !== count($namespaceDeclarations)) {
             return;
             return;
         }
         }
 
 

+ 40 - 16
src/Fixer/Import/OrderedImportsFixer.php

@@ -19,9 +19,14 @@ use PhpCsFixer\Tokenizer\TokensAnalyzer;
 /**
 /**
  * @author Sebastiaan Stok <s.stok@rollerscapes.net>
  * @author Sebastiaan Stok <s.stok@rollerscapes.net>
  * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ * @author SpacePossum
  */
  */
 final class OrderedImportsFixer extends AbstractFixer
 final class OrderedImportsFixer extends AbstractFixer
 {
 {
+    const IMPORT_TYPE_CLASS = 1;
+    const IMPORT_TYPE_CONST = 2;
+    const IMPORT_TYPE_FUNCTION = 3;
+
     /**
     /**
      * {@inheritdoc}
      * {@inheritdoc}
      */
      */
@@ -39,25 +44,25 @@ final class OrderedImportsFixer extends AbstractFixer
         $namespacesImports = $tokensAnalyzer->getImportUseIndexes(true);
         $namespacesImports = $tokensAnalyzer->getImportUseIndexes(true);
         $usesOrder = array();
         $usesOrder = array();
 
 
-        if (!count($namespacesImports)) {
+        if (0 === count($namespacesImports)) {
             return;
             return;
         }
         }
 
 
+        $usesOrder = array();
         foreach ($namespacesImports as $uses) {
         foreach ($namespacesImports as $uses) {
-            $uses = array_reverse($uses);
-            $usesOrder = array_replace($usesOrder, $this->getNewOrder($uses, $tokens));
+            $usesOrder = array_replace($usesOrder, $this->getNewOrder(array_reverse($uses), $tokens));
         }
         }
 
 
         $usesOrder = array_reverse($usesOrder, true);
         $usesOrder = array_reverse($usesOrder, true);
         $mapStartToEnd = array();
         $mapStartToEnd = array();
 
 
         foreach ($usesOrder as $use) {
         foreach ($usesOrder as $use) {
-            $mapStartToEnd[$use[1]] = $use[2];
+            $mapStartToEnd[$use['startIndex']] = $use['endIndex'];
         }
         }
 
 
         // Now insert the new tokens, starting from the end
         // Now insert the new tokens, starting from the end
         foreach ($usesOrder as $index => $use) {
         foreach ($usesOrder as $index => $use) {
-            $declarationTokens = Tokens::fromCode('<?php use '.$use[0].';');
+            $declarationTokens = Tokens::fromCode('<?php use '.$use['namespace'].';');
             $declarationTokens->clearRange(0, 2); // clear `<?php use `
             $declarationTokens->clearRange(0, 2); // clear `<?php use `
             $declarationTokens[count($declarationTokens) - 1]->clear(); // clear `;`
             $declarationTokens[count($declarationTokens) - 1]->clear(); // clear `;`
             $declarationTokens->clearEmptyTokens();
             $declarationTokens->clearEmptyTokens();
@@ -95,14 +100,18 @@ final class OrderedImportsFixer extends AbstractFixer
      */
      */
     public static function sortingCallBack(array $first, array $second)
     public static function sortingCallBack(array $first, array $second)
     {
     {
-        $a = trim(preg_replace('%/\*(.*)\*/%s', '', $first[0]));
-        $b = trim(preg_replace('%/\*(.*)\*/%s', '', $second[0]));
+        if ($first['importType'] !== $second['importType']) {
+            return $first['importType'] > $second['importType'] ? 1 : -1;
+        }
+
+        $firstNamespace = trim(preg_replace('%/\*(.*)\*/%s', '', $first['namespace']));
+        $secondNamespace = trim(preg_replace('%/\*(.*)\*/%s', '', $second['namespace']));
 
 
         // Replace backslashes by spaces before sorting for correct sort order
         // Replace backslashes by spaces before sorting for correct sort order
-        $a = str_replace('\\', ' ', $a);
-        $b = str_replace('\\', ' ', $b);
+        $firstNamespace = str_replace('\\', ' ', $firstNamespace);
+        $secondNamespace = str_replace('\\', ' ', $secondNamespace);
 
 
-        return strcasecmp($a, $b);
+        return strcasecmp($firstNamespace, $secondNamespace);
     }
     }
 
 
     private function getNewOrder(array $uses, Tokens $tokens)
     private function getNewOrder(array $uses, Tokens $tokens)
@@ -113,8 +122,18 @@ final class OrderedImportsFixer extends AbstractFixer
         $originalIndexes = array();
         $originalIndexes = array();
 
 
         foreach ($uses as $index) {
         foreach ($uses as $index) {
-            $endIndex = $tokens->getNextTokenOfKind($index, array(';'));
             $startIndex = $tokens->getTokenNotOfKindSibling($index + 1, 1, array(array(T_WHITESPACE)));
             $startIndex = $tokens->getTokenNotOfKindSibling($index + 1, 1, array(array(T_WHITESPACE)));
+            $endIndex = $tokens->getNextTokenOfKind($startIndex, array(';', array(T_CLOSE_TAG)));
+            $previous = $tokens->getPrevMeaningfulToken($endIndex);
+
+            $group = $tokens[$previous]->equals('}');
+            if ($tokens[$startIndex]->isGivenKind(array(CT_CONST_IMPORT))) {
+                $type = self::IMPORT_TYPE_CONST;
+            } elseif ($tokens[$startIndex]->isGivenKind(array(CT_FUNCTION_IMPORT))) {
+                $type = self::IMPORT_TYPE_FUNCTION;
+            } else {
+                $type = self::IMPORT_TYPE_CLASS;
+            }
 
 
             $namespace = '';
             $namespace = '';
             $index = $startIndex;
             $index = $startIndex;
@@ -122,8 +141,14 @@ final class OrderedImportsFixer extends AbstractFixer
             while ($index <= $endIndex) {
             while ($index <= $endIndex) {
                 $token = $tokens[$index];
                 $token = $tokens[$index];
 
 
-                if ($index === $endIndex || $token->equals(',')) {
-                    $indexes[$startIndex] = array($namespace, $startIndex, $index - 1);
+                if ($index === $endIndex || (!$group && $token->equals(','))) {
+                    $indexes[$startIndex] = array(
+                        'namespace' => $namespace,
+                        'startIndex' => $startIndex,
+                        'endIndex' => $index - 1,
+                        'importType' => $type,
+                    );
+
                     $originalIndexes[] = $startIndex;
                     $originalIndexes[] = $startIndex;
 
 
                     if ($index === $endIndex) {
                     if ($index === $endIndex) {
@@ -145,13 +170,12 @@ final class OrderedImportsFixer extends AbstractFixer
 
 
         uasort($indexes, 'self::sortingCallBack');
         uasort($indexes, 'self::sortingCallBack');
 
 
-        $i = -1;
-
+        $index = -1;
         $usesOrder = array();
         $usesOrder = array();
 
 
         // Loop trough the index but use original index order
         // Loop trough the index but use original index order
         foreach ($indexes as $v) {
         foreach ($indexes as $v) {
-            $usesOrder[$originalIndexes[++$i]] = $v;
+            $usesOrder[$originalIndexes[++$index]] = $v;
         }
         }
 
 
         return $usesOrder;
         return $usesOrder;

+ 27 - 5
src/Fixer/Import/SingleImportPerStatementFixer.php

@@ -40,11 +40,23 @@ final class SingleImportPerStatementFixer extends AbstractFixer
         $uses = array_reverse($tokensAnalyzer->getImportUseIndexes());
         $uses = array_reverse($tokensAnalyzer->getImportUseIndexes());
 
 
         foreach ($uses as $index) {
         foreach ($uses as $index) {
-            $endIndex = $tokens->getNextTokenOfKind($index, array(';'));
-            $declarationContent = $tokens->generatePartialCode($index + 1, $endIndex - 1);
+            $endIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG)));
+            $previous = $tokens->getPrevMeaningfulToken($endIndex);
+            if ($tokens[$previous]->equals('}')) {
+                $start = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $previous, false);
+                $declarationContent = $tokens->generatePartialCode($start + 1, $previous - 1);
+                $prefix = '';
+                for ($i = $index + 1; $i < $start; ++$i) {
+                    $prefix .= $tokens[$i]->getContent();
+                }
+
+                $prefix = ' '.ltrim($prefix);
+            } else {
+                $declarationContent = $tokens->generatePartialCode($index + 1, $endIndex - 1);
+                $prefix = ' ';
+            }
 
 
             $declarationParts = explode(',', $declarationContent);
             $declarationParts = explode(',', $declarationContent);
-
             if (1 === count($declarationParts)) {
             if (1 === count($declarationParts)) {
                 continue;
                 continue;
             }
             }
@@ -52,15 +64,19 @@ final class SingleImportPerStatementFixer extends AbstractFixer
             $declarationContent = array();
             $declarationContent = array();
 
 
             foreach ($declarationParts as $declarationPart) {
             foreach ($declarationParts as $declarationPart) {
-                $declarationContent[] = 'use '.trim($declarationPart).';';
+                $declarationContent[] = 'use'.$prefix.trim($declarationPart).';';
             }
             }
 
 
             $declarationContent = implode("\n".$this->detectIndent($tokens, $index), $declarationContent);
             $declarationContent = implode("\n".$this->detectIndent($tokens, $index), $declarationContent);
 
 
-            for ($i = $index; $i <= $endIndex; ++$i) {
+            for ($i = $index; $i < $endIndex; ++$i) {
                 $tokens[$i]->clear();
                 $tokens[$i]->clear();
             }
             }
 
 
+            if ($tokens[$endIndex]->equals(';')) {
+                $tokens[$endIndex]->clear();
+            }
+
             $declarationTokens = Tokens::fromCode('<?php '.$declarationContent);
             $declarationTokens = Tokens::fromCode('<?php '.$declarationContent);
             $declarationTokens[0]->clear();
             $declarationTokens[0]->clear();
             $declarationTokens->clearEmptyTokens();
             $declarationTokens->clearEmptyTokens();
@@ -77,6 +93,12 @@ final class SingleImportPerStatementFixer extends AbstractFixer
         return 'There MUST be one use keyword per declaration.';
         return 'There MUST be one use keyword per declaration.';
     }
     }
 
 
+    /**
+     * @param Tokens $tokens
+     * @param int    $index
+     *
+     * @return string
+     */
     private function detectIndent(Tokens $tokens, $index)
     private function detectIndent(Tokens $tokens, $index)
     {
     {
         $prevIndex = $index - 1;
         $prevIndex = $index - 1;

+ 31 - 19
src/Fixer/Import/SingleLineAfterImportsFixer.php

@@ -51,30 +51,42 @@ final class SingleLineAfterImportsFixer extends AbstractFixer
                 $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
                 $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$index - 1]);
             }
             }
 
 
-            $newline = "\n";
+            $semicolonIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG))); // Handle insert index for inline T_COMMENT with whitespace after semicolon
+            $insertIndex = $semicolonIndex;
 
 
-            // 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;
-            }
+            if ($tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG)) {
+                if ($tokens[$insertIndex - 1]->isWhitespace()) {
+                    --$insertIndex;
+                }
 
 
-            // Increment insert index for inline T_COMMENT or T_DOC_COMMENT
-            if ($tokens[$insertIndex]->isComment()) {
-                ++$insertIndex;
+                $tokens->insertAt($insertIndex, new Token(';'));
             }
             }
 
 
-            $afterSemicolon = $tokens->getNextMeaningfulToken($semicolonIndex);
-            if (!$tokens[$afterSemicolon]->isGivenKind(T_USE)) {
-                $newline .= "\n";
-            }
+            if ($semicolonIndex === count($tokens) - 1) {
+                $tokens->insertAt($insertIndex + 1, new Token(array(T_WHITESPACE, "\n\n".$indent)));
+            } else {
+                $newline = "\n";
+                $tokens[$semicolonIndex]->isGivenKind(T_CLOSE_TAG) ? --$insertIndex : ++$insertIndex;
+                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 (null === $afterSemicolon || !$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)));
+                if ($tokens[$insertIndex]->isWhitespace()) {
+                    $nextToken = $tokens[$insertIndex];
+                    $nextToken->setContent($newline.$indent.ltrim($nextToken->getContent()));
+                } else {
+                    $tokens->insertAt($insertIndex, new Token(array(T_WHITESPACE, $newline.$indent)));
+                }
             }
             }
         }
         }
     }
     }

+ 30 - 9
src/Fixer/Operator/ConcatWithSpacesFixer.php

@@ -35,18 +35,39 @@ final class ConcatWithSpacesFixer extends AbstractFixer
     public function fix(\SplFileInfo $file, Tokens $tokens)
     public function fix(\SplFileInfo $file, Tokens $tokens)
     {
     {
         for ($index = $tokens->count() - 1; $index >= 0; --$index) {
         for ($index = $tokens->count() - 1; $index >= 0; --$index) {
-            $token = $tokens[$index];
+            if (!$tokens[$index]->equals('.')) {
+                continue;
+            }
 
 
-            if ($token->equals('.')) {
-                if (!$tokens[$index + 1]->isWhitespace()) {
-                    $tokens->insertAt($index + 1, new Token(array(T_WHITESPACE, ' ')));
-                }
+            $this->fixWhiteSpaceAroundConcatToken($tokens, $index, 1);
+            $this->fixWhiteSpaceAroundConcatToken($tokens, $index, -1);
+        }
+    }
 
 
-                if (!$tokens[$index - 1]->isWhitespace()) {
-                    $tokens->insertAt($index, new Token(array(T_WHITESPACE, ' ')));
-                }
-            }
+    /**
+     * @param Tokens $tokens
+     * @param int    $index  Index of concat token
+     * @param int    $offset 1 or -1
+     */
+    private function fixWhiteSpaceAroundConcatToken(Tokens $tokens, $index, $offset)
+    {
+        $offsetIndex = $index + $offset;
+
+        if (!$tokens[$offsetIndex]->isWhitespace()) {
+            $tokens->insertAt($index + (1 === $offset ?: 0), new Token(array(T_WHITESPACE, ' ')));
+
+            return;
+        }
+
+        if (false !== strpos($tokens[$offsetIndex]->getContent(), "\n")) {
+            return;
         }
         }
+
+        if ($tokens[$index + $offset * 2]->isComment()) {
+            return;
+        }
+
+        $tokens[$offsetIndex]->setContent(' ');
     }
     }
 
 
     /**
     /**

Some files were not shown because too many files changed in this diff