Browse Source

feat: Deprecate `NewWithBracesFixer` and proxy to `NewWithParenthesesFixer` (#7331)

Andreas Möller 1 year ago
parent
commit
2abddefba3

+ 1 - 1
dev-tools/phpstan/baseline.php

@@ -299,7 +299,7 @@ $ignoreErrors[] = [
 $ignoreErrors[] = [
 $ignoreErrors[] = [
 	'message' => '#^Only booleans are allowed in an if condition, mixed given\\.$#',
 	'message' => '#^Only booleans are allowed in an if condition, mixed given\\.$#',
 	'count' => 2,
 	'count' => 2,
-	'path' => __DIR__ . '/../../src/Fixer/Operator/NewWithBracesFixer.php',
+	'path' => __DIR__ . '/../../src/Fixer/Operator/NewWithParenthesesFixer.php',
 ];
 ];
 $ignoreErrors[] = [
 $ignoreErrors[] = [
 	'message' => '#^Only booleans are allowed in a negated boolean, mixed given\\.$#',
 	'message' => '#^Only booleans are allowed in a negated boolean, mixed given\\.$#',

+ 20 - 1
doc/list.rst

@@ -1340,6 +1340,25 @@ List of Available Rules
 
 
    All instances created with ``new`` keyword must (not) be followed by braces.
    All instances created with ``new`` keyword must (not) be followed by braces.
 
 
+   *warning deprecated*   Use ``new_with_parentheses`` instead.
+
+   Configuration options:
+
+   - | ``named_class``
+     | Whether named classes should be followed by parentheses.
+     | Allowed types: ``bool``
+     | Default value: ``true``
+   - | ``anonymous_class``
+     | Whether anonymous classes should be followed by parentheses.
+     | Allowed types: ``bool``
+     | Default value: ``true``
+
+
+   `Source PhpCsFixer\\Fixer\\Operator\\NewWithBracesFixer <./../src/Fixer/Operator/NewWithBracesFixer.php>`_
+-  `new_with_parentheses <./rules/operator/new_with_parentheses.rst>`_
+
+   All instances created with ``new`` keyword must (not) be followed by parentheses.
+
    Configuration options:
    Configuration options:
 
 
    - | ``named_class``
    - | ``named_class``
@@ -1354,7 +1373,7 @@ List of Available Rules
 
 
    Part of rule sets `@PER <./ruleSets/PER.rst>`_ `@PER-CS <./ruleSets/PER-CS.rst>`_ `@PER-CS1.0 <./ruleSets/PER-CS1.0.rst>`_ `@PER-CS2.0 <./ruleSets/PER-CS2.0.rst>`_ `@PSR12 <./ruleSets/PSR12.rst>`_ `@PhpCsFixer <./ruleSets/PhpCsFixer.rst>`_ `@Symfony <./ruleSets/Symfony.rst>`_
    Part of rule sets `@PER <./ruleSets/PER.rst>`_ `@PER-CS <./ruleSets/PER-CS.rst>`_ `@PER-CS1.0 <./ruleSets/PER-CS1.0.rst>`_ `@PER-CS2.0 <./ruleSets/PER-CS2.0.rst>`_ `@PSR12 <./ruleSets/PSR12.rst>`_ `@PhpCsFixer <./ruleSets/PhpCsFixer.rst>`_ `@Symfony <./ruleSets/Symfony.rst>`_
 
 
-   `Source PhpCsFixer\\Fixer\\Operator\\NewWithBracesFixer <./../src/Fixer/Operator/NewWithBracesFixer.php>`_
+   `Source PhpCsFixer\\Fixer\\Operator\\NewWithParenthesesFixer <./../src/Fixer/Operator/NewWithParenthesesFixer.php>`_
 -  `non_printable_character <./rules/basic/non_printable_character.rst>`_
 -  `non_printable_character <./rules/basic/non_printable_character.rst>`_
 
 
    Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.
    Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.

+ 1 - 1
doc/ruleSets/PSR12.rst

@@ -27,7 +27,7 @@ Rules
 - `declare_equal_normalize <./../rules/language_construct/declare_equal_normalize.rst>`_
 - `declare_equal_normalize <./../rules/language_construct/declare_equal_normalize.rst>`_
 - `lowercase_cast <./../rules/cast_notation/lowercase_cast.rst>`_
 - `lowercase_cast <./../rules/cast_notation/lowercase_cast.rst>`_
 - `lowercase_static_reference <./../rules/casing/lowercase_static_reference.rst>`_
 - `lowercase_static_reference <./../rules/casing/lowercase_static_reference.rst>`_
-- `new_with_braces <./../rules/operator/new_with_braces.rst>`_
+- `new_with_parentheses <./../rules/operator/new_with_parentheses.rst>`_
 - `no_blank_lines_after_class_opening <./../rules/class_notation/no_blank_lines_after_class_opening.rst>`_
 - `no_blank_lines_after_class_opening <./../rules/class_notation/no_blank_lines_after_class_opening.rst>`_
 - `no_leading_import_slash <./../rules/import/no_leading_import_slash.rst>`_
 - `no_leading_import_slash <./../rules/import/no_leading_import_slash.rst>`_
 - `no_whitespace_in_blank_line <./../rules/whitespace/no_whitespace_in_blank_line.rst>`_
 - `no_whitespace_in_blank_line <./../rules/whitespace/no_whitespace_in_blank_line.rst>`_

+ 4 - 1
doc/rules/index.rst

@@ -551,9 +551,12 @@ Operator
 - `long_to_shorthand_operator <./operator/long_to_shorthand_operator.rst>`_
 - `long_to_shorthand_operator <./operator/long_to_shorthand_operator.rst>`_
 
 
   Shorthand notation for operators should be used if possible.
   Shorthand notation for operators should be used if possible.
-- `new_with_braces <./operator/new_with_braces.rst>`_
+- `new_with_braces <./operator/new_with_braces.rst>`_ *(deprecated)*
 
 
   All instances created with ``new`` keyword must (not) be followed by braces.
   All instances created with ``new`` keyword must (not) be followed by braces.
+- `new_with_parentheses <./operator/new_with_parentheses.rst>`_
+
+  All instances created with ``new`` keyword must (not) be followed by parentheses.
 - `no_space_around_double_colon <./operator/no_space_around_double_colon.rst>`_
 - `no_space_around_double_colon <./operator/no_space_around_double_colon.rst>`_
 
 
   There must be no space around double colons (also called Scope Resolution Operator or Paamayim Nekudotayim).
   There must be no space around double colons (also called Scope Resolution Operator or Paamayim Nekudotayim).

+ 8 - 14
doc/rules/operator/new_with_braces.rst

@@ -4,6 +4,14 @@ Rule ``new_with_braces``
 
 
 All instances created with ``new`` keyword must (not) be followed by braces.
 All instances created with ``new`` keyword must (not) be followed by braces.
 
 
+Warning
+-------
+
+This rule is deprecated and will be removed in the next major version
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You should use ``new_with_parentheses`` instead.
+
 Configuration
 Configuration
 -------------
 -------------
 
 
@@ -71,17 +79,3 @@ With configuration: ``['named_class' => false]``.
 
 
    -$x = new X();
    -$x = new X();
    +$x = new X;
    +$x = new X;
-
-Rule sets
----------
-
-The rule is part of the following rule sets:
-
-- `@PER <./../../ruleSets/PER.rst>`_
-- `@PER-CS <./../../ruleSets/PER-CS.rst>`_
-- `@PER-CS1.0 <./../../ruleSets/PER-CS1.0.rst>`_
-- `@PER-CS2.0 <./../../ruleSets/PER-CS2.0.rst>`_
-- `@PSR12 <./../../ruleSets/PSR12.rst>`_
-- `@PhpCsFixer <./../../ruleSets/PhpCsFixer.rst>`_
-- `@Symfony <./../../ruleSets/Symfony.rst>`_
-

+ 88 - 0
doc/rules/operator/new_with_parentheses.rst

@@ -0,0 +1,88 @@
+=============================
+Rule ``new_with_parentheses``
+=============================
+
+All instances created with ``new`` keyword must (not) be followed by
+parentheses.
+
+Configuration
+-------------
+
+``named_class``
+~~~~~~~~~~~~~~~
+
+Whether named classes should be followed by parentheses.
+
+Allowed types: ``bool``
+
+Default value: ``true``
+
+``anonymous_class``
+~~~~~~~~~~~~~~~~~~~
+
+Whether anonymous classes should be followed by parentheses.
+
+Allowed types: ``bool``
+
+Default value: ``true``
+
+Examples
+--------
+
+Example #1
+~~~~~~~~~~
+
+*Default* configuration.
+
+.. code-block:: diff
+
+   --- Original
+   +++ New
+    <?php
+
+   -$x = new X;
+   -$y = new class {};
+   +$x = new X();
+   +$y = new class() {};
+
+Example #2
+~~~~~~~~~~
+
+With configuration: ``['anonymous_class' => false]``.
+
+.. code-block:: diff
+
+   --- Original
+   +++ New
+    <?php
+
+   -$y = new class() {};
+   +$y = new class {};
+
+Example #3
+~~~~~~~~~~
+
+With configuration: ``['named_class' => false]``.
+
+.. code-block:: diff
+
+   --- Original
+   +++ New
+    <?php
+
+   -$x = new X();
+   +$x = new X;
+
+Rule sets
+---------
+
+The rule is part of the following rule sets:
+
+- `@PER <./../../ruleSets/PER.rst>`_
+- `@PER-CS <./../../ruleSets/PER-CS.rst>`_
+- `@PER-CS1.0 <./../../ruleSets/PER-CS1.0.rst>`_
+- `@PER-CS2.0 <./../../ruleSets/PER-CS2.0.rst>`_
+- `@PSR12 <./../../ruleSets/PSR12.rst>`_
+- `@PhpCsFixer <./../../ruleSets/PhpCsFixer.rst>`_
+- `@Symfony <./../../ruleSets/Symfony.rst>`_
+

+ 1 - 1
src/Fixer/ClassNotation/ClassDefinitionFixer.php

@@ -102,7 +102,7 @@ $foo = new class(){};
      * {@inheritdoc}
      * {@inheritdoc}
      *
      *
      * Must run before BracesFixer, SingleLineEmptyBodyFixer.
      * Must run before BracesFixer, SingleLineEmptyBodyFixer.
-     * Must run after NewWithBracesFixer.
+     * Must run after NewWithBracesFixer, NewWithParenthesesFixer.
      */
      */
     public function getPriority(): int
     public function getPriority(): int
     {
     {

+ 33 - 146
src/Fixer/Operator/NewWithBracesFixer.php

@@ -14,38 +14,38 @@ declare(strict_types=1);
 
 
 namespace PhpCsFixer\Fixer\Operator;
 namespace PhpCsFixer\Fixer\Operator;
 
 
-use PhpCsFixer\AbstractFixer;
+use PhpCsFixer\AbstractProxyFixer;
 use PhpCsFixer\Fixer\ConfigurableFixerInterface;
 use PhpCsFixer\Fixer\ConfigurableFixerInterface;
-use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
+use PhpCsFixer\Fixer\DeprecatedFixerInterface;
 use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
 use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
-use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
-use PhpCsFixer\FixerDefinition\CodeSample;
 use PhpCsFixer\FixerDefinition\FixerDefinition;
 use PhpCsFixer\FixerDefinition\FixerDefinition;
 use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
 use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
-use PhpCsFixer\Tokenizer\CT;
-use PhpCsFixer\Tokenizer\Token;
-use PhpCsFixer\Tokenizer\Tokens;
 
 
 /**
 /**
  * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * @deprecated
  */
  */
-final class NewWithBracesFixer extends AbstractFixer implements ConfigurableFixerInterface
+final class NewWithBracesFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface
 {
 {
+    private NewWithParenthesesFixer $newWithParenthesesFixer;
+
+    public function __construct()
+    {
+        $this->newWithParenthesesFixer = new NewWithParenthesesFixer();
+
+        parent::__construct();
+    }
+
     public function getDefinition(): FixerDefinitionInterface
     public function getDefinition(): FixerDefinitionInterface
     {
     {
+        $fixerDefinition = $this->newWithParenthesesFixer->getDefinition();
+
         return new FixerDefinition(
         return new FixerDefinition(
             'All instances created with `new` keyword must (not) be followed by braces.',
             'All instances created with `new` keyword must (not) be followed by braces.',
-            [
-                new CodeSample("<?php\n\n\$x = new X;\n\$y = new class {};\n"),
-                new CodeSample(
-                    "<?php\n\n\$y = new class() {};\n",
-                    ['anonymous_class' => false]
-                ),
-                new CodeSample(
-                    "<?php\n\n\$x = new X();\n",
-                    ['named_class' => false]
-                ),
-            ]
+            $fixerDefinition->getCodeSamples(),
+            $fixerDefinition->getDescription(),
+            $fixerDefinition->getRiskyDescription(),
         );
         );
     }
     }
 
 
@@ -56,145 +56,32 @@ final class NewWithBracesFixer extends AbstractFixer implements ConfigurableFixe
      */
      */
     public function getPriority(): int
     public function getPriority(): int
     {
     {
-        return 37;
+        return $this->newWithParenthesesFixer->getPriority();
     }
     }
 
 
-    public function isCandidate(Tokens $tokens): bool
+    public function configure(array $configuration): void
     {
     {
-        return $tokens->isTokenKindFound(T_NEW);
-    }
-
-    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
-    {
-        static $nextTokenKinds = null;
-
-        if (null === $nextTokenKinds) {
-            $nextTokenKinds = [
-                '?',
-                ';',
-                ',',
-                '(',
-                ')',
-                '[',
-                ']',
-                ':',
-                '<',
-                '>',
-                '+',
-                '-',
-                '*',
-                '/',
-                '%',
-                '&',
-                '^',
-                '|',
-                [T_CLASS],
-                [T_IS_SMALLER_OR_EQUAL],
-                [T_IS_GREATER_OR_EQUAL],
-                [T_IS_EQUAL],
-                [T_IS_NOT_EQUAL],
-                [T_IS_IDENTICAL],
-                [T_IS_NOT_IDENTICAL],
-                [T_CLOSE_TAG],
-                [T_LOGICAL_AND],
-                [T_LOGICAL_OR],
-                [T_LOGICAL_XOR],
-                [T_BOOLEAN_AND],
-                [T_BOOLEAN_OR],
-                [T_SL],
-                [T_SR],
-                [T_INSTANCEOF],
-                [T_AS],
-                [T_DOUBLE_ARROW],
-                [T_POW],
-                [T_SPACESHIP],
-                [CT::T_ARRAY_SQUARE_BRACE_OPEN],
-                [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
-                [CT::T_BRACE_CLASS_INSTANTIATION_OPEN],
-                [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE],
-            ];
-
-            if (\defined('T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG')) { // @TODO: drop condition when PHP 8.1+ is required
-                $nextTokenKinds[] = [T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG];
-                $nextTokenKinds[] = [T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG];
-            }
-        }
-
-        for ($index = $tokens->count() - 3; $index > 0; --$index) {
-            if (!$tokens[$index]->isGivenKind(T_NEW)) {
-                continue;
-            }
+        $this->newWithParenthesesFixer->configure($configuration);
 
 
-            $nextIndex = $tokens->getNextTokenOfKind($index, $nextTokenKinds);
-
-            // new anonymous class definition
-            if ($tokens[$nextIndex]->isGivenKind(T_CLASS)) {
-                $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
-
-                if ($this->configuration['anonymous_class']) {
-                    $this->ensureBracesAt($tokens, $nextIndex);
-                } else {
-                    $this->ensureNoBracesAt($tokens, $nextIndex);
-                }
-
-                continue;
-            }
-
-            // entrance into array index syntax - need to look for exit
-
-            while ($tokens[$nextIndex]->equals('[') || $tokens[$nextIndex]->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN)) {
-                $nextIndex = $tokens->findBlockEnd(Tokens::detectBlockType($tokens[$nextIndex])['type'], $nextIndex);
-                $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
-            }
-
-            if ($this->configuration['named_class']) {
-                $this->ensureBracesAt($tokens, $nextIndex);
-            } else {
-                $this->ensureNoBracesAt($tokens, $nextIndex);
-            }
-        }
+        parent::configure($configuration);
     }
     }
 
 
-    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
+    public function getSuccessorsNames(): array
     {
     {
-        return new FixerConfigurationResolver([
-            (new FixerOptionBuilder('named_class', 'Whether named classes should be followed by parentheses.'))
-                ->setAllowedTypes(['bool'])
-                ->setDefault(true)
-                ->getOption(),
-            (new FixerOptionBuilder('anonymous_class', 'Whether anonymous classes should be followed by parentheses.'))
-                ->setAllowedTypes(['bool'])
-                ->setDefault(true)
-                ->getOption(),
-        ]);
+        return [
+            $this->newWithParenthesesFixer->getName(),
+        ];
     }
     }
 
 
-    private function ensureBracesAt(Tokens $tokens, int $index): void
+    protected function createProxyFixers(): array
     {
     {
-        $token = $tokens[$index];
-
-        if (!$token->equals('(') && !$token->isObjectOperator()) {
-            $tokens->insertAt(
-                $tokens->getPrevMeaningfulToken($index) + 1,
-                [new Token('('), new Token(')')]
-            );
-        }
+        return [
+            $this->newWithParenthesesFixer,
+        ];
     }
     }
 
 
-    private function ensureNoBracesAt(Tokens $tokens, int $index): void
+    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
     {
     {
-        if (!$tokens[$index]->equals('(')) {
-            return;
-        }
-
-        $closingIndex = $tokens->getNextMeaningfulToken($index);
-
-        // constructor has arguments - braces can not be removed
-        if (!$tokens[$closingIndex]->equals(')')) {
-            return;
-        }
-
-        $tokens->clearTokenAndMergeSurroundingWhitespace($closingIndex);
-        $tokens->clearTokenAndMergeSurroundingWhitespace($index);
+        return $this->newWithParenthesesFixer->createConfigurationDefinition();
     }
     }
 }
 }

+ 200 - 0
src/Fixer/Operator/NewWithParenthesesFixer.php

@@ -0,0 +1,200 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\Fixer\Operator;
+
+use PhpCsFixer\AbstractFixer;
+use PhpCsFixer\Fixer\ConfigurableFixerInterface;
+use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
+use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
+use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
+use PhpCsFixer\FixerDefinition\CodeSample;
+use PhpCsFixer\FixerDefinition\FixerDefinition;
+use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
+use PhpCsFixer\Tokenizer\CT;
+use PhpCsFixer\Tokenizer\Token;
+use PhpCsFixer\Tokenizer\Tokens;
+
+/**
+ * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ */
+final class NewWithParenthesesFixer extends AbstractFixer implements ConfigurableFixerInterface
+{
+    public function getDefinition(): FixerDefinitionInterface
+    {
+        return new FixerDefinition(
+            'All instances created with `new` keyword must (not) be followed by parentheses.',
+            [
+                new CodeSample("<?php\n\n\$x = new X;\n\$y = new class {};\n"),
+                new CodeSample(
+                    "<?php\n\n\$y = new class() {};\n",
+                    ['anonymous_class' => false]
+                ),
+                new CodeSample(
+                    "<?php\n\n\$x = new X();\n",
+                    ['named_class' => false]
+                ),
+            ]
+        );
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * Must run before ClassDefinitionFixer.
+     */
+    public function getPriority(): int
+    {
+        return 37;
+    }
+
+    public function isCandidate(Tokens $tokens): bool
+    {
+        return $tokens->isTokenKindFound(T_NEW);
+    }
+
+    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
+    {
+        static $nextTokenKinds = null;
+
+        if (null === $nextTokenKinds) {
+            $nextTokenKinds = [
+                '?',
+                ';',
+                ',',
+                '(',
+                ')',
+                '[',
+                ']',
+                ':',
+                '<',
+                '>',
+                '+',
+                '-',
+                '*',
+                '/',
+                '%',
+                '&',
+                '^',
+                '|',
+                [T_CLASS],
+                [T_IS_SMALLER_OR_EQUAL],
+                [T_IS_GREATER_OR_EQUAL],
+                [T_IS_EQUAL],
+                [T_IS_NOT_EQUAL],
+                [T_IS_IDENTICAL],
+                [T_IS_NOT_IDENTICAL],
+                [T_CLOSE_TAG],
+                [T_LOGICAL_AND],
+                [T_LOGICAL_OR],
+                [T_LOGICAL_XOR],
+                [T_BOOLEAN_AND],
+                [T_BOOLEAN_OR],
+                [T_SL],
+                [T_SR],
+                [T_INSTANCEOF],
+                [T_AS],
+                [T_DOUBLE_ARROW],
+                [T_POW],
+                [T_SPACESHIP],
+                [CT::T_ARRAY_SQUARE_BRACE_OPEN],
+                [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
+                [CT::T_BRACE_CLASS_INSTANTIATION_OPEN],
+                [CT::T_BRACE_CLASS_INSTANTIATION_CLOSE],
+            ];
+
+            if (\defined('T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG')) { // @TODO: drop condition when PHP 8.1+ is required
+                $nextTokenKinds[] = [T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG];
+                $nextTokenKinds[] = [T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG];
+            }
+        }
+
+        for ($index = $tokens->count() - 3; $index > 0; --$index) {
+            if (!$tokens[$index]->isGivenKind(T_NEW)) {
+                continue;
+            }
+
+            $nextIndex = $tokens->getNextTokenOfKind($index, $nextTokenKinds);
+
+            // new anonymous class definition
+            if ($tokens[$nextIndex]->isGivenKind(T_CLASS)) {
+                $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
+
+                if ($this->configuration['anonymous_class']) {
+                    $this->ensureParenthesesAt($tokens, $nextIndex);
+                } else {
+                    $this->ensureNoParenthesesAt($tokens, $nextIndex);
+                }
+
+                continue;
+            }
+
+            // entrance into array index syntax - need to look for exit
+
+            while ($tokens[$nextIndex]->equals('[') || $tokens[$nextIndex]->isGivenKind(CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN)) {
+                $nextIndex = $tokens->findBlockEnd(Tokens::detectBlockType($tokens[$nextIndex])['type'], $nextIndex);
+                $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
+            }
+
+            if ($this->configuration['named_class']) {
+                $this->ensureParenthesesAt($tokens, $nextIndex);
+            } else {
+                $this->ensureNoParenthesesAt($tokens, $nextIndex);
+            }
+        }
+    }
+
+    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
+    {
+        return new FixerConfigurationResolver([
+            (new FixerOptionBuilder('named_class', 'Whether named classes should be followed by parentheses.'))
+                ->setAllowedTypes(['bool'])
+                ->setDefault(true)
+                ->getOption(),
+            (new FixerOptionBuilder('anonymous_class', 'Whether anonymous classes should be followed by parentheses.'))
+                ->setAllowedTypes(['bool'])
+                ->setDefault(true)
+                ->getOption(),
+        ]);
+    }
+
+    private function ensureParenthesesAt(Tokens $tokens, int $index): void
+    {
+        $token = $tokens[$index];
+
+        if (!$token->equals('(') && !$token->isObjectOperator()) {
+            $tokens->insertAt(
+                $tokens->getPrevMeaningfulToken($index) + 1,
+                [new Token('('), new Token(')')]
+            );
+        }
+    }
+
+    private function ensureNoParenthesesAt(Tokens $tokens, int $index): void
+    {
+        if (!$tokens[$index]->equals('(')) {
+            return;
+        }
+
+        $closingIndex = $tokens->getNextMeaningfulToken($index);
+
+        // constructor has arguments - parentheses can not be removed
+        if (!$tokens[$closingIndex]->equals(')')) {
+            return;
+        }
+
+        $tokens->clearTokenAndMergeSurroundingWhitespace($closingIndex);
+        $tokens->clearTokenAndMergeSurroundingWhitespace($index);
+    }
+}

+ 1 - 1
src/RuleSet/Sets/PSR12Set.php

@@ -42,7 +42,7 @@ final class PSR12Set extends AbstractRuleSetDescription
             'declare_equal_normalize' => true,
             'declare_equal_normalize' => true,
             'lowercase_cast' => true,
             'lowercase_cast' => true,
             'lowercase_static_reference' => true,
             'lowercase_static_reference' => true,
-            'new_with_braces' => true,
+            'new_with_parentheses' => true,
             'no_blank_lines_after_class_opening' => true,
             'no_blank_lines_after_class_opening' => true,
             'no_leading_import_slash' => true,
             'no_leading_import_slash' => true,
             'no_whitespace_in_blank_line' => true,
             'no_whitespace_in_blank_line' => true,

Some files were not shown because too many files changed in this diff