Browse Source

NoSpaceAroundDoubleColonFixer - introduction

SpacePossum 3 years ago
parent
commit
99f5790c85

+ 1 - 0
doc/ruleSets/PSR2.rst

@@ -22,6 +22,7 @@ Rules
   ``['on_multiline' => 'ensure_fully_multiline']``
   ``['on_multiline' => 'ensure_fully_multiline']``
 - `no_break_comment <./../rules/control_structure/no_break_comment.rst>`_
 - `no_break_comment <./../rules/control_structure/no_break_comment.rst>`_
 - `no_closing_tag <./../rules/php_tag/no_closing_tag.rst>`_
 - `no_closing_tag <./../rules/php_tag/no_closing_tag.rst>`_
+- `no_space_around_double_colon <./../rules/operator/no_space_around_double_colon.rst>`_
 - `no_spaces_after_function_name <./../rules/function_notation/no_spaces_after_function_name.rst>`_
 - `no_spaces_after_function_name <./../rules/function_notation/no_spaces_after_function_name.rst>`_
 - `no_spaces_inside_parenthesis <./../rules/whitespace/no_spaces_inside_parenthesis.rst>`_
 - `no_spaces_inside_parenthesis <./../rules/whitespace/no_spaces_inside_parenthesis.rst>`_
 - `no_trailing_whitespace <./../rules/whitespace/no_trailing_whitespace.rst>`_
 - `no_trailing_whitespace <./../rules/whitespace/no_trailing_whitespace.rst>`_

+ 2 - 0
doc/rules/index.rst

@@ -351,6 +351,8 @@ Operator
     Use ``&&`` and ``||`` logical operators instead of ``and`` and ``or``.
     Use ``&&`` and ``||`` logical operators instead of ``and`` and ``or``.
 - `new_with_braces <./operator/new_with_braces.rst>`_
 - `new_with_braces <./operator/new_with_braces.rst>`_
     All instances created with new keyword must be followed by braces.
     All instances created with new keyword must be followed by braces.
+- `no_space_around_double_colon <./operator/no_space_around_double_colon.rst>`_
+    There must be no space around double colons (also called Scope Resolution Operator or Paamayim Nekudotayim).
 - `not_operator_with_space <./operator/not_operator_with_space.rst>`_
 - `not_operator_with_space <./operator/not_operator_with_space.rst>`_
     Logical NOT operators (``!``) should have leading and trailing whitespaces.
     Logical NOT operators (``!``) should have leading and trailing whitespaces.
 - `not_operator_with_successor_space <./operator/not_operator_with_successor_space.rst>`_
 - `not_operator_with_successor_space <./operator/not_operator_with_successor_space.rst>`_

+ 37 - 0
doc/rules/operator/no_space_around_double_colon.rst

@@ -0,0 +1,37 @@
+=====================================
+Rule ``no_space_around_double_colon``
+=====================================
+
+There must be no space around double colons (also called Scope Resolution
+Operator or Paamayim Nekudotayim).
+
+Examples
+--------
+
+Example #1
+~~~~~~~~~~
+
+.. code-block:: diff
+
+   --- Original
+   +++ New
+
+   -<?php echo Foo\Bar :: class;
+   +<?php echo Foo\Bar::class;
+
+Rule sets
+---------
+
+The rule is part of the following rule sets:
+
+@PSR12
+  Using the `@PSR12 <./../../ruleSets/PSR12.rst>`_ rule set will enable the ``no_space_around_double_colon`` rule.
+
+@PSR2
+  Using the `@PSR2 <./../../ruleSets/PSR2.rst>`_ rule set will enable the ``no_space_around_double_colon`` rule.
+
+@PhpCsFixer
+  Using the `@PhpCsFixer <./../../ruleSets/PhpCsFixer.rst>`_ rule set will enable the ``no_space_around_double_colon`` rule.
+
+@Symfony
+  Using the `@Symfony <./../../ruleSets/Symfony.rst>`_ rule set will enable the ``no_space_around_double_colon`` rule.

+ 69 - 0
src/Fixer/Operator/NoSpaceAroundDoubleColonFixer.php

@@ -0,0 +1,69 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * 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 PhpCsFixer\Fixer\Operator;
+
+use PhpCsFixer\AbstractFixer;
+use PhpCsFixer\FixerDefinition\CodeSample;
+use PhpCsFixer\FixerDefinition\FixerDefinition;
+use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
+use PhpCsFixer\Tokenizer\Tokens;
+
+final class NoSpaceAroundDoubleColonFixer extends AbstractFixer
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getDefinition(): FixerDefinitionInterface
+    {
+        return new FixerDefinition(
+            'There must be no space around double colons (also called Scope Resolution Operator or Paamayim Nekudotayim).',
+            [new CodeSample("\n<?php echo Foo\\Bar :: class;\n")]
+        );
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isCandidate(Tokens $tokens): bool
+    {
+        return $tokens->isTokenKindFound(T_DOUBLE_COLON);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
+    {
+        for ($index = \count($tokens) - 2; $index > 1; --$index) {
+            if ($tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
+                $this->removeSpace($tokens, $index, 1);
+                $this->removeSpace($tokens, $index, -1);
+            }
+        }
+    }
+
+    private function removeSpace(Tokens $tokens, int $index, int $direction): void
+    {
+        if (!$tokens[$index + $direction]->isWhitespace()) {
+            return;
+        }
+
+        if ($tokens[$tokens->getNonWhitespaceSibling($index, $direction)]->isComment()) {
+            return;
+        }
+
+        $tokens->clearAt($index + $direction);
+    }
+}

+ 1 - 0
src/RuleSet/Sets/PSR2Set.php

@@ -39,6 +39,7 @@ final class PSR2Set extends AbstractRuleSetDescription
             ],
             ],
             'no_break_comment' => true,
             'no_break_comment' => true,
             'no_closing_tag' => true,
             'no_closing_tag' => true,
