SpacePossum 4 years ago
parent
commit
1d5ca8647c

+ 15 - 4
src/AbstractNoUselessElseFixer.php

@@ -36,6 +36,7 @@ abstract class AbstractNoUselessElseFixer extends AbstractFixer
     protected function isSuperfluousElse(Tokens $tokens, $index)
     {
         $previousBlockStart = $index;
+
         do {
             // Check if all 'if', 'else if ' and 'elseif' blocks above this 'else' always end,
             // if so this 'else' is overcomplete.
@@ -69,10 +70,19 @@ abstract class AbstractNoUselessElseFixer extends AbstractFixer
                 ]
             );
 
-            if (
-                null === $candidateIndex
-                || $tokens[$candidateIndex]->equalsAny([';', [T_CLOSE_TAG], [T_IF]])
-                || $this->isInConditional($tokens, $candidateIndex, $previousBlockStart)
+            if (null === $candidateIndex || $tokens[$candidateIndex]->equalsAny([';', [T_CLOSE_TAG], [T_IF]])) {
+                return false;
+            }
+
+            if ($tokens[$candidateIndex]->equals([T_THROW])) {
+                $previousIndex = $tokens->getPrevMeaningfulToken($candidateIndex);
+
+                if (!$tokens[$previousIndex]->equalsAny([';', '{'])) {
+                    return false;
+                }
+            }
+
+            if ($this->isInConditional($tokens, $candidateIndex, $previousBlockStart)
                 || $this->isInConditionWithoutBraces($tokens, $candidateIndex, $previousBlockStart)
             ) {
                 return false;
@@ -165,6 +175,7 @@ abstract class AbstractNoUselessElseFixer extends AbstractFixer
             if ($token->equals(';')) {
                 return false;
             }
+
             if ($token->equals('{')) {
                 $index = $tokens->getPrevMeaningfulToken($index);
 

+ 17 - 8
src/Fixer/ControlStructure/NoBreakCommentFixer.php

@@ -131,6 +131,7 @@ switch ($foo) {
         $empty = true;
         $fallThrough = true;
         $commentPosition = null;
+
         for ($i = $tokens->getNextTokenOfKind($casePosition, [':', ';']) + 1, $max = \count($tokens); $i < $max; ++$i) {
             if ($tokens[$i]->isGivenKind([T_SWITCH, T_IF, T_ELSE, T_ELSEIF, T_FOR, T_FOREACH, T_WHILE, T_DO, T_FUNCTION, T_CLASS])) {
                 $empty = false;
@@ -139,12 +140,22 @@ switch ($foo) {
                 continue;
             }
 
-            if ($tokens[$i]->isGivenKind([T_BREAK, T_CONTINUE, T_RETURN, T_EXIT, T_THROW, T_GOTO])) {
+            if ($tokens[$i]->isGivenKind([T_BREAK, T_CONTINUE, T_RETURN, T_EXIT, T_GOTO])) {
                 $fallThrough = false;
 
                 continue;
             }
 
+            if ($tokens[$i]->isGivenKind([T_THROW])) {
+                $previousIndex = $tokens->getPrevMeaningfulToken($i);
+
+                if ($previousIndex === $casePosition || $tokens[$previousIndex]->equalsAny(['{', ';', [T_OPEN_TAG]])) {
+                    $fallThrough = false;
+                }
+
+                continue;
+            }
+
             if ($tokens[$i]->equals('}') || $tokens[$i]->isGivenKind(T_ENDSWITCH)) {
                 if (null !== $commentPosition) {
                     $this->removeComment($tokens, $commentPosition);
@@ -170,7 +181,6 @@ switch ($foo) {
                         $this->insertCommentAt($tokens, $i);
                     } else {
                         $text = $this->configuration['comment_text'];
-
                         $tokens[$commentPosition] = new Token([
                             $tokens[$commentPosition]->getId(),
                             str_ireplace($text, $text, $tokens[$commentPosition]->getContent()),
@@ -211,12 +221,10 @@ switch ($foo) {
     private function insertCommentAt(Tokens $tokens, $casePosition)
     {
         $lineEnding = $this->whitespacesConfig->getLineEnding();
-
         $newlinePosition = $this->ensureNewLineAt($tokens, $casePosition);
-
         $newlineToken = $tokens[$newlinePosition];
-
         $nbNewlines = substr_count($newlineToken->getContent(), $lineEnding);
+
         if ($newlineToken->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $newlineToken->getContent())) {
             ++$nbNewlines;
         } elseif ($tokens[$newlinePosition - 1]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$newlinePosition - 1]->getContent())) {
@@ -236,7 +244,6 @@ switch ($foo) {
         }
 
         $tokens->insertAt($newlinePosition, new Token([T_COMMENT, '// '.$this->configuration['comment_text']]));
-
         $this->ensureNewLineAt($tokens, $newlinePosition);
     }
 
@@ -249,8 +256,8 @@ switch ($foo) {
     {
         $lineEnding = $this->whitespacesConfig->getLineEnding();
         $content = $lineEnding.$this->getIndentAt($tokens, $position);
-
         $whitespaceToken = $tokens[$position - 1];
+
         if (!$whitespaceToken->isGivenKind(T_WHITESPACE)) {
             if ($whitespaceToken->isGivenKind(T_OPEN_TAG)) {
                 $content = Preg::replace('/\R/', '', $content);
@@ -293,6 +300,7 @@ switch ($foo) {
         }
 
         $whitespaceToken = $tokens[$whitespacePosition];
+
         if ($whitespaceToken->isGivenKind(T_WHITESPACE)) {
             $content = Preg::replace($regex, '', $whitespaceToken->getContent());
             if ('' !== $content) {
@@ -320,8 +328,8 @@ switch ($foo) {
             }
 
             $content = $tokens[$position]->getContent();
-
             $prevToken = $tokens[$position - 1];
+
             if ($prevToken->isGivenKind(T_OPEN_TAG) && Preg::match('/\R$/', $prevToken->getContent())) {
                 $content = $this->whitespacesConfig->getLineEnding().$content;
             }
@@ -359,6 +367,7 @@ switch ($foo) {
         }
 
         $position = $tokens->getNextMeaningfulToken($position);
+
         if ('{' !== $tokens[$position]->getContent()) {
             return $tokens->getNextTokenOfKind($position, [';']);
         }

+ 6 - 5
src/Fixer/ControlStructure/NoSuperfluousElseifFixer.php

@@ -71,11 +71,10 @@ final class NoSuperfluousElseifFixer extends AbstractNoUselessElseFixer
      */
     private function isElseif(Tokens $tokens, $index)
     {
-        if ($tokens[$index]->isGivenKind(T_ELSEIF)) {
-            return true;
-        }
-
-        return $tokens[$index]->isGivenKind(T_ELSE) && $tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_IF);
+        return
+            $tokens[$index]->isGivenKind(T_ELSEIF)
+            || ($tokens[$index]->isGivenKind(T_ELSE) && $tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_IF))
+        ;
     }
 
     /**
@@ -90,6 +89,7 @@ final class NoSuperfluousElseifFixer extends AbstractNoUselessElseFixer
         }
 
         $whitespace = '';
+
         for ($previous = $index - 1; $previous > 0; --$previous) {
             $token = $tokens[$previous];
             if ($token->isWhitespace() && Preg::match('/(\R\N*)$/', $token->getContent(), $matches)) {
@@ -104,6 +104,7 @@ final class NoSuperfluousElseifFixer extends AbstractNoUselessElseFixer
         }
 
         $previousToken = $tokens[$index - 1];
+
         if (!$previousToken->isWhitespace()) {
             $tokens->insertAt($index, new Token([T_WHITESPACE, $whitespace]));
         } elseif (!Preg::match('/\R/', $previousToken->getContent())) {

+ 2 - 0
src/Fixer/ControlStructure/NoUselessElseFixer.php

@@ -90,6 +90,7 @@ final class NoUselessElseFixer extends AbstractNoUselessElseFixer
     private function fixEmptyElse(Tokens $tokens, $index)
     {
         $next = $tokens->getNextMeaningfulToken($index);
+
         if ($tokens[$next]->equals('{')) {
             $close = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next);
             if (1 === $close - $next) { // '{}'
@@ -117,6 +118,7 @@ final class NoUselessElseFixer extends AbstractNoUselessElseFixer
 
         // clear T_ELSE and the '{' '}' if there are any
         $next = $tokens->getNextMeaningfulToken($index);
+
         if (!$tokens[$next]->equals('{')) {
             return;
         }

+ 58 - 2
tests/Fixer/ControlStructure/NoBreakCommentFixerTest.php

@@ -734,19 +734,25 @@ switch ($foo) {
             [
                 '<?php
 switch ($foo) {
-    case 1:
+    case 1: {
         throw new \Exception();
+    }
     case 2:
+        ?>
+        <?php
         throw new \Exception();
     default:
         throw new \Exception();
 }',
                 '<?php
 switch ($foo) {
-    case 1:
+    case 1: {
         // no break
         throw new \Exception();
+    }
     case 2:
+        ?>
+        <?php
         // no break
         throw new \Exception();
     default:
@@ -1113,4 +1119,54 @@ switch ($foo) {
 
         $this->fixer->configure(['foo' => true]);
     }
+
+    /**
+     * @param string $input
+     * @param string $expected
+     *
+     * @dataProvider provideFix80Cases
+     * @requires PHP 8.0
+     */
+    public function testFix80($expected, $input)
+    {
+        $this->doTest($expected, $input);
+    }
+
+    public function provideFix80Cases()
+    {
+        yield [
+            '<?php
+                switch ($foo) {
+                    case 1:
+                        foo() ?? throw new \Exception();
+                        // no break
+                    case 2:
+                        $a = $condition and throw new Exception();
+                        // no break
+                    case 3:
+                        $callable = fn() => throw new Exception();
+                        // no break
+                    case 4:
+                        $value = $falsableValue ?: throw new InvalidArgumentException();
+                        // no break
+                    default:
+                        echo "PHP8";
+                }
+            ',
+            '<?php
+                switch ($foo) {
+                    case 1:
+                        foo() ?? throw new \Exception();
+                    case 2:
+                        $a = $condition and throw new Exception();
+                    case 3:
+                        $callable = fn() => throw new Exception();
+                    case 4:
+                        $value = $falsableValue ?: throw new InvalidArgumentException();
+                    default:
+                        echo "PHP8";
+                }
+            ',
+        ];
+    }
 }

+ 24 - 0
tests/Fixer/ControlStructure/NoSuperfluousElseifFixerTest.php

@@ -279,4 +279,28 @@ if ($some) { return 1; } elseif ($a == 6){ $test = false; } //',
             ],
         ];
     }
+
+    /**
+     * @param string $expected
+     *
+     * @dataProvider provideFix80Cases
+     * @requires PHP 8.0
+     */
+    public function testFix80($expected)
+    {
+        $this->doTest($expected);
+    }
+
+    public function provideFix80Cases()
+    {
+        yield [
+            '<?php
+            if ($foo) {
+                $a = $bar ?? throw new \Exception();
+            } elseif ($bar) {
+                echo 1;
+            }
+            ',
+        ];
+    }
 }

+ 64 - 26
tests/Fixer/ControlStructure/NoUselessElseFixerTest.php

@@ -231,7 +231,8 @@ else?><?php echo 5;',
                     }
                 else
                     echo 4;
-            ', ];
+            ',
+        ];
 
         $cases[] = [
             '<?php
@@ -247,7 +248,8 @@ else?><?php echo 5;',
                         return 1;
                 } else
                     echo 4;
-            ', ];
+            ',
+        ];
 
         return $cases;
     }
@@ -265,35 +267,37 @@ else?><?php echo 5;',
 
     public function provideFixIfElseCases()
     {
-        $expected =
-            '<?php
+        $expected = '<?php
+            while(true) {
                 while(true) {
-                    while(true) {
-                        if ($a) {
-                            %s
-                        }  '.'
-                            echo 1;
-                        '.'
-                    }
+                    if ($a) {
+                        %s
+                    }  '.'
+                        echo 1;
+                    '.'
                 }
-            ';
+            }
+        ';
 
-        $input =
-            '<?php
+        $input = '<?php
+            while(true) {
                 while(true) {
-                    while(true) {
-                        if ($a) {
-                            %s
-                        } else {
-                            echo 1;
-                        }
+                    if ($a) {
+                        %s
+                    } else {
+                        echo 1;
                     }
                 }
-            ';
+            }
+        ';
 
-        $cases = $this->generateCases($expected, $input);
+        $tests = $this->generateCases($expected, $input);
 
-        $cases[] = [
+        foreach ($tests as $index => $test) {
+            yield $index => $test;
+        }
+
+        yield [
             '<?php
                 if ($a) {
                     GOTO jump;
@@ -313,8 +317,6 @@ else?><?php echo 5;',
                 jump:
             ',
         ];
-
-        return $cases;
     }
 
     /**
@@ -465,7 +467,7 @@ else?><?php echo 5;',
 
     public function provideNegativeCases()
     {
-        return [
+        $tests = [
             [
                 '<?php
                     if ($a0) {
@@ -623,6 +625,37 @@ else?><?php echo 5;',
                     };',
             ],
         ];
+
+        foreach ($tests as $index => $test) {
+            yield $index => $test;
+        }
+
+        if (\PHP_VERSION_ID >= 80000) {
+            $cases = [
+                '$bar = $foo1 ?? throw new \Exception($e);',
+                '$callable = fn() => throw new Exception();',
+                '$value = $falsableValue ?: throw new InvalidArgumentException();',
+                '$value = !empty($array)
+                    ? reset($array)
+                    : throw new InvalidArgumentException();',
+                '$a = $condition && throw new Exception();',
+                '$a = $condition || throw new Exception();',
+                '$a = $condition and throw new Exception();',
+                '$a = $condition or throw new Exception();',
+            ];
+
+            $template = '<?php
+                if ($foo) {
+                    %s
+                } else {
+                    echo 123;
+                }
+            ';
+
+            foreach ($cases as $index => $case) {
+                yield [sprintf('PHP8 Negative case %d', $index) => sprintf($template, $case)];
+            }
+        }
     }
 
     /**
@@ -713,6 +746,10 @@ else?><?php echo 5;',
             $statements[] = 'throw new class ($a, 9) extends Exception{ public function z($a, $b){ echo 7;} };';
         }
 
+        if (\PHP_VERSION_ID >= 80000) {
+            $statements[] = '$b = $a ?? throw new Exception($i);';
+        }
+
         $ifTemplate = '<?php
             if ($a === false)
             {
@@ -964,6 +1001,7 @@ else?><?php echo 5;',
     private function generateCases($expected, $input = null)
     {
         $cases = [];
+
         foreach ([
             'exit;',
             'exit();',

+ 31 - 22
tests/Fixer/ControlStructure/YodaStyleFixerTest.php

@@ -55,17 +55,9 @@ final class YodaStyleFixerTest extends AbstractFixerTestCase
         }
     }
 
-    /**
-     * @return array
-     */
     public function provideFixCases()
     {
-        return [
-            [
-                '<?php $a = ($b + $c) || 1 === true ? 1 : 2;',
-                null,
-                ['always_move_variable' => true],
-            ],
+        $tests = [
             [
                 '<?php $a = 1 + ($b + $c) === true ? 1 : 2;',
                 null,
@@ -620,10 +612,6 @@ $a#4
                 '<?php $a = -/* bar */1 === reset($foo);',
                 '<?php $a = reset($foo) === -/* bar */1;',
             ],
-            [
-                '<?php $a **= 4 === $b ? 2 : 3;',
-                '<?php $a **= $b === 4 ? 2 : 3;',
-            ],
             [
                 '<?php $a %= 4 === $b ? 2 : 3;',
                 '<?php $a %= $b === 4 ? 2 : 3;',
@@ -648,7 +636,37 @@ $a#4
                     // 1
                 ];',
             ],
+            [
+                '<?php $a = $b = null === $c;',
+                '<?php $a = $b = $c === null;',
+            ],
         ];
+
+        foreach ($tests as $index => $test) {
+            yield $index => $test;
+        }
+
+        $template = '<?php $a = ($b + $c) %s 1 === true ? 1 : 2;';
+        $operators = ['||', '&&'];
+
+        foreach ($operators as $operator) {
+            yield [
+                sprintf($template, $operator),
+                null,
+                ['always_move_variable' => true],
+            ];
+        }
+
+        $templateExpected = '<?php $a %s 4 === $b ? 2 : 3;';
+        $templateInput = '<?php $a %s $b === 4 ? 2 : 3;';
+        $operators = ['**=', '*=', '|=', '+=', '-=', '^=', 'xor', 'or', 'and', '<<=', '>>=', '&=', '.=', '/=', '-=', '||', '&&'];
+
+        foreach ($operators as $operator) {
+            yield [
+                sprintf($templateExpected, $operator),
+                sprintf($templateInput, $operator),
+            ];
+        }
     }
 
     /**
@@ -677,9 +695,6 @@ $a#4
         $this->doTest($input, $expected);
     }
 
-    /**
-     * @return array<string[]>
-     */
     public function provideLessGreaterCases()
     {
         return [
@@ -782,9 +797,6 @@ $a#4
         }
     }
 
-    /**
-     * @return array<string[]>
-     */
     public function providePHP70Cases()
     {
         return [
@@ -845,9 +857,6 @@ function a() {
         }
     }
 
-    /**
-     * @return array<string[]>
-     */
     public function providePHP71Cases()
     {
         return [

+ 31 - 0
tests/Fixer/Whitespace/NoExtraBlankLinesFixerTest.php

@@ -1234,6 +1234,37 @@ use const some\Z\{ConstX,ConstY,ConstZ,};
         ];
     }
 
+    /**
+     * @param string $expected
+     *
+     * @dataProvider provideFix80Cases
+     * @requires PHP 8.0
+     */
+    public function testFix80($expected)
+    {
+        $this->fixer->configure(['tokens' => ['throw']]);
+
+        $this->doTest($expected);
+    }
+
+    public function provideFix80Cases()
+    {
+        yield [
+            '<?php
+                $a = $bar ?? throw new \Exception();
+                $a = $bar ?? throw new \Exception();
+                $a = $bar ?? throw new \Exception();
+            ',
+            '<?php
+                $a = $bar ?? throw new \Exception();
+
+                $a = $bar ?? throw new \Exception();
+
+                $a = $bar ?? throw new \Exception();
+            ',
+        ];
+    }
+
     private function removeLinesFromString($input, array $lineNumbers)
     {
         sort($lineNumbers);