Browse Source

minor: `SelfStaticAccessorFixer` improvements for enums (#7026)

SpacePossum 1 year ago
parent
commit
137667d437

+ 21 - 12
src/Fixer/ClassNotation/SelfStaticAccessorFixer.php

@@ -103,8 +103,14 @@ enum Foo
 
     public function isCandidate(Tokens $tokens): bool
     {
-        return ($tokens->isAllTokenKindsFound([T_CLASS, T_STATIC])
-            || (\defined('T_ENUM') && $tokens->isAllTokenKindsFound([T_ENUM, T_STATIC]))) // @TODO drop condition when PHP 8.1+ is required
+        $classyTypes = [T_CLASS];
+
+        if (\defined('T_ENUM')) { // @TODO: drop condition when PHP 8.1+ is required
+            $classyTypes[] = T_ENUM;
+        }
+
+        return $tokens->isTokenKindFound(T_STATIC)
+            && $tokens->isAnyTokenKindsFound($classyTypes)
             && $tokens->isAnyTokenKindsFound([T_DOUBLE_COLON, T_NEW, T_INSTANCEOF]);
     }
 
@@ -130,21 +136,24 @@ enum Foo
         $classyIndex = $tokens->getNextTokenOfKind(0, $classyTokensOfInterest);
 
         while (null !== $classyIndex) {
-            $modifiers = $this->tokensAnalyzer->getClassyModifiers($classyIndex);
-
-            if (
-                isset($modifiers['final'])
-                || $this->tokensAnalyzer->isAnonymousClass($classyIndex)
-                || (\defined('T_ENUM') && $tokens[$classyIndex]->isGivenKind(T_ENUM)) // @TODO drop condition when PHP 8.1+ is required
-            ) {
-                $classyIndex = $this->fixClass($tokens, $classyIndex);
+            if ($tokens[$classyIndex]->isGivenKind(T_CLASS)) {
+                $modifiers = $this->tokensAnalyzer->getClassyModifiers($classyIndex);
+
+                if (
+                    isset($modifiers['final'])
+                    || $this->tokensAnalyzer->isAnonymousClass($classyIndex)
+                ) {
+                    $classyIndex = $this->fixClassy($tokens, $classyIndex);
+                }
+            } else {
+                $classyIndex = $this->fixClassy($tokens, $classyIndex);
             }
 
             $classyIndex = $tokens->getNextTokenOfKind($classyIndex, $classyTokensOfInterest);
         }
     }
 
-    private function fixClass(Tokens $tokens, int $index): int
+    private function fixClassy(Tokens $tokens, int $index): int
     {
         $index = $tokens->getNextTokenOfKind($index, ['{']);
         $classOpenCount = 1;
@@ -178,7 +187,7 @@ enum Foo
                         } elseif ($tokens[$index]->equals('{')) {
                             ++$openCount;
                         } else {
-                            $index = $this->fixClass($tokens, $index);
+                            $index = $this->fixClassy($tokens, $index);
                         }
                     } while ($openCount > 0);
                 }

+ 50 - 1
tests/Fixer/ClassNotation/SelfStaticAccessorFixerTest.php

@@ -365,7 +365,7 @@ $b = function() { return static::class; };
      *
      * @requires PHP 8.1
      */
-    public function testFix81(string $expected, ?string $input = null): void
+    public function testFix81(string $expected, string $input): void
     {
         $this->doTest($expected, $input);
     }
@@ -414,6 +414,55 @@ enum Foo
 }
 ',
         ];
+
+        yield 'enum with nested anonymous class' => [
+            '<?php
+                enum Suit: int implements SomeIntInterface, Z
+                {
+                    case Hearts = 1;
+                    case Clubs = 3;
+                    public const HEARTS = self::Hearts;
+
+                    public function Foo(): string
+                    {
+                        return self::Hearts->Bar()->getBar() . self::class . self::Clubs->value;
+                    }
+
+                    public function Bar(): object
+                    {
+                        return new class {
+                            public function getBar()
+                            {
+                                return self::class;
+                            }
+                        };
+                    }
+                }
+            ',
+            '<?php
+                enum Suit: int implements SomeIntInterface, Z
+                {
+                    case Hearts = 1;
+                    case Clubs = 3;
+                    public const HEARTS = self::Hearts;
+
+                    public function Foo(): string
+                    {
+                        return static::Hearts->Bar()->getBar() . static::class . static::Clubs->value;
+                    }
+
+                    public function Bar(): object
+                    {
+                        return new class {
+                            public function getBar()
+                            {
+                                return static::class;
+                            }
+                        };
+                    }
+                }
+            ',
+        ];
     }
 
     /**