Просмотр исходного кода

feature: `BlankLineBeforeStatementFixer` - skip enum cases (#7203)

John Paul E. Balandan, CPA 1 год назад
Родитель
Сommit
4f0e839371

+ 4 - 0
src/Fixer/Whitespace/BlankLineBeforeStatementFixer.php

@@ -266,6 +266,10 @@ function getValues() {
                 continue;
             }
 
+            if ($token->isGivenKind(T_CASE) && $analyzer->isEnumCase($index)) {
+                continue;
+            }
+
             $insertBlankLineIndex = $this->getInsertBlankLineIndex($tokens, $index);
             $prevNonWhitespace = $tokens->getPrevNonWhitespace($insertBlankLineIndex);
 

+ 25 - 0
src/Tokenizer/TokensAnalyzer.php

@@ -633,6 +633,31 @@ final class TokensAnalyzer
         return $tokens[$beforeStartIndex]->isGivenKind(T_DO);
     }
 
+    /**
+     * @throws \LogicException when provided index does not point to token containing T_CASE
+     */
+    public function isEnumCase(int $caseIndex): bool
+    {
+        $tokens = $this->tokens;
+        $token = $tokens[$caseIndex];
+
+        if (!$token->isGivenKind(T_CASE)) {
+            throw new \LogicException(sprintf(
+                'No T_CASE given at index %d, got %s instead.',
+                $caseIndex,
+                $token->getName() ?? $token->getContent()
+            ));
+        }
+
+        if (!\defined('T_ENUM') || !$tokens->isTokenKindFound(T_ENUM)) {
+            return false;
+        }
+
+        $prevIndex = $tokens->getPrevTokenOfKind($caseIndex, [[T_ENUM], [T_SWITCH]]);
+
+        return null !== $prevIndex && $tokens[$prevIndex]->isGivenKind(T_ENUM);
+    }
+
     public function isSuperGlobal(int $index): bool
     {
         static $superNames = [

+ 0 - 3
tests/Fixer/Whitespace/BlankLineBeforeStatementFixerTest.php

@@ -1515,9 +1515,7 @@ do {
             '<?php
 enum Suit {
     case Hearts;
-
     case Diamonds;
-
     case Clubs;
 
 
@@ -1526,7 +1524,6 @@ enum Suit {
 
 enum UserStatus: string {
     case Pending = "P";
-
     case Active = "A";
 
     public function label(): string {

+ 139 - 0
tests/Tokenizer/TokensAnalyzerTest.php

@@ -2317,6 +2317,145 @@ class TestClass {
         }
     }
 
+    /**
+     * @dataProvider provideIsEnumCaseCases
+     *
+     * @param array<int, bool> $expected
+     *
+     * @requires PHP 8.1
+     */
+    public function testIsEnumCase(string $source, array $expected): void
+    {
+        $tokens = Tokens::fromCode($source);
+        $tokensAnalyzer = new TokensAnalyzer($tokens);
+
+        foreach ($tokens as $index => $token) {
+            if (!$token->isGivenKind(T_CASE)) {
+                try {
+                    $tokensAnalyzer->isEnumCase($index);
+                    self::fail('TokensAnalyzer::isEnumCase() did not throw LogicException.');
+                } catch (\Throwable $e) {
+                    self::assertInstanceOf(\LogicException::class, $e);
+                    self::assertMatchesRegularExpression('/^No T_CASE given at index \d+, got \S+ instead\.$/', $e->getMessage());
+                }
+
+                continue;
+            }
+
+            self::assertSame($expected[$index], $tokensAnalyzer->isEnumCase($index));
+        }
+    }
+
+    public static function provideIsEnumCaseCases(): iterable
+    {
+        yield 'switch only' => [
+            '<?php
+function bar(string $a): string
+{
+    switch ($a) {
+        case \'one\':
+            return $a;
+        case \'two\':
+        default:
+            return strtoupper($a);
+    }
+}
+',
+            [
+                23 => false,
+                33 => false,
+            ],
+        ];
+
+        yield 'pure enum' => [
+            '<?php
+enum Foo
+{
+    case One;
+    case Two;
+}
+',
+            [
+                7 => true,
+                12 => true,
+            ],
+        ];
+
+        yield 'pure enum with switch' => [
+            '<?php
+enum Foo
+{
+    case One;
+    case Two;
+
+    public static function getLowerName(self $instance): string
+    {
+        switch ($instance->name) {
+            case \'One\':
+            case \'Two\':
+                return strtolower($instance->name);
+        }
+    }
+}
+',
+            [
+                7 => true,
+                12 => true,
+                45 => false,
+                50 => false,
+            ],
+        ];
+
+        yield 'backed enum' => [
+            '<?php
+enum Suit: string
+{
+    case Hearts = \'hearts\';
+    case Spades = \'spades\';
+    case Clubs = \'clubs\';
+    case Diamonds = \'diamonds\';
+}
+',
+            [
+                10 => true,
+                19 => true,
+                28 => true,
+                37 => true,
+            ],
+        ];
+
+        yield 'backed enum with switch' => [
+            '<?php
+enum Suit: string
+{
+    case Hearts = \'hearts\';
+    case Spades = \'spades\';
+    case Clubs = \'clubs\';
+    case Diamonds = \'diamonds\';
+
+    public static function getUppercasedValue(self $instance): string
+    {
+        switch ($instance->value) {
+            case \'hearts\':
+            case \'spades\':
+                return strtoupper($instance->value);
+            default:
+                return $instance->value;
+        }
+    }
+}
+',
+            [
+                10 => true,
+                19 => true,
+                28 => true,
+                37 => true,
+                74 => false,
+                79 => false,
+            ],
+        ];
+    }
+
     /**
      * @param array<int, list<int>>|list<int> $expected
      *