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

bug: BinaryOperatorSpacesFixer: Solve issues with scoped arrow and equal alignments (#6515)

Vincent Langlet 2 лет назад
Родитель
Сommit
2c36a47a04

+ 68 - 14
src/Fixer/Operator/BinaryOperatorSpacesFixer.php

@@ -519,7 +519,6 @@ $array = [
 
     private function injectAlignmentPlaceholdersDefault(Tokens $tokens, int $startAt, int $endAt, string $tokenContent): void
     {
-        $functionKind = [T_FUNCTION, T_FN];
         $newLineFoundSinceLastPlaceholder = true;
 
         for ($index = $startAt; $index < $endAt; ++$index) {
@@ -542,16 +541,41 @@ $array = [
                 continue;
             }
 
-            if ($token->isGivenKind($functionKind)) {
-                $index = $tokens->getNextTokenOfKind($index, ['(']);
-                $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
+            if ($token->isGivenKind(T_FN)) {
+                $index = $this->getLastTokenIndexOfFn($tokens, $index);
 
                 continue;
             }
 
-            if ($token->isGivenKind([T_FOREACH, T_FOR, T_WHILE, T_IF, T_SWITCH, T_ELSEIF])) {
-                $index = $tokens->getNextMeaningfulToken($index);
-                $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
+            if ($token->isGivenKind([T_FUNCTION, T_CLASS])) {
+                $index = $tokens->getNextTokenOfKind($index, ['{', ';', '(']);
+                // We don't align `=` on multi-line definition of function parameters with default values
+                if ($tokens[$index]->equals('(')) {
+                    $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
+
+                    continue;
+                }
+
+                if ($tokens[$index]->equals(';')) {
+                    continue;
+                }
+
+                // Update the token to the `{` one in order to apply the following logic
+                $token = $tokens[$index];
+            }
+
+            if ($token->equals('{')) {
+                $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
+                $this->injectAlignmentPlaceholders($tokens, $index + 1, $until - 1, $tokenContent);
+                $index = $until;
+
+                continue;
+            }
+
+            if ($token->equals('(')) {
+                $until = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
+                $this->injectAlignmentPlaceholders($tokens, $index + 1, $until - 1, $tokenContent);
+                $index = $until;
 
                 continue;
             }
@@ -577,9 +601,10 @@ $array = [
         // Only inject placeholders for multi-line code
         if ($tokens->isPartialCodeMultiline($from, $until)) {
             ++$this->deepestLevel;
-            ++$this->currentLevel;
+            $currentLevel = $this->currentLevel;
+            $this->currentLevel = $this->deepestLevel;
             $this->injectAlignmentPlaceholdersDefault($tokens, $from, $until, $tokenContent);
-            --$this->currentLevel;
+            $this->currentLevel = $currentLevel;
         }
     }
 
@@ -595,9 +620,8 @@ $array = [
                 $newLineFoundSinceLastPlaceholder = true;
             }
 
-            if ($token->isGivenKind([T_FOREACH, T_FOR, T_WHILE, T_IF, T_SWITCH, T_ELSEIF])) {
-                $index = $tokens->getNextMeaningfulToken($index);
-                $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
+            if ($token->isGivenKind(T_FN)) {
+                $index = $this->getLastTokenIndexOfFn($tokens, $index);
 
                 continue;
             }
@@ -679,9 +703,10 @@ $array = [
         // Only inject placeholders for multi-line arrays
         if ($tokens->isPartialCodeMultiline($from, $until)) {
             ++$this->deepestLevel;
-            ++$this->currentLevel;
+            $currentLevel = $this->currentLevel;
+            $this->currentLevel = $this->deepestLevel;
             $this->injectAlignmentPlaceholdersForArrow($tokens, $from, $until);
-            --$this->currentLevel;
+            $this->currentLevel = $currentLevel;
         }
     }
 
@@ -779,4 +804,33 @@ $array = [
 
         return $tmpCode;
     }
+
+    private function getLastTokenIndexOfFn(Tokens $tokens, int $index): int
+    {
+        $index = $tokens->getNextTokenOfKind($index, [[T_DOUBLE_ARROW]]);
+
+        while (true) {
+            $index = $tokens->getNextMeaningfulToken($index);
+
+            if ($tokens[$index]->equalsAny([';', ',', [T_CLOSE_TAG]])) {
+                break;
+            }
+
+            $blockType = Tokens::detectBlockType($tokens[$index]);
+
+            if (null === $blockType) {
+                continue;
+            }
+
+            if ($blockType['isStart']) {
+                $index = $tokens->findBlockEnd($blockType['type'], $index);
+
+                continue;
+            }
+
+            break;
+        }
+
+        return $index;
+    }
 }

+ 118 - 0
tests/Fixer/Operator/BinaryOperatorSpacesFixerTest.php

@@ -1566,6 +1566,64 @@ $someOtherArray = [$bcd = 1];
 $a = [$b];
 $ab = [$bc];
 $abc = [$bcd];
+',
+            ],
+            [
+                '<?php
+$result = false;
+
+$callback = static function () use (&$result) {
+    $result = true;
+};
+
+$this->query = $this->db->prepare(static function ($db) {
+   $sql = "INSERT INTO {$db->protectIdentifiers($db->DBPrefix)} ("
+          . $db->protectIdentifiers("name") . ", "
+          . $db->protectIdentifiers("email") . ", "
+          . $db->protectIdentifiers("country");
+});
+
+$classSet = Closure::bind(function ($key, $value) {
+    $this->{$key} = $value;
+}, $classObj, $className);
+',
+            ],
+            [
+                '<?php
+$obj = new class() extends SomeClass {
+    public $someProperty = null;
+};
+',
+            ],
+            [
+                '<?php
+$fabricator->setOverrides(["first" => "Bobby"], $persist = false);
+$bobbyUser = $fabricator->make();
+$bobbyUser = $fabricator->make();
+',
+            ],
+            [
+                '<?php
+$a = 1; if (true) {
+$bbb = 1;
+}
+',
+            ],
+            [
+                '<?php
+$fabricator->setOverrides(
+["first" => "Bobby"], $persist = false);
+$fabricator->setOverrides(["first" => "Bobby"], $persist = false
+);
+',
+            ],
+            [
+                '<?php
+$start = (
+    $input["start"] !== "" && ($date = DateTime::parse($input["start"]))
+        ? $date->setTimezone("UTC")
+        : $date->setTimezone("Europe/London")
+);
 ',
             ],
         ];
@@ -2156,6 +2214,66 @@ function asd() {
           "array" => fn () => false,
       ];
 }
+',
+            ],
+            [
+                '<?php
+collect()
+    ->map(fn ($arg) => [])
+    ->keyBy(fn ($arg) => []);
+',
+            ],
+            [
+                '<?php
+if ($this->save([
+    "bar"       => "baz",
+    "barbarbar" => "baz",
+])) {
+    // Do the work
+}
+',
+                '<?php
+if ($this->save([
+    "bar" => "baz",
+    "barbarbar" => "baz",
+])) {
+    // Do the work
+}
+',
+            ],
+            [
+                '<?php
+class test
+{
+    public function __construct()
+    {
+        $result = $this->test1(fn () => $this->test2($a));
+        foreach ($result as $k => $v)
+        {
+        }
+
+        $result = $this->test1(fn () => $this->test2($a, $b));
+        foreach ($result as $k => $v)
+        {
+        }
+    }
+}
+',
+            ],
+            [
+                '<?php
+$array = [
+    "foo"     => 123,
+    "longkey" => "test",
+    "baz"     => fn () => "value",
+];
+',
+                '<?php
+$array = [
+    "foo" => 123,
+    "longkey" => "test",
+    "baz" => fn () => "value",
+];
 ',
             ],
         ];