Browse Source

Merge branch '1.12'

Conflicts:
	README.rst
	Symfony/CS/Fixer/Symfony/SpacesBeforeSemicolonFixer.php
	Symfony/CS/Tests/FixerTest.php
Dariusz Ruminski 9 years ago
parent
commit
7bb4580069

+ 12 - 0
README.rst

@@ -207,6 +207,12 @@ Choose from the list of available fixers:
                         placed. Body of braces should
                         be properly indented.
 
+* **class_definition** [@PSR2, @Symfony]
+                        Whitespace around the key
+                        words of a class, trait or
+                        interfaces definition should
+                        be one space.
+
 * **concat_with_spaces**
                         Concatenation should be used
                         with at least one whitespace
@@ -327,6 +333,12 @@ Choose from the list of available fixers:
                         PHP keywords MUST be in lower
                         case.
 
+* **method_argument_default_value** [@Symfony]
+                        In method arguments there must
+                        not be arguments with default
+                        values before non-default
+                        ones.
+
 * **method_argument_space** [@PSR2, @Symfony]
                         In method arguments and method
                         call, there MUST NOT be a

+ 221 - 0
Symfony/CS/Fixer/PSR2/ClassDefinitionFixer.php

@@ -0,0 +1,221 @@
+<?php
+
+/*
+ * This file is part of the PHP CS utility.
+ *
+ * (c) Fabien Potencier <fabien@symfony.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 part of the rules defined in PSR2 ¶4.1 Extends and Implements.
+ *
+ * @author SpacePossum
+ */
+final class ClassDefinitionFixer extends AbstractFixer
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function isCandidate(Tokens $tokens)
+    {
+        return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function fix(\SplFileInfo $file, Tokens $tokens)
+    {
+        for ($index = $tokens->getSize() - 1; $index > 0; --$index) {
+            if (!$tokens[$index]->isClassy()) {
+                continue;
+            }
+
+            $this->fixClassDefinition($tokens, $index, $tokens->getNextTokenOfKind($index, array('{')));
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDescription()
+    {
+        return 'Whitespace around the key words of a class, trait or interfaces definition should be one space.';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getPriority()
+    {
+        // should be run before the TrailingSpacesFixer
+        return 21;
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $start      Class definition token start index
+     * @param int    $classyOpen Class definition token end index
+     */
+    private function fixClassDefinition(Tokens $tokens, $start, $classyOpen)
+    {
+        // check if there is a `implements` part in the definition, since there are rules for it in PSR 2.
+        $implementsInfo = $this->getMultiLineInfo($tokens, $start, $classyOpen);
+
+        // 4.1 The extends and implements keywords MUST be declared on the same line as the class name.
+        if ($implementsInfo['numberOfInterfaces'] > 1 && $implementsInfo['multiLine']) {
+            $classyOpen += $this->ensureWhiteSpaceSeparation($tokens, $start, $implementsInfo['breakAt']);
+            $this->fixMultiLineImplements($tokens, $implementsInfo['breakAt'], $classyOpen);
+        } else {
+            $classyOpen -= $tokens[$classyOpen - 1]->isWhitespace() ? 2 : 1;
+            $this->ensureWhiteSpaceSeparation($tokens, $start, $classyOpen);
+        }
+    }
+
+    /**
+     * Returns an array with `implements` data.
+     *
+     * Returns array:
+     * * int  'breakAt'            index of the Token of type T_IMPLEMENTS for the definition, or 0
+     * * int  'numberOfInterfaces'
+     * * bool 'multiLine'
+     *
+     * @param Tokens $tokens
+     * @param int    $start
+     * @param int    $classyOpen
+     *
+     * @return array
+     */
+    private function getMultiLineInfo(Tokens $tokens, $start, $classyOpen)
+    {
+        $implementsInfo = array('breakAt' => 0, 'numberOfInterfaces' => 0, 'multiLine' => false);
+        $breakAtToken = $tokens->findGivenKind($tokens[$start]->isGivenKind(T_INTERFACE) ? T_EXTENDS : T_IMPLEMENTS, $start, $classyOpen);
+        if (count($breakAtToken) < 1) {
+            return $implementsInfo;
+        }
+
+        $implementsInfo['breakAt'] = key($breakAtToken);
+        $classyOpen = $tokens->getPrevNonWhitespace($classyOpen);
+        for ($j = $implementsInfo['breakAt'] + 1; $j < $classyOpen; ++$j) {
+            if ($tokens[$j]->isGivenKind(T_STRING)) {
+                ++$implementsInfo['numberOfInterfaces'];
+                continue;
+            }
+
+            if (!$implementsInfo['multiLine'] && ($tokens[$j]->isWhitespace() || $tokens[$j]->isComment()) && false !== strpos($tokens[$j]->getContent(), "\n")) {
+                $implementsInfo['multiLine'] = true;
+            }
+        }
+
+        return $implementsInfo;
+    }
+
+    /**
+     * Fix spacing between lines following `implements`.
+     *
+     * PSR2 4.1 Lists of implements MAY be split across multiple lines, where each subsequent line is indented once.
+     * When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line.
+     *
+     * @param Tokens $tokens
+     * @param int    $breakAt
+     * @param int    $classyOpen
+     */
+    private function fixMultiLineImplements(Tokens $tokens, $breakAt, $classyOpen)
+    {
+        // implements should be followed by a line break, but we allow a comments before that,
+        // the lines after 'implements' are always build up as (comment|whitespace)*T_STRING{1}(comment|whitespace)*','
+        // after fixing it must be (whitespace indent)(comment)*T_STRING{1}(comment)*','
+        for ($index = $classyOpen - 1; $index > $breakAt - 1; --$index) {
+            if ($tokens[$index]->isWhitespace()) {
+                if ($tokens[$index + 1]->equals(',')) {
+                    $tokens[$index]->clear();
+                } elseif (
+                    $tokens[$index + 1]->isComment()
+                    && ' ' !== $tokens[$index]->getContent()
+                    && !($tokens[$index - 1]->isComment() && "\n" === $tokens[$index]->getContent()[0])
+                ) {
+                    $tokens[$index]->setContent(' ');
+                }
+            }
+
+            if ($tokens[$index]->isGivenKind(T_STRING)) {
+                $index = $this->ensureOnNewLine($tokens, $index);
+            }
+        }
+    }
+
+    /**
+     * Make sure the tokens are separated by a single space.
+     *
+     * @param Tokens $tokens
+     * @param int    $start
+     * @param int    $end
+     *
+     * @return int number tokens inserted by the method before the end token
+     */
+    private function ensureWhiteSpaceSeparation(Tokens $tokens, $start, $end)
+    {
+        $insertCount = 0;
+        for ($i = $end; $i > $start; --$i) {
+            if ($tokens[$i]->isWhitespace()) {
+                $content = $tokens[$i]->getContent();
+                if (
+                    ' ' !== $content
+                    && !($tokens[$i - 1]->isComment() && "\n" === $content[0])
+                ) {
+                    $tokens[$i]->setContent(' ');
+                }
+                continue;
+            }
+
+            if ($tokens[$i - 1]->isWhitespace() || "\n" === substr($tokens[$i - 1]->getContent(), -1)) {
+                continue;
+            }
+
+            if ($tokens[$i - 1]->isComment() || $tokens[$i]->isComment()) {
+                $tokens->insertAt($i, new Token(array(T_WHITESPACE, ' ')));
+                ++$insertCount;
+                continue;
+            }
+        }
+
+        return $insertCount;
+    }
+
+    private function ensureOnNewLine(Tokens $tokens, $index)
+    {
+        // while not whitespace and not comment go back
+        for (--$index; $index > 0; --$index) {
+            if (!$tokens[$index]->isGivenKind(array(T_NS_SEPARATOR, T_STRING))) {
+                break;
+            }
+        }
+
+        if ("\n" === substr($tokens[$index]->getContent(), -1)) {
+            return $index;
+        }
+
+        if (!$tokens[$index]->isWhitespace()) {
+            $tokens->insertAt($index + 1, new Token(array(T_WHITESPACE, "\n")));
+
+            return $index;
+        }
+
+        if (false !== strpos($tokens[$index]->getContent(), "\n")) {
+            return $index;
+        }
+
+        $tokens[$index]->setContent($tokens[$index]->getContent()."\n");
+
+        return $index;
+    }
+}

+ 250 - 0
Symfony/CS/Fixer/Symfony/MethodArgumentDefaultValueFixer.php

@@ -0,0 +1,250 @@
+<?php
+
+/*
+ * This file is part of the PHP CS utility.
+ *
+ * (c) Fabien Potencier <fabien@symfony.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\Symfony;
+
+use Symfony\CS\AbstractFixer;
+use Symfony\CS\FixerInterface;
+use Symfony\CS\Tokenizer\Tokens;
+
+/**
+ * @author Mark Scherer
+ * @author Lucas Manzke <lmanzke@outlook.com>
+ */
+final class MethodArgumentDefaultValueFixer extends AbstractFixer
+{
+    private $argumentBoundaryTokens = array('(', ',', ';', '{', '}');
+    private $variableOrTerminatorTokens = array(array(T_VARIABLE), ';', '{', '}');
+    private $argumentTerminatorTokens = array(',', ')', ';', '{');
+    private $defaultValueTokens = array('=', ';', '{');
+    private $immediateDefaultValueTokens = array('=', ',', ';', '{');
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCandidate(Tokens $tokens)
+    {
+        return $tokens->isTokenKindFound(T_FUNCTION);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDescription()
+    {
+        return 'In method arguments there must not be arguments with default values before non-default ones.';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function fix(\SplFileInfo $file, Tokens $tokens)
+    {
+        for ($i = 0, $l = $tokens->count(); $i < $l; ++$i) {
+            if ($tokens[$i]->isGivenKind(T_FUNCTION)) {
+                $this->fixFunctionDefinition($tokens, $i);
+            }
+        }
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $index
+     */
+    private function fixFunctionDefinition(Tokens $tokens, $index)
+    {
+        $examinedIndex = $tokens->getNextTokenOfKind($index, $this->argumentBoundaryTokens);
+        $lastNonDefaultArgumentIndex = $this->getLastNonDefaultArgumentIndex($tokens, $index);
+
+        while (
+            $examinedIndex < $lastNonDefaultArgumentIndex &&
+            $this->hasDefaultValueAfterIndex($tokens, $examinedIndex)
+        ) {
+            $nextRelevantIndex = $tokens->getNextTokenOfKind($examinedIndex, $this->variableOrTerminatorTokens);
+
+            if (!$tokens[$nextRelevantIndex]->isGivenKind(T_VARIABLE)) {
+                break;
+            }
+
+            if (
+                $this->isDefaultArgumentAfterIndex($tokens, $nextRelevantIndex - 1) &&
+                $nextRelevantIndex - 1 < $lastNonDefaultArgumentIndex
+            ) {
+                $this->removeDefaultArgument($tokens, $nextRelevantIndex);
+            }
+            $examinedIndex = $nextRelevantIndex;
+        }
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $index
+     *
+     * @return int|null
+     */
+    private function getLastNonDefaultArgumentIndex(Tokens $tokens, $index)
+    {
+        $nextRelevantTokenIndex = $tokens->getNextTokenOfKind($index, $this->variableOrTerminatorTokens);
+
+        if (null === $nextRelevantTokenIndex) {
+            return;
+        }
+
+        $lastNonDefaultArgumentIndex = null;
+
+        while ($tokens[$nextRelevantTokenIndex]->isGivenKind(T_VARIABLE)) {
+            if (!$tokens[$tokens->getNextMeaningfulToken($nextRelevantTokenIndex)]->equals('=') &&
+                !$this->isEllipsis($tokens, $nextRelevantTokenIndex)
+            ) {
+                $lastNonDefaultArgumentIndex = $nextRelevantTokenIndex;
+            }
+
+            $nextRelevantTokenIndex = $tokens->getNextTokenOfKind($nextRelevantTokenIndex, $this->variableOrTerminatorTokens);
+        }
+
+        return $lastNonDefaultArgumentIndex;
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $variableIndex
+     *
+     * @return bool
+     */
+    private function isEllipsis(Tokens $tokens, $variableIndex)
+    {
+        if (PHP_VERSION_ID < 50600) {
+            return $tokens[$tokens->getPrevMeaningfulToken($variableIndex)]->equals('.');
+        }
+
+        return $tokens[$tokens->getPrevMeaningfulToken($variableIndex)]->isGivenKind(T_ELLIPSIS);
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $index
+     *
+     * @return bool
+     */
+    private function hasDefaultValueAfterIndex(Tokens $tokens, $index)
+    {
+        $nextTokenIndex = $tokens->getNextTokenOfKind($index, $this->defaultValueTokens);
+        $nextToken = $tokens[$nextTokenIndex];
+
+        return $nextToken->equals('=');
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $index
+     *
+     * @return bool
+     */
+    private function isDefaultArgumentAfterIndex(Tokens $tokens, $index)
+    {
+        $nextTokenIndex = $tokens->getNextTokenOfKind($index, $this->immediateDefaultValueTokens);
+        $nextToken = $tokens[$nextTokenIndex];
+
+        return $nextToken->equals('=');
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $variableIndex
+     */
+    private function removeDefaultArgument(Tokens $tokens, $variableIndex)
+    {
+        if ($this->isTypehintedNullableVariable($tokens, $variableIndex)) {
+            return;
+        }
+
+        $argumentEndIndex = $this->findArgumentEndIndex($tokens, $variableIndex);
+        $currentIndex = $tokens->getNextMeaningfulToken($variableIndex);
+
+        while ($currentIndex < $argumentEndIndex) {
+            $tokens[$currentIndex]->clear();
+            $this->clearWhitespacesBeforeIndex($tokens, $currentIndex);
+            $currentIndex = $tokens->getNextMeaningfulToken($currentIndex);
+        }
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $variableIndex
+     *
+     * @return bool
+     */
+    private function isTypehintedNullableVariable(Tokens $tokens, $variableIndex)
+    {
+        $typehintedTokens = array(array(T_STRING), array(CT_ARRAY_TYPEHINT), ',', '(');
+        $typehintedKinds = array(T_STRING, CT_ARRAY_TYPEHINT);
+
+        if (PHP_VERSION_ID >= 50400) {
+            $typehintedTokens[] = array(T_CALLABLE);
+            $typehintedKinds[] = T_CALLABLE;
+        }
+
+        $prevMeaningfulTokenIndex = $tokens->getPrevTokenOfKind($variableIndex, $typehintedTokens);
+
+        if (!$tokens[$prevMeaningfulTokenIndex]->isGivenKind($typehintedKinds)) {
+            return false;
+        }
+
+        $nextMeaningfulTokenIndex = $tokens->getNextTokenOfKind($variableIndex, array(array(T_STRING), ',', ')'));
+        $lowerCasedNextContent = strtolower($tokens[$nextMeaningfulTokenIndex]->getContent());
+
+        return 'null' === $lowerCasedNextContent;
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $variableIndex
+     *
+     * @return int
+     */
+    private function findArgumentEndIndex(Tokens $tokens, $variableIndex)
+    {
+        $currentIndex = $variableIndex;
+        while (!$tokens[$currentIndex]->equalsAny($this->argumentTerminatorTokens)) {
+            ++$currentIndex;
+            if ($tokens[$currentIndex]->equals('(')) {
+                $currentIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $currentIndex) + 1;
+            }
+
+            if ($tokens[$currentIndex]->isGivenKind(CT_ARRAY_SQUARE_BRACE_OPEN)) {
+                $currentIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $currentIndex) + 1;
+            }
+        }
+
+        return $currentIndex;
+    }
+
+    /**
+     * @param Tokens $tokens
+     * @param int    $index
+     */
+    private function clearWhitespacesBeforeIndex(Tokens $tokens, $index)
+    {
+        $token = $tokens[$index - 1];
+
+        if ($token->isGivenKind(T_WHITESPACE)) {
+            $token->clear();
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getLevel()
+    {
+        return FixerInterface::SYMFONY_LEVEL;
+    }
+}

+ 8 - 5
Symfony/CS/Fixer/Symfony/SpacesBeforeSemicolonFixer.php

@@ -33,14 +33,17 @@ final class SpacesBeforeSemicolonFixer extends AbstractFixer
     public function fix(\SplFileInfo $file, Tokens $tokens)
     {
         foreach ($tokens as $index => $token) {
-            if (!$token->equals(';')) {
+            if (!$token->equals(';') || !$tokens[$index - 1]->isWhitespace(" \t")) {
                 continue;
             }
 
-            $previous = $tokens[$index - 1];
-
-            if ($previous->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
-                $previous->clear();
+            if ($tokens[$index - 2]->equals(';')) {
+                // do not remove all whitespace before the semicolon because it is also whitespace after another semicolon
+                if (!$tokens[$index - 1]->equals(' ')) {
+                    $tokens[$index - 1]->setContent(' ');
+                }
+            } elseif (!$tokens[$index - 2]->isComment()) {
+                $tokens[$index - 1]->clear();
             }
         }
     }

+ 2 - 0
Symfony/CS/RuleSet.php

@@ -28,6 +28,7 @@ final class RuleSet implements RuleSetInterface
         '@PSR2' => array(
             '@PSR1' => true,
             'braces' => true,
+            'class_definition' => true,
             'elseif' => true,
             'eof_ending' => true,
             'function_call_space' => true,
@@ -59,6 +60,7 @@ final class RuleSet implements RuleSetInterface
             'function_typehint_space' => true,
             'include' => true,
             'list_commas' => true,
+            'method_argument_default_value' => true,
             'method_separation' => true,
             'multiline_array_trailing_comma' => true,
             'namespace_no_leading_whitespace' => true,

+ 246 - 0
Symfony/CS/Tests/Fixer/PSR2/ClassDefinitionFixerTest.php

@@ -0,0 +1,246 @@
+<?php
+
+/*
+ * This file is part of the PHP CS utility.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace Symfony\CS\Tests\Fixer\PSR2;
+
+use Symfony\CS\Test\AbstractFixerTestCase;
+
+/**
+ * @internal
+ */
+final class ClassDefinitionFixerTest extends AbstractFixerTestCase
+{
+    /**
+     * @dataProvider provideCases
+     */
+    public function testFix($expected, $input = null)
+    {
+        $this->doTest($expected, $input);
+    }
+
+    public function provideCases()
+    {
+        $cases = array(
+            array(
+                '<?php
+class Aaa implements
+    \RFb,
+    \Fcc, '.'
+\GFddZz
+{
+}',
+                '<?php
+class Aaa implements
+    \RFb,
+    \Fcc, \GFddZz
+{
+}',
+            ),
+            array(
+                '<?php
+class Aaa implements
+    Symfony\CS\Tests\Fixer,
+\RFb,
+    \Fcc1, '.'
+\GFdd
+{
+}',
+                '<?php
+class Aaa implements
+    Symfony\CS\Tests\Fixer,\RFb,
+    \Fcc1, \GFdd
+{
+}',
+            ),
+            array(
+                '<?php
+interface Test extends /*a*/ /*b*/
+TestInterface1, /* test */
+    TestInterface2, // test
+    '.'
+
+// test
+TestInterface3, /**/     '.'
+TestInterface4,
+      TestInterface5, /**/
+TestInterface6    {}',
+                '<?php
+interface Test
+extends
+  /*a*/    /*b*/TestInterface1   ,  /* test */
+    TestInterface2   ,   // test
+    '.'
+
+// test
+TestInterface3, /**/     TestInterface4   ,
+      TestInterface5    ,     '.'
+        /**/TestInterface6    {}',
+            ),
+            array(
+                '<?php
+class Test extends TestInterface8 implements /*a*/ /*b*/
+TestInterface1, /* test */
+    TestInterface2, // test
+    '.'
+
+// test
+TestInterface3, /**/     '.'
+TestInterface4,
+      TestInterface5, /**/
+TestInterface6
+{
+}',
+                '<?php
+class Test
+extends
+    TestInterface8
+  implements  /*a*/    /*b*/TestInterface1   ,  /* test */
+    TestInterface2   ,   // test
+    '.'
+
+// test
+TestInterface3, /**/     TestInterface4   ,
+      TestInterface5    ,    '.'
+        /**/TestInterface6
+{
+}',
+            ),
+            array(
+                '<?php
+class /**/ Test123 extends /**/ \RuntimeException implements TestZ{
+}',
+                '<?php
+class/**/Test123
+extends  /**/        \RuntimeException    implements
+
+TestZ{
+}',
+            ),
+            array(
+                '<?php
+class /**/ Test125 //aaa
+extends /*
+
+*/
+//
+\Exception //
+{}',
+                '<?php
+class/**/Test125 //aaa
+extends  /*
+
+*/
+//
+\Exception        //
+{}',
+            ),
+            array(
+                '<?php
+class Test124 extends \Exception {}',
+                '<?php
+class
+Test124
+
+extends
+\Exception {}',
+            ),
+            array(
+                '<?php
+class Aaa implements Fbb, Ccc
+{
+}',
+            ),
+            array(
+                '<?php
+    class Aaa implements Ebb, Ccc
+    {
+    }',
+            ),
+            array(
+                '<?php
+class Aaa implements \Dbb, Ccc
+{
+}',
+            ),
+            array(
+                '<?php
+class Aaa implements Cbb, \Ccc
+{
+}',
+            ),
+            array(
+                '<?php
+class Aaa implements \CFb, \Ccc
+{
+}',
+            ),
+            array(
+                '<?php
+if (1) {
+    class IndentedClass
+    {
+    }
+}',
+            ),
+            array(
+                '<?php
+namespace {
+    class IndentedNameSpacedClass
+    {
+    }
+}',
+            ),
+            array(
+                '<?php
+class Aaa implements
+    \CFb,
+    \Ccc,
+    \CFdd
+{
+}', ),
+        );
+
+        return $cases;
+    }
+
+    /**
+     * @dataProvider provide54Cases
+     */
+    public function testFix54($expected, $input = null)
+    {
+        $this->doTest($expected, $input);
+    }
+
+    public function provide54Cases()
+    {
+        if (!defined('T_TRAIT')) {
+            $this->markTestSkipped('Test requires traits.');
+        }
+
+        return array(
+            array(
+            '<?php
+trait traitTest
+{}
+
+trait /**/ traitTest2 //
+/**/ {}',
+            '<?php
+trait
+   traitTest
+{}
+
+trait/**/traitTest2//
+/**/ {}',
+            ),
+        );
+    }
+}

+ 153 - 0
Symfony/CS/Tests/Fixer/Symfony/MethodArgumentDefaultValueFixerTest.php

@@ -0,0 +1,153 @@
+<?php
+
+/*
+ * This file is part of the PHP CS utility.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace Symfony\CS\Tests\Fixer\Symfony;
+
+use Symfony\CS\Test\AbstractFixerTestCase;
+
+/**
+ * @internal
+ */
+final class MethodArgumentDefaultValueFixerTest extends AbstractFixerTestCase
+{
+    /**
+     * @dataProvider provideExamplesForAllVersions
+     *
+     * @param string      $expected
+     * @param string|null $input
+     */
+    public function testFixForAllVersions($expected, $input = null)
+    {
+        $this->doTest($expected, $input);
+    }
+
+    /**
+     * @return array
+     */
+    public function provideExamplesForAllVersions()
+    {
+        return array(
+            array(
+                '<?php function bFunction($foo, $bar) {}',
+                '<?php function bFunction($foo = null, $bar) {}',
+            ),
+            array(
+                '<?php function bFunction($foo, $bar) {}',
+                '<?php function bFunction($foo = \'two words\', $bar) {}',
+            ),
+            array(
+                '<?php function cFunction($foo, $bar, $baz) {}',
+                '<?php function cFunction($foo = false, $bar = \'bar\', $baz) {}',
+            ),
+            array(
+                '<?php function dFunction($foo, $bar, $baz) {}',
+                '<?php function dFunction($foo = false, $bar, $baz) {}',
+            ),
+            array(
+                '<?php function foo (Foo $bar = null, $baz) {}',
+            ),
+            array(
+                '<?php function eFunction($foo, $bar, \SplFileInfo $baz, $x = \'default\') {}',
+                '<?php function eFunction($foo, $bar = \'removedDefault\', \SplFileInfo $baz, $x = \'default\') {}',
+            ),
+            array(
+                <<<'EOT'
+                    <?php
+                        function eFunction($foo, $bar, \SplFileInfo $baz, $x = 'default') {};
+
+                        function fFunction($foo, $bar, \SplFileInfo $baz, $x = 'default') {};
+EOT
+                ,
+                <<<'EOT'
+                    <?php
+                        function eFunction($foo, $bar, \SplFileInfo $baz, $x = 'default') {};
+
+                        function fFunction($foo, $bar = 'removedValue', \SplFileInfo $baz, $x = 'default') {};
+EOT
+            ),
+            array(
+                '<?php function foo ($bar /* a */ /* b */, $c) {}',
+                '<?php function foo ($bar /* a */ = /* b */ 1, $c) {}',
+            ),
+            array(
+                '<?php function hFunction($foo,$bar,\SplFileInfo $baz,$x = 5) {};',
+                '<?php function hFunction($foo,$bar=\'removedValue\',\SplFileInfo $baz,$x = 5) {};',
+            ),
+            array(
+                '<?php function eFunction($foo, $bar, \SplFileInfo $baz = null, $x) {}',
+                '<?php function eFunction($foo = PHP_EOL, $bar, \SplFileInfo $baz = null, $x) {}',
+            ),
+            array(
+                '<?php function eFunction($foo, $bar) {}',
+                '<?php function eFunction($foo       = null, $bar) {}',
+            ),
+            array(
+                <<<'EOT'
+                    <?php
+                        function foo(
+                            $a, // test
+                            $b, /* test */
+                            $c, // abc
+                            $d
+                        ) {}
+EOT
+            ,
+                <<<'EOT'
+                    <?php
+                        function foo(
+                            $a = 1, // test
+                            $b = 2, /* test */
+                            $c = null, // abc
+                            $d
+                        ) {}
+EOT
+            ),
+            array(
+                '<?php function foo($foo, $bar) {}',
+                '<?php function foo($foo = array(array(1)), $bar) {}',
+            ),
+            array(
+                '<?php function a($a, $b) {}',
+                '<?php function a($a = array(\'a\' => \'b\', \'c\' => \'d\'), $b) {}',
+            ),
+            array(
+                '<?php function a($a, $b) {}',
+                '<?php function a($a = [\'a\' => \'b\', \'c\' => \'d\'], $b) {}',
+            ),
+            array(
+                '<?php function a($a, $b) {}',
+                '<?php function a($a = NULL, $b) {}',
+            ),
+            array(
+                '<?php function a(\SplFileInfo $a = Null, $b) {}',
+            ),
+            array(
+                '<?php function a(array $a = null, $b) {}',
+            ),
+            array(
+                '<?php function a(callable $a = null, $b) {}',
+            ),
+            array(
+                '<?php function a(\SplFileInfo &$a = Null, $b) {}',
+            ),
+            array(
+                '<?php function a(&$a, $b) {}',
+                '<?php function a(&$a = null, $b) {}',
+            ),
+            array(
+                '<?php function a($a = 1, ...$b) {}',
+            ),
+            array(
+                '<?php function a($a = 1, \SplFileInfo ...$b) {}',
+            ),
+        );
+    }
+}

+ 4 - 0
Symfony/CS/Tests/Fixer/Symfony/SpacesBeforeSemicolonFixerTest.php

@@ -33,6 +33,10 @@ final class SpacesBeforeSemicolonFixerTest extends AbstractFixerTestCase
     public function provideCases()
     {
         return array(
+            array(
+                '<?php for ($uu = 0; ; ++$uu) {}',
+                '<?php for ($uu = 0    ;    ; ++$uu) {}',
+            ),
             array(
                 '<?php
 $this

+ 1 - 0
Symfony/CS/Tests/FixerFactoryTest.php

@@ -254,6 +254,7 @@ final class FixerFactoryTest extends \PHPUnit_Framework_TestCase
             array($fixers['short_echo_tag'], $fixers['echo_to_print']), // tested also in: echo_to_print,short_echo_tag.test
             array($fixers['short_bool_cast'], $fixers['spaces_cast']),
             array($fixers['unneeded_control_parentheses'], $fixers['trailing_spaces']), // tested also in: trailing_spaces,unneeded_control_parentheses.test
+            array($fixers['class_definition'], $fixers['trailing_spaces']),
         );
 
         // prepare bulk tests for phpdoc fixers to test that:

+ 21 - 0
Symfony/CS/Tests/Fixtures/Integration/class_definition,trailing_spaces.test

@@ -0,0 +1,21 @@
+--TEST--
+Integration of fixers: class_definition, trailing_spaces.
+--CONFIG--
+{"class_definition": true, "trailing_spaces": true}
+--INPUT--
+<?php
+class Aaa implements
+    Symfony\CS\Tests\Fixer,\RFb,
+    \Fcc1, \GFdd
+{
+}
+
+--EXPECT--
+<?php
+class Aaa implements
+    Symfony\CS\Tests\Fixer,
+\RFb,
+    \Fcc1,
+\GFdd
+{
+}

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