Browse Source

feature #1580 Added HeredocToNowdocFixer (gharlan)

This PR was merged into the 1.12 branch.

Discussion
----------

Added HeredocToNowdocFixer

Commits
-------

b0739ee Added HeredocToNowdocFixer
Dariusz Ruminski 9 years ago
parent
commit
a6f2bf489d

+ 1 - 1
.php_cs

@@ -1,6 +1,6 @@
 <?php
 
-$header = <<<EOF
+$header = <<<'EOF'
 This file is part of the PHP CS utility.
 
 (c) Fabien Potencier <fabien@symfony.com>

+ 4 - 0
README.rst

@@ -350,6 +350,10 @@ Choose from the list of available fixers:
                         use double slashes (//) and
                         not hash (#).
 
+* **heredoc_to_nowdoc** [symfony]
+                        Convert heredoc to nowdoc if
+                        possible.
+
 * **include** [symfony]
                         Include/Require and file path
                         should be divided with a

+ 14 - 14
Symfony/CS/Console/Command/ReadmeCommand.php

@@ -36,7 +36,7 @@ class ReadmeCommand extends Command
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $header = <<<EOF
+        $header = <<<'EOF'
 PHP Coding Standards Fixer
 ==========================
 
@@ -69,24 +69,24 @@ your system:
 
 .. code-block:: bash
 
-    \$ wget http://get.sensiolabs.org/php-cs-fixer.phar -O php-cs-fixer
+    $ wget http://get.sensiolabs.org/php-cs-fixer.phar -O php-cs-fixer
     # With a specific version
-    \$ wget http://get.sensiolabs.org/php-cs-fixer-v1.11.phar -O php-cs-fixer
+    $ wget http://get.sensiolabs.org/php-cs-fixer-v1.11.phar -O php-cs-fixer
 
 or with curl:
 
 .. code-block:: bash
 
-    \$ curl http://get.sensiolabs.org/php-cs-fixer.phar -o php-cs-fixer
+    $ curl http://get.sensiolabs.org/php-cs-fixer.phar -o php-cs-fixer
     # With a specific version
-    \$ curl http://get.sensiolabs.org/php-cs-fixer-v1.11.phar -o php-cs-fixer
+    $ curl http://get.sensiolabs.org/php-cs-fixer-v1.11.phar -o php-cs-fixer
 
 then:
 
 .. code-block:: bash
 
-    \$ sudo chmod a+x php-cs-fixer
-    \$ sudo mv php-cs-fixer /usr/local/bin/php-cs-fixer
+    $ sudo chmod a+x php-cs-fixer
+    $ sudo mv php-cs-fixer /usr/local/bin/php-cs-fixer
 
 Then, just run ``php-cs-fixer``.
 
@@ -104,7 +104,7 @@ you're good to go:
 
 .. code-block:: bash
 
-    export PATH="\$PATH:\$HOME/.composer/vendor/bin"
+    export PATH="$PATH:$HOME/.composer/vendor/bin"
 
 Globally (homebrew)
 ~~~~~~~~~~~~~~~~~~~
@@ -115,7 +115,7 @@ already have it.
 
 .. code-block:: bash
 
-    \$ brew install homebrew/php/php-cs-fixer
+    $ brew install homebrew/php/php-cs-fixer
 
 Update
 ------
@@ -127,7 +127,7 @@ The ``self-update`` command tries to update ``php-cs-fixer`` itself:
 
 .. code-block:: bash
 
-    \$ php php-cs-fixer.phar self-update
+    $ php php-cs-fixer.phar self-update
 
 Globally (manual)
 ~~~~~~~~~~~~~~~~~
@@ -136,7 +136,7 @@ You can update ``php-cs-fixer`` through this command:
 
 .. code-block:: bash
 
-    \$ sudo php-cs-fixer self-update
+    $ sudo php-cs-fixer self-update
 
 Globally (Composer)
 ~~~~~~~~~~~~~~~~~~~
@@ -145,7 +145,7 @@ You can update ``php-cs-fixer`` through this command:
 
 .. code-block:: bash
 
-    \$ ./composer.phar global update fabpot/php-cs-fixer
+    $ ./composer.phar global update fabpot/php-cs-fixer
 
 Globally (homebrew)
 ~~~~~~~~~~~~~~~~~~~
@@ -154,14 +154,14 @@ You can update ``php-cs-fixer`` through this command:
 
 .. code-block:: bash
 
-    \$ brew upgrade php-cs-fixer
+    $ brew upgrade php-cs-fixer
 
 Usage
 -----
 
 EOF;
 
-        $footer = <<<EOF
+        $footer = <<<'EOF'
 
 Helpers
 -------

+ 1 - 1
Symfony/CS/Console/Command/SelfUpdateCommand.php

@@ -32,7 +32,7 @@ class SelfUpdateCommand extends Command
             ->setName('self-update')
             ->setAliases(array('selfupdate'))
             ->setDescription('Update php-cs-fixer.phar to the latest version.')
-            ->setHelp(<<<EOT
+            ->setHelp(<<<'EOT'
 The <info>%command.name%</info> command replace your php-cs-fixer.phar by the
 latest version from cs.sensiolabs.org.
 

+ 78 - 0
Symfony/CS/Fixer/Symfony/HeredocToNowdocFixer.php

@@ -0,0 +1,78 @@
+<?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\Tokenizer\Token;
+use Symfony\CS\Tokenizer\Tokens;
+
+/**
+ * @author Gregor Harlan <gharlan@web.de>
+ */
+final class HeredocToNowdocFixer extends AbstractFixer
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function fix(\SplFileInfo $file, $content)
+    {
+        $tokens = Tokens::fromCode($content);
+
+        foreach ($tokens as $index => $token) {
+            if (!$token->isGivenKind(T_START_HEREDOC) || false !== strpos($token->getContent(), "'")) {
+                continue;
+            }
+
+            if ($tokens[$index + 1]->isGivenKind(T_END_HEREDOC)) {
+                $this->convertToNowdoc($token);
+                continue;
+            }
+
+            if (
+                !$tokens[$index + 1]->isGivenKind(T_ENCAPSED_AND_WHITESPACE) ||
+                !$tokens[$index + 2]->isGivenKind(T_END_HEREDOC)
+            ) {
+                continue;
+            }
+
+            $content = $tokens[$index + 1]->getContent();
+            // regex: odd number of backslashes, not followed by dollar
+            if (preg_match('/(?<!\\\\)(?:\\\\{2})*\\\\(?![$\\\\])/', $content)) {
+                continue;
+            }
+
+            $this->convertToNowdoc($token);
+            $content = str_replace(array('\\\\', '\\$'), array('\\', '$'), $content);
+            $tokens[$index + 1]->setContent($content);
+        }
+
+        return $tokens->generateCode();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDescription()
+    {
+        return 'Convert heredoc to nowdoc if possible.';
+    }
+
+    /**
+     * Transforms the heredoc start token to nowdoc notation.
+     *
+     * @param Token $token
+     */
+    private function convertToNowdoc(Token $token)
+    {
+        $token->setContent(preg_replace('/(?<=^<<<)"?(.*?)"?$/', '\'$1\'', $token->getContent()));
+    }
+}

+ 1 - 1
Symfony/CS/Tests/Fixer/Contrib/HeaderCommentFixerTest.php

@@ -17,7 +17,7 @@ use Symfony\CS\Tests\Fixer\AbstractFixerTestBase;
 class HeaderCommentFixerTest extends AbstractFixerTestBase
 {
     protected static $savedHeader;
-    protected static $testHeader = <<<EOH
+    protected static $testHeader = <<<'EOH'
 This file is part of the PHP CS utility.
 
 (c) Fabien Potencier <fabien@symfony.com>

+ 1 - 1
Symfony/CS/Tests/Fixer/PSR2/ParenthesisFixerTest.php

@@ -28,7 +28,7 @@ class ParenthesisFixerTest extends AbstractFixerTestBase
 
     public function testLeaveNewLinesAlone()
     {
-        $expected = <<<EOF
+        $expected = <<<'EOF'
 <?php
 
 class Foo

+ 108 - 0
Symfony/CS/Tests/Fixer/Symfony/HeredocToNowdocFixerTest.php

@@ -0,0 +1,108 @@
+<?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\Tests\Fixer\AbstractFixerTestBase;
+
+/**
+ * @author Gregor Harlan <gharlan@web.de>
+ *
+ * @internal
+ */
+final class HeredocToNowdocFixerTest extends AbstractFixerTestBase
+{
+    /**
+     * @dataProvider provideTestFixCases
+     */
+    public function testFix($expected, $input = null)
+    {
+        $this->makeTest($expected, $input);
+    }
+
+    public function provideTestFixCases()
+    {
+        return array(
+            array(<<<'EOF'
+<?php $a = <<<'TEST'
+Foo $bar \n
+TEST;
+
+EOF
+            ),
+            array(<<<'EOF'
+<?php $a = <<<'TEST'
+TEST;
+
+EOF
+            , <<<'EOF'
+<?php $a = <<<TEST
+TEST;
+
+EOF
+            ),
+            array(<<<'EOF'
+<?php $a = <<<'TEST'
+Foo \\ $bar \n
+TEST;
+
+EOF
+            , <<<'EOF'
+<?php $a = <<<TEST
+Foo \\\\ \$bar \\n
+TEST;
+
+EOF
+            ),
+            array(<<<'EOF'
+<?php $a = <<<'TEST'
+Foo
+TEST;
+
+EOF
+            , <<<'EOF'
+<?php $a = <<<"TEST"
+Foo
+TEST;
+
+EOF
+            ),
+            array(<<<'EOF'
+<?php $a = <<<TEST
+Foo $bar
+TEST;
+
+EOF
+            ),
+            array(<<<'EOF'
+<?php $a = <<<TEST
+Foo \\$bar
+TEST;
+
+EOF
+            ),
+            array(<<<'EOF'
+<?php $a = <<<TEST
+Foo \n $bar
+TEST;
+
+EOF
+            ),
+            array(<<<'EOF'
+<?php $a = <<<TEST
+Foo \x00 $bar
+TEST;
+
+EOF
+            ),
+        );
+    }
+}