Browse Source

feat: `no_superfluous_phpdoc_tags` - introduce `allow_future_params` option (#7743)

Dariusz Rumiński 1 year ago
parent
commit
aba9464f67

+ 1 - 1
doc/ruleSets/Symfony.rst

@@ -81,7 +81,7 @@ Rules
 - `no_spaces_around_offset <./../rules/whitespace/no_spaces_around_offset.rst>`_
 - `no_superfluous_phpdoc_tags <./../rules/phpdoc/no_superfluous_phpdoc_tags.rst>`_ with config:
 
-  ``['remove_inheritdoc' => true]``
+  ``['allow_hidden_params' => true, 'remove_inheritdoc' => true]``
 
 - `no_trailing_comma_in_singleline <./../rules/basic/no_trailing_comma_in_singleline.rst>`_
 - `no_unneeded_braces <./../rules/control_structure/no_unneeded_braces.rst>`_ with config:

+ 31 - 1
doc/rules/phpdoc/no_superfluous_phpdoc_tags.rst

@@ -8,6 +8,15 @@ information.
 Configuration
 -------------
 
+``allow_hidden_params``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Whether ``param`` annotation for hidden params in method signature are allowed.
+
+Allowed types: ``bool``
+
+Default value: ``false``
+
 ``allow_mixed``
 ~~~~~~~~~~~~~~~
 
@@ -99,6 +108,26 @@ With configuration: ``['remove_inheritdoc' => true]``.
 Example #4
 ~~~~~~~~~~
 
+With configuration: ``['allow_hidden_params' => true]``.
+
+.. code-block:: diff
+
+   --- Original
+   +++ New
+    <?php
+    class Foo {
+        /**
+   -     * @param Bar $bar
+   -     * @param mixed $baz
+         * @param string|int|null $qux
+   -     * @param mixed $foo
+         */
+        public function doFoo(Bar $bar, $baz /*, $qux = null */) {}
+    }
+
+Example #5
+~~~~~~~~~~
+
 With configuration: ``['allow_unused_params' => true]``.
 
 .. code-block:: diff
@@ -111,6 +140,7 @@ With configuration: ``['allow_unused_params' => true]``.
    -     * @param Bar $bar
    -     * @param mixed $baz
          * @param string|int|null $qux
+         * @param mixed $foo
          */
         public function doFoo(Bar $bar, $baz /*, $qux = null */) {}
     }
@@ -126,7 +156,7 @@ The rule is part of the following rule sets:
 
 - `@Symfony <./../../ruleSets/Symfony.rst>`_ with config:
 
-  ``['remove_inheritdoc' => true]``
+  ``['allow_hidden_params' => true, 'remove_inheritdoc' => true]``
 
 
 References

+ 47 - 8
src/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixer.php

