Browse Source

minor: Let PhpdocLineSpan fixer detect docblocks when seperator from token with attribute (#6343)

Let PhpdocLineSpan fixer detect docblocks when seperator from token with attribute
Bob van de Vijver 2 years ago
parent
commit
2389f5c408

+ 1 - 1
phpstan.neon

@@ -23,6 +23,6 @@ parameters:
         -
             message: '#^.+no value type specified in iterable type.+\.$#'
             path: *
-            count: 542
+            count: 540
     tipsOfTheDay: false
     tmpDir: dev-tools/phpstan/cache

+ 8 - 0
src/Fixer/Phpdoc/PhpdocLineSpanFixer.php

@@ -144,12 +144,20 @@ final class PhpdocLineSpanFixer extends AbstractFixer implements WhitespacesAwar
             CT::T_NULLABLE_TYPE,
         ];
 
+        if (\defined('T_ATTRIBUTE')) { // @TODO: drop condition when PHP 8.0+ is required
+            $propertyPartKinds[] = T_ATTRIBUTE;
+        }
+
         if (\defined('T_READONLY')) { // @TODO: drop condition when PHP 8.1+ is required
             $propertyPartKinds[] = T_READONLY;
         }
 
         do {
             $index = $tokens->getPrevNonWhitespace($index);
+
+            if ($tokens[$index]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) {
+                $index = $tokens->getPrevTokenOfKind($index, [[T_ATTRIBUTE]]);
+            }
         } while ($tokens[$index]->isGivenKind($propertyPartKinds));
 
         return $index;

+ 197 - 3
tests/Fixer/Phpdoc/PhpdocLineSpanFixerTest.php

@@ -27,6 +27,8 @@ final class PhpdocLineSpanFixerTest extends AbstractFixerTestCase
 {
     /**
      * @dataProvider provideFixCases
+     *
+     * @param array<string, mixed> $config
      */
     public function testFix(string $expected, ?string $input = null, array $config = []): void
     {
@@ -557,9 +559,158 @@ class Foo
         ];
     }
 
+    /**
+     * @dataProvider provideFix80Cases
+     * @requires PHP 8.0
+     *
+     * @param array<string, mixed> $config
+     */
+    public function testFix80(string $expected, string $input = null, array $config = []): void
+    {
+        $this->fixer->configure($config);
+        $this->doTest($expected, $input);
+    }
+
+    public function provideFix80Cases(): iterable
+    {
+        yield 'It detects attributes between docblock and token' => [
+            '<?php
+
+class Foo
+{
+    /** @var string[] */
+    #[Attribute1]
+    private array $foo1;
+
+    /** @var string[] */
+    #[Attribute1]
+    #[Attribute2]
+    private array $foo2;
+
+    /** @var string[] */
+    #[Attribute1, Attribute2]
+    public array $foo3;
+}',
+            '<?php
+
+class Foo
+{
+    /**
+     * @var string[]
+     */
+    #[Attribute1]
+    private array $foo1;
+
+    /**
+     * @var string[]
+     */
+    #[Attribute1]
+    #[Attribute2]
+    private array $foo2;
+
+    /**
+     * @var string[]
+     */
+    #[Attribute1, Attribute2]
+    public array $foo3;
+}',
+            [
+                'property' => 'single',
+            ],
+        ];
+
+        yield 'It handles class constants correctly' => [
+            '<?php
+class Foo
+{
+    /**
+     * 0
+     */
+    #[Attribute1]
+    const B0 = "0";
+
+    /**
+     * 1
+     */
+    #[Attribute1]
+    #[Attribute2]
+    public const B1 = "1";
+
+    /**
+     * 2
+     */
+    #[Attribute1, Attribute2]
+    public const B2 = "2";
+}
+',
+            '<?php
+class Foo
+{
+    /** 0 */
+    #[Attribute1]
+    const B0 = "0";
+
+    /** 1 */
+    #[Attribute1]
+    #[Attribute2]
+    public const B1 = "1";
+
+    /** 2 */
+    #[Attribute1, Attribute2]
+    public const B2 = "2";
+}
+',
+        ];
+
+        yield 'It handles class functions correctly' => [
+            '<?php
+                class Foo
+                {
+                    /**
+                     * @return void
+                     */
+                    #[Attribute1]
+                    public function hello1() {}
+
+                    /**
+                     * @return void
+                     */
+                    #[Attribute1]
+                    #[Attribute2]
+                    public function hello2() {}
+
+                    /**
+                     * @return void
+                     */
+                    #[Attribute1, Attribute2]
+                    public function hello3() {}
+                }
+            ',
+            '<?php
+                class Foo
+                {
+                    /** @return void */
+                    #[Attribute1]
+                    public function hello1() {}
+
+                    /** @return void */
+                    #[Attribute1]
+                    #[Attribute2]
+                    public function hello2() {}
+
+                    /** @return void */
+                    #[Attribute1, Attribute2]
+                    public function hello3() {}
+                }
+            ',
+        ];
+    }
+
     /**
      * @dataProvider provideFix81Cases
      * @requires PHP 8.1
+     *
+     * @param array<string, mixed> $config
      */
     public function testFix81(string $expected, string $input = null, array $config = []): void
     {
@@ -569,7 +720,7 @@ class Foo
 
     public function provideFix81Cases(): iterable
     {
-        yield 'readonly' => [
+        yield 'It handles readonly properties correctly' => [
             '<?php
 
 class Foo
@@ -607,7 +758,7 @@ class Foo
             ],
         ];
 
-        yield [
+        yield 'It handles class constant correctly' => [
             '<?php
 class Foo
 {
@@ -650,7 +801,7 @@ class Foo
 ',
         ];
 
-        yield [
+        yield 'It handles enum functions correctly' => [
             '<?php
                 enum Foo
                 {
@@ -668,5 +819,48 @@ class Foo
                 }
             ',
         ];
+
+        yield 'It handles enum function with attributes correctly' => [
+            '<?php
+                enum Foo
+                {
+                    /**
+                     * @return void
+                     */
+                    #[Attribute1]
+                    public function hello1() {}
+
+                    /**
+                     * @return void
+                     */
+                    #[Attribute1]
+                    #[Attribute2]
+                    public function hello2() {}
+
+                    /**
+                     * @return void
+                     */
+                    #[Attribute1, Attribute2]
+                    public function hello3() {}
+                }
+            ',
+            '<?php
+                enum Foo
+                {
+                    /** @return void */
+                    #[Attribute1]
+                    public function hello1() {}
+
+                    /** @return void */
+                    #[Attribute1]
+                    #[Attribute2]
+                    public function hello2() {}
+
+                    /** @return void */
+                    #[Attribute1, Attribute2]
+                    public function hello3() {}
+                }
+            ',
+        ];
     }
 }