Repository: FriendsOfPHP/PHP-CS-Fixer (php)

Issue:
DoctrineAnnotationBracesFixer false positive
## Bug report

I configured the `syntax` option to `with_braces` but now this fixer has unexpected sideeffects on psalm annotations:

```
        /**
-        * @psalm-param numeric-string $amount
+        * @psalm()-param numeric-string $amount
         */
```


Pull request:
DoctrineAnnotationBracesFixer false positive
Fixes #5120 

Patch:
diff --git a/doc/rules/doctrine_annotation/doctrine_annotation_array_assignment.rst b/doc/rules/doctrine_annotation/doctrine_annotation_array_assignment.rst
index e71dd1f66..999dc8bf0 100644
--- a/doc/rules/doctrine_annotation/doctrine_annotation_array_assignment.rst
+++ b/doc/rules/doctrine_annotation/doctrine_annotation_array_assignment.rst
@@ -14,7 +14,7 @@ List of tags that must not be treated as Doctrine Annotations.
 
 Allowed types: ``array``
 
-Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'fix', 'FIXME', 'fixme', 'override']``
+Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'psalm', 'phpstan', 'fix', 'FIXME', 'fixme', 'override']``
 
 ``operator``
 ~~~~~~~~~~~~
diff --git a/doc/rules/doctrine_annotation/doctrine_annotation_braces.rst b/doc/rules/doctrine_annotation/doctrine_annotation_braces.rst
index a0f029be5..8852b7798 100644
--- a/doc/rules/doctrine_annotation/doctrine_annotation_braces.rst
+++ b/doc/rules/doctrine_annotation/doctrine_annotation_braces.rst
@@ -14,7 +14,7 @@ List of tags that must not be treated as Doctrine Annotations.
 
 Allowed types: ``array``
 
-Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'fix', 'FIXME', 'fixme', 'override']``
+Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'psalm', 'phpstan', 'fix', 'FIXME', 'fixme', 'override']``
 
 ``syntax``
 ~~~~~~~~~~
diff --git a/doc/rules/doctrine_annotation/doctrine_annotation_indentation.rst b/doc/rules/doctrine_annotation/doctrine_annotation_indentation.rst
index 2e5f774f7..62f8d32bf 100644
--- a/doc/rules/doctrine_annotation/doctrine_annotation_indentation.rst
+++ b/doc/rules/doctrine_annotation/doctrine_annotation_indentation.rst
@@ -14,7 +14,7 @@ List of tags that must not be treated as Doctrine Annotations.
 
 Allowed types: ``array``
 
-Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'fix', 'FIXME', 'fixme', 'override']``
+Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'psalm', 'phpstan', 'fix', 'FIXME', 'fixme', 'override']``
 
 ``indent_mixed_lines``
 ~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/rules/doctrine_annotation/doctrine_annotation_spaces.rst b/doc/rules/doctrine_annotation/doctrine_annotation_spaces.rst
index a253fa1d7..046a4c3ee 100644
--- a/doc/rules/doctrine_annotation/doctrine_annotation_spaces.rst
+++ b/doc/rules/doctrine_annotation/doctrine_annotation_spaces.rst
@@ -21,7 +21,7 @@ List of tags that must not be treated as Doctrine Annotations.
 
 Allowed types: ``array``
 
-Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'fix', 'FIXME', 'fixme', 'override']``
+Default value: ``['abstract', 'access', 'code', 'deprec', 'encode', 'exception', 'final', 'ingroup', 'inheritdoc', 'inheritDoc', 'magic', 'name', 'toc', 'tutorial', 'private', 'static', 'staticvar', 'staticVar', 'throw', 'api', 'author', 'category', 'copyright', 'deprecated', 'example', 'filesource', 'global', 'ignore', 'internal', 'license', 'link', 'method', 'package', 'param', 'property', 'property-read', 'property-write', 'return', 'see', 'since', 'source', 'subpackage', 'throws', 'todo', 'TODO', 'usedBy', 'uses', 'var', 'version', 'after', 'afterClass', 'backupGlobals', 'backupStaticAttributes', 'before', 'beforeClass', 'codeCoverageIgnore', 'codeCoverageIgnoreStart', 'codeCoverageIgnoreEnd', 'covers', 'coversDefaultClass', 'coversNothing', 'dataProvider', 'depends', 'expectedException', 'expectedExceptionCode', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp', 'group', 'large', 'medium', 'preserveGlobalState', 'requires', 'runTestsInSeparateProcesses', 'runInSeparateProcess', 'small', 'test', 'testdox', 'ticket', 'uses', 'SuppressWarnings', 'noinspection', 'package_version', 'enduml', 'startuml', 'psalm', 'phpstan', 'fix', 'FIXME', 'fixme', 'override']``
 
 ``around_parentheses``
 ~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/AbstractDoctrineAnnotationFixer.php b/src/AbstractDoctrineAnnotationFixer.php
index a47eb667b..f1ef7d5b5 100644
--- a/src/AbstractDoctrineAnnotationFixer.php
+++ b/src/AbstractDoctrineAnnotationFixer.php
@@ -184,6 +184,12 @@ protected function createConfigurationDefinition()
                     'enduml',
                     'startuml',
 
+                    // Psalm
+                    'psalm',
+
+                    // PHPStan
+                    'phpstan',
+
                     // other
                     'fix',
                     'FIXME',
diff --git a/src/Documentation/DocumentationGenerator.php b/src/Documentation/DocumentationGenerator.php
index 273e36c8a..2e288181c 100644
--- a/src/Documentation/DocumentationGenerator.php
+++ b/src/Documentation/DocumentationGenerator.php
@@ -14,7 +14,8 @@
 
 use PhpCsFixer\AbstractFixer;
 use PhpCsFixer\Console\Command\HelpCommand;
-use PhpCsFixer\Differ\FullDiffer;
+use PhpCsFixer\Diff\GeckoPackages\DiffOutputBuilder\UnifiedDiffOutputBuilder;
+use PhpCsFixer\Diff\v2_0\Differ;
 use PhpCsFixer\Fixer\Basic\Psr0Fixer;
 use PhpCsFixer\Fixer\ConfigurableFixerInterface;
 use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
@@ -41,7 +42,7 @@
 final class DocumentationGenerator
 {
     /**
-     * @var FullDiffer
+     * @var Differ
      */
     private $differ;
 
@@ -49,7 +50,11 @@ final class DocumentationGenerator
 
     public function __construct()
     {
-        $this->differ = new FullDiffer();
+        $this->differ = new Differ(new UnifiedDiffOutputBuilder([
+            'contextLines' => 1024, // number large enough to have all lines in diff
+            'fromFile' => 'Original',
+            'toFile' => 'New',
+        ]));
 
         $this->path = \dirname(__DIR__, 2).'/doc';
     }


Test patch:
diff --git a/tests/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixerTest.php b/tests/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixerTest.php
index 7a75770c7..0268686f5 100644
--- a/tests/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixerTest.php
+++ b/tests/Fixer/DoctrineAnnotation/DoctrineAnnotationBracesFixerTest.php
@@ -253,6 +253,14 @@ public function provideFixWithBracesCases()
  * @enduml
  * @startuml
  *
+ * // Psalm
+ * @psalm
+ * @psalm-param
+ *
+ * // PHPStan
+ * @phpstan
+ * @phpstan-param
+ *
  * // other
  * @fix
  * @FIXME
@@ -525,6 +533,15 @@ public function provideFixWithoutBracesCases()
  * @enduml()
  * @startuml()
  *
+ * // Psalm
+ * @psalm()
+ * @psalm-param()
+ *
+ * // PHPStan
+ * @phpstan()
+ * @psalm-param()
+ *
+ *
  * // other
  * @fix()
  * @FIXME()
diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php
index e2658921c..1fefeb7df 100644
--- a/tests/IntegrationTest.php
+++ b/tests/IntegrationTest.php
@@ -41,7 +41,7 @@ protected static function getFixturesDir()
      */
     protected static function getTempFile()
     {
-        return tempnam(sys_get_temp_dir(), 'PHP-CS-Fixer');
+        return self::getFixturesDir().\DIRECTORY_SEPARATOR.'.tmp.php';
     }
 
     /**