+            'no_space_around_double_colon' => true,
             'no_spaces_after_function_name' => true,
             'no_spaces_after_function_name' => true,
             'no_spaces_inside_parenthesis' => true,
             'no_spaces_inside_parenthesis' => true,
             'no_trailing_whitespace' => true,
             'no_trailing_whitespace' => true,

+ 122 - 0
tests/Fixer/Operator/NoSpaceAroundDoubleColonFixerTest.php

@@ -0,0 +1,122 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * 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 PhpCsFixer\Tests\Fixer\Operator;
+
+use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
+
+/**
+ * @covers \PhpCsFixer\Fixer\Operator\NoSpaceAroundDoubleColonFixer
+ *
+ * @internal
+ */
+final class NoSpaceAroundDoubleColonFixerTest extends AbstractFixerTestCase
+{
+    /**
+     * @dataProvider provideFixCases
+     */
+    public function testFix(string $expected, string $input): void
+    {
+        $this->doTest($expected, $input);
+    }
+
+    public static function provideFixCases(): \Generator
+    {
+        yield [
+            '<?php echo self::$a;',
+            '<?php echo self :: $a;',
+        ];
+
+        yield [
+            '<?php echo static::$a;',
+            '<?php echo static ::$a;',
+        ];
+
+        yield [
+            '<?php
+                echo F\B::class;
+                echo A\B::     /**/ c;
+                echo C\B/**/::c;
+            ',
+            '<?php
+                echo F\B::    class;
+                echo A\B   ::     /**/ c;
+                echo C\B/**/::   c;
+            ',
+        ];
+
+        yield [
+            '<?php
+namespace {
+    class Foo { public const a = 1; }
+
+    echo Foo::a; // Fix
+    echo "\n".Place\Bar::$a."\n"; // Fix
+}
+
+namespace Somewhere\Over\The\Rainbow {
+    class Bar {
+        public static $a = "BAR-A:: ";
+
+        public function v(?string $z = "zzz"): void
+        {
+            echo "\n".self::$a.$z; // Fix
+            echo "\n".static::class; // Fix
+            echo "\n".static # do ...
+              :: # ... not ...
+            $a.$z; // ... fix
+        }
+    }
+
+    $bar = new Bar();
+    $bar->v();
+}
+
+ # ; echo A :: B;
+// ; echo A :: B;
+/* ; echo A :: B; */
+',
+            '<?php
+namespace {
+    class Foo { public const a = 1; }
+
+    echo Foo:: a; // Fix
+    echo "\n".Place\Bar  ::   $a."\n"; // Fix
+}
+
+namespace Somewhere\Over\The\Rainbow {
+    class Bar {
+        public static $a = "BAR-A:: ";
+
+        public function v(?string $z = "zzz"): void
+        {
+            echo "\n".self  ::  $a.$z; // Fix
+            echo "\n".static  ::  class; // Fix
+            echo "\n".static # do ...
+              :: # ... not ...
+            $a.$z; // ... fix
+        }
+    }
+
+    $bar = new Bar();
+    $bar->v();
+}
+
+ # ; echo A :: B;
+// ; echo A :: B;
+/* ; echo A :: B; */
+',
+        ];
+    }
+}

+ 2 - 0
tests/RuleSet/RuleSetTest.php

@@ -198,6 +198,7 @@ final class RuleSetTest extends TestCase
                 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
                 'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
                 'no_break_comment' => true,
                 'no_break_comment' => true,
                 'no_closing_tag' => true,
                 'no_closing_tag' => true,
+                'no_space_around_double_colon' => true,
                 'no_spaces_after_function_name' => true,
                 'no_spaces_after_function_name' => true,
                 'no_spaces_inside_parenthesis' => true,
                 'no_spaces_inside_parenthesis' => true,
                 'no_trailing_whitespace' => true,
                 'no_trailing_whitespace' => true,
@@ -239,6 +240,7 @@ final class RuleSetTest extends TestCase
                 'no_break_comment' => true,
                 'no_break_comment' => true,
                 'no_closing_tag' => true,
                 'no_closing_tag' => true,
                 'no_spaces_after_function_name' => true,
                 'no_spaces_after_function_name' => true,
+                'no_space_around_double_colon' => true,
                 'no_spaces_inside_parenthesis' => true,
                 'no_spaces_inside_parenthesis' => true,
                 'no_trailing_whitespace' => true,
                 'no_trailing_whitespace' => true,
                 'no_trailing_whitespace_in_comment' => true,
                 'no_trailing_whitespace_in_comment' => true,