@@ -59,7 +59,8 @@ final class NoSuperfluousPhpdocTagsFixer extends AbstractFixer implements Config
         return new FixerDefinition(
             'Removes `@param`, `@return` and `@var` tags that don\'t provide any useful information.',
             [
-                new CodeSample('<?php
+                new CodeSample(
+                    '<?php
 class Foo {
     /**
      * @param Bar $bar
@@ -69,8 +70,10 @@ class Foo {
      */
     public function doFoo(Bar $bar, $baz): Baz {}
 }
-'),
-                new CodeSample('<?php
+',
+                ),
+                new CodeSample(
+                    '<?php
 class Foo {
     /**
      * @param Bar $bar
@@ -78,25 +81,48 @@ class Foo {
      */
     public function doFoo(Bar $bar, $baz) {}
 }
-', ['allow_mixed' => true]),
-                new CodeSample('<?php
+',
+                    ['allow_mixed' => true],
+                ),
+                new CodeSample(
+                    '<?php
 class Foo {
     /**
      * @inheritDoc
      */
     public function doFoo(Bar $bar, $baz) {}
 }
-', ['remove_inheritdoc' => true]),
-                new CodeSample('<?php
+',
+                    ['remove_inheritdoc' => true],
+                ),
+                new CodeSample(
+                    '<?php
 class Foo {
     /**
      * @param Bar $bar
      * @param mixed $baz
      * @param string|int|null $qux
+     * @param mixed $foo
      */
     public function doFoo(Bar $bar, $baz /*, $qux = null */) {}
 }
-', ['allow_unused_params' => true]),
+',
+                    ['allow_hidden_params' => true],
+                ),
+                new CodeSample(
+                    '<?php
+class Foo {
+    /**
+     * @param Bar $bar
+     * @param mixed $baz
+     * @param string|int|null $qux
+     * @param mixed $foo
+     */
+    public function doFoo(Bar $bar, $baz /*, $qux = null */) {}
+}
+',
+                    ['allow_unused_params' => true],
+                ),
             ]
         );
     }
@@ -209,6 +235,10 @@ class Foo {
                 ->setAllowedTypes(['bool'])
                 ->setDefault(false)
                 ->getOption(),
+            (new FixerOptionBuilder('allow_hidden_params', 'Whether `param` annotation for hidden params in method signature are allowed.'))
+                ->setAllowedTypes(['bool'])
+                ->setDefault(false) // @TODO set to `true` on 4.0
+                ->getOption(),
             (new FixerOptionBuilder('allow_unused_params', 'Whether `param` annotation without actual signature is allowed (`true`) or considered superfluous (`false`).'))
                 ->setAllowedTypes(['bool'])
                 ->setDefault(false)
@@ -433,6 +463,15 @@ class Foo {
             $argumentsInfo[$token->getContent()] = $info;
         }
 
+        // virtualise "hidden params" as if they would be regular ones
+        if (true === $this->configuration['allow_hidden_params']) {
+            $paramsString = $tokens->generatePartialCode($start, $end);
+            Preg::matchAll('|/\*[^$]*(\$\w+)[^*]*\*/|', $paramsString, $matches);
+            foreach ($matches[1] as $match) {
+                $argumentsInfo[$match] = self::NO_TYPE_INFO; // HINT: one could try to extract actual type for hidden param, for now we only indicate it's existence
+            }
+        }
+
         return $argumentsInfo;
     }
 

+ 1 - 0
src/RuleSet/Sets/SymfonySet.php

@@ -108,6 +108,7 @@ final class SymfonySet extends AbstractRuleSetDescription
             'no_singleline_whitespace_before_semicolons' => true,
             'no_spaces_around_offset' => true,
             'no_superfluous_phpdoc_tags' => [
+                'allow_hidden_params' => true,
                 'remove_inheritdoc' => true,
             ],
             'no_trailing_comma_in_singleline' => true,

+ 42 - 0
tests/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixerTest.php

@@ -2566,6 +2566,48 @@ static fn ($foo): int => 1;',
                 }
                 EOD,
         ];
+
+        yield '@param for hidden parameter with option disabled' => [
+            <<<'EOD'
+                <?php
+                /**
+                 */
+                function foo(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container, /* string $bundleDir1 = null, */ $foo1/** , string $bundleDir2 = null */, $foo2 /* , mixed $bundleDir3 */) {}
+                EOD,
+            <<<'EOD'
+                <?php
+                /**
+                 * @param array   $bundleConfig
+                 * @param ?string $bundleDir1
+                 * @param ?string $bundleDir2
+                 * @param mixed   $bundleDir3
+                 */
+                function foo(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container, /* string $bundleDir1 = null, */ $foo1/** , string $bundleDir2 = null */, $foo2 /* , mixed $bundleDir3 */) {}
+                EOD,
+            ['allow_hidden_params' => false],
+        ];
+
+        yield '@param for hidden parameter with option enabled' => [
+            <<<'EOD'
+                <?php
+                /**
+                 * @param ?string $bundleDir1
+                 * @param ?string $bundleDir2
+                 */
+                function foo(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container, /* string $bundleDir1 = null, */ $foo1/** , string $bundleDir2 = null */, $foo2 /* , mixed $bundleDir3 */) {}
+                EOD,
+            <<<'EOD'
+                <?php
+                /**
+                 * @param array   $bundleConfig
+                 * @param ?string $bundleDir1
+                 * @param ?string $bundleDir2
+                 * @param mixed   $bundleDir3
+                 */
+                function foo(array $bundleConfig, \ReflectionClass $bundle, ContainerBuilder $container, /* string $bundleDir1 = null, */ $foo1/** , string $bundleDir2 = null */, $foo2 /* , mixed $bundleDir3 */) {}
+                EOD,
+            ['allow_hidden_params' => true],
+        ];
     }
 
     /**