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

Issue:
Bug in NoSuperfluousPhpdocTags
#### The PHP version you are using (`$ php -v`):
=> 7.4 (running on github actions)

#### PHP CS Fixer version you are using (`$ php-cs-fixer -V`):
=> v2.16.2 Yellow Bird

#### The command you use to run PHP CS Fixer:
=> php-cs-fixer fix

#### The configuration file you are using, if any:
```php
<?php

$finder = PhpCsFixer\Finder::create()
    ->in(__DIR__.'/src')
    ->in(__DIR__.'/tests')
;

return PhpCsFixer\Config::create()
    ->setRiskyAllowed(true)
    ->setRules([
        '@PSR2' => true,
        '@Symfony' => true,
        'array_syntax' => ['syntax' => 'short'],
        'blank_line_after_opening_tag' => true,
        'concat_space' => ['spacing' => 'one'],
        'declare_strict_types' => false,
        'fully_qualified_strict_types' => true,
        'header_comment' => false,
        'lowercase_cast' => true,
        'is_null' => true,
        'magic_method_casing' => true,
        'modernize_types_casting' => true,
        'multiline_comment_opening_closing' => true,
        'native_constant_invocation' => true,
        'no_alias_functions' => true,
        'no_alternative_syntax' => true,
        'no_blank_lines_after_phpdoc' => true,
        'no_empty_comment' => true,
        'no_empty_phpdoc' => true,
        'no_extra_blank_lines' => true,
        'no_leading_import_slash' => true,
        'no_spaces_around_offset' => true,
        'no_superfluous_phpdoc_tags' => ['allow_mixed' => true],
        'no_trailing_comma_in_singleline_array' => true,
        'no_unset_cast' => true,
        'no_unused_imports' => true,
        'no_useless_else' => true,
        'no_useless_return' => true,
        'no_whitespace_in_blank_line' => true,
        'ordered_imports' => true,
        'ordered_interfaces' => true,
        'php_unit_mock' => ['target' => 'newest'],
        'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'],
        'php_unit_expectation' => ['target' => 'newest'],
        'php_unit_no_expectation_annotation' => ['target' => 'newest'],
        // 'php_unit_test_annotation' => ['style' => 'prefix'],
        'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
        'php_unit_mock_short_will_return' => true,
        'phpdoc_align' => ['align' => 'vertical'],
        'phpdoc_line_span' => ['method' => 'multi', 'property' => 'multi'],
        'phpdoc_scalar' => true,
        'phpdoc_separation' => true,
        'phpdoc_single_line_var_spacing' => true,
        'phpdoc_trim' => true,
        'phpdoc_trim_consecutive_blank_line_separation' => true,
        'phpdoc_types' => true,
        'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
        'phpdoc_var_without_name' => true,
        'short_scalar_cast' => true,
        'single_line_throw' => true,
        'single_trait_insert_per_statement' => true,
        'standardize_not_equals' => true,
        'visibility_required' => true,
        'yoda_style' => true,
        'native_function_invocation' => ['include' => ['@compiler_optimized']],
        'compact_nullable_typehint' => true,
        'declare_equal_normalize' => ['space' => 'none'],
        'function_typehint_space' => true,
        'no_leading_namespace_whitespace' => true,
        'blank_line_before_statement' => true,
        'single_quote' => true,
        'phpdoc_to_comment' => false,
        'ordered_class_elements' => ['sortAlgorithm'=>'none'],
        'class_attributes_separation' => ['elements'=>['property', 'method']],
        'array_indentation' => true,
    ])
    ->setFinder($finder)
;

```

#### If applicable, please provide minimum samples of PHP code (as plain text, not screenshots):
 * before running PHP CS Fixer (no changes):
```php
class MyEnum {
  const ONE=1;
  const TWO=2;
}

class Foo {
    /**
     * @var null|MyEnum::*
     */	
    private $numbers;

    /**
     * @var list<MyEnum::*>	
     */	
    private $numbers;
}
```

This is supported by PSALM: https://psalm.dev/docs/annotating_code/typing_in_psalm/#specifying-stringint-options-aka-enums

I dont expect these comments to be removed. Version v2.16.1 did not remove them. Version v2.16.1 does remove these comments. 

Pull request:
Improve PHPDoc types support
Related to #4913.

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 80a915145..168ec6c54 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -35,6 +35,12 @@ jobs:
             PHP_CS_FIXER_TEST_USE_LEGACY_TOKENIZER: 1
             SYMFONY_DEPRECATIONS_HELPER: 'disabled'
 
+          - operating-system: 'ubuntu-20.04'
+            php-version: '7.4'
+            job-description: 'with calculating code coverage'
+            calculate-code-coverage: 'yes'
+            phpunit-flags: '--testsuite coverage --exclude-group covers-nothing --coverage-clover build/logs/clover.xml'
+
           - operating-system: 'ubuntu-20.04'
             php-version: '7.4'
             job-description: 'with deployment'
@@ -47,9 +53,7 @@ jobs:
 
           - operating-system: 'ubuntu-20.04'
             php-version: '8.0'
-            job-description: 'with calculating code coverage'
-            calculate-code-coverage: 'yes'
-            phpunit-flags: '--testsuite coverage --exclude-group covers-nothing --coverage-clover build/logs/clover.xml'
+            composer-flags: '--ignore-platform-req=php' # as this is a version not yet officially supported by PHP CS Fixer
 
           - operating-system: 'windows-latest'
             php-version: '7.4'
diff --git a/benchmark.sh b/benchmark.sh
index f3782a391..d80169d8a 100644
--- a/benchmark.sh
+++ b/benchmark.sh
@@ -19,7 +19,6 @@ do
     git checkout "$BRANCH" > /dev/null 2>&1 &&
     git reset --hard > /dev/null 2>&1 &&
     printf '%s' "$BRANCH"
-    composer update -q
     (for _ in $(seq 1 10); do php php-cs-fixer fix --dry-run 2> /dev/null ; done) | grep -i seconds | awk '
     {
         total += $5;
diff --git a/doc/usage.rst b/doc/usage.rst
index a43f2c82d..871610372 100644
--- a/doc/usage.rst
+++ b/doc/usage.rst
@@ -25,8 +25,8 @@ The ``--format`` option for the output format. Supported formats are ``txt`` (de
 
 NOTE: the output for the following formats are generated in accordance with schemas
 
-* ``checkstyle`` follows the common `"checkstyle" XML schema </doc/schemas/fix/checkstyle.xsd>`_
-* ``json`` follows the `own JSON schema </doc/schemas/fix/schema.json>`_
+* ``checkstyle` follows the common `"checkstyle" XML schema </doc/schemas/fix/checkstyle.xsd>`_
+* ``json` follows the `own JSON schema </doc/schemas/fix/schema.json>`_
 * ``junit`` follows the `JUnit XML schema from Jenkins </doc/schemas/fix/junit-10.xsd>`_
 * ``xml`` follows the `own XML schema </doc/schemas/fix/xml.xsd>`_
 
@@ -36,9 +36,9 @@ The ``--verbose`` option will show the applied rules. When using the ``txt`` for
 
 NOTE: if there is an error like "errors reported during linting after fixing", you can use this to be even more verbose for debugging purpose
 
-* ``-v``: verbose
-* ``-vv``: very verbose
-* ``-vvv``: debug
+* `-v`: verbose
+* `-vv`: very verbose
+* `-vvv`: debug
 
 The ``--rules`` option limits the rules to apply to the
 project:
@@ -81,7 +81,7 @@ The ``--diff`` flag can be used to let the fixer output all the changes it makes
 The ``--diff-format`` option allows to specify in which format the fixer should output the changes it makes:
 
 * ``udiff``: unified diff format;
-* ``sbd``: Sebastianbergmann/diff format (default when using ``--diff`` without specifying ``diff-format``).
+* ``sbd``: Sebastianbergmann/diff format (default when using `--diff` without specifying `diff-format`).
 
 The ``--allow-risky`` option (pass ``yes`` or ``no``) allows you to set whether risky rules may run. Default value is taken from config file.
 A rule is considered risky if it could change code behaviour. By default no risky rules are run.
@@ -151,8 +151,8 @@ Note: You need to pass the config to the ``fix`` command, in order to make it wo
 
     $ php php-cs-fixer.phar list-files --config=.php-cs-fixer.dist.php | xargs -n 10 -P 8 php php-cs-fixer.phar fix --config=.php-cs-fixer.dist.php --path-mode intersection -v
 
-* ``-n`` defines how many files a single subprocess process
-* ``-P`` defines how many subprocesses the shell is allowed to spawn for parallel processing (usually similar to the number of CPUs your system has)
+* `-n` defines how many files a single subprocess process
+* `-P` defines how many subprocesses the shell is allowed to spawn for parallel processing (usually similar to the number of CPUs your system has)
 
 
 Rule descriptions
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 5c15a12e9..7b829a2ef 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -17,7 +17,6 @@
     convertWarningsToExceptions="true"
     defaultTimeLimit="10"
     enforceTimeLimit="true"
-    failOnRisky="true"
     failOnWarning="true"
     processIsolation="false"
     stopOnFailure="false"
diff --git a/src/Console/Application.php b/src/Console/Application.php
index 9d089996d..a9b2f5002 100644
--- a/src/Console/Application.php
+++ b/src/Console/Application.php
@@ -105,7 +105,8 @@ public function doRun(InputInterface $input, OutputInterface $output)
             null !== $stdErr
             && $output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE
         ) {
-            $triggeredDeprecations = Utils::getTriggeredDeprecations();
+            $triggeredDeprecations = array_unique(Utils::getTriggeredDeprecations());
+            sort($triggeredDeprecations);
             if ($triggeredDeprecations) {
                 $stdErr->writeln('');
                 $stdErr->writeln($stdErr->isDecorated() ? '<bg=yellow;fg=black;>Detected deprecations in use:</>' : 'Detected deprecations in use:');
diff --git a/src/DocBlock/TypeExpression.php b/src/DocBlock/TypeExpression.php
index 56a5c5e39..1e68589d2 100644
--- a/src/DocBlock/TypeExpression.php
+++ b/src/DocBlock/TypeExpression.php
@@ -25,31 +25,73 @@ final class TypeExpression
      * Regex to match any types, shall be used with `x` modifier.
      */
     const REGEX_TYPES = '
-    # <simple> is any non-array, non-generic, non-alternated type, eg `int` or `\Foo`
-    # <array> is array of <simple>, eg `int[]` or `\Foo[]`
-    # <generic> is generic collection type, like `array<string, int>`, `Collection<Item>` and more complex like `Collection<int, \null|SubCollection<string>>`
-    # <type> is <simple>, <array> or <generic> type, like `int`, `bool[]` or `Collection<ItemKey, ItemVal>`
-    # <types> is one or more types alternated via `|`, like `int|bool[]|Collection<ItemKey, ItemVal>`
-    (?<types>
-        (?<type>
-            (?<array>
-                (?&simple)(\[\])*
-            )
-            |
-            (?<simple>
-                [@$?]?[\\\\\w]+
-            )
-            |
-            (?<generic>
-                (?&simple)
-                <
-                    (?:(?&types),\s*)?(?:(?&types)|(?&generic))
-                >
+    (?<types> # alternation of several types separated by `|`
+        (?<type> # single type
+            \?? # optionally nullable
+            (?:
+                (?<object_like_array>
+                    array\h*\{
+                        (?<object_like_array_key>
+                            \h*[^?:\h]+\h*\??\h*:\h*(?&types)
+                        )
+                        (?:\h*,(?&object_like_array_key))*
+                    \h*\}
+                )
+                |
+                (?<callable> # callable syntax, e.g. `callable(string): bool`
+                    (?:callable|Closure)\h*\(\h*
+                        (?&types)
+                        (?:
+                            \h*,\h*
+                            (?&types)
+                        )*
+                    \h*\)
+                    (?:
+                        \h*\:\h*
+                        (?&types)
+                    )?
+                )
+                |
+                (?<generic> # generic syntax, e.g.: `array<int, \Foo\Bar>`
+                    (?&name)+
+                    \h*<\h*
+                        (?&types)
+                        (?:
+                            \h*,\h*
+                            (?&types)
+                        )*
+                    \h*>
+                )
+                |
+                (?<class_constant> # class constants with optional wildcard, e.g.: `Foo::*`, `Foo::CONST_A`, `FOO::CONST_*`
+                    (?&name)::(\*|\w+\*?)
+                )
+                |
+                (?<array> # array expression, e.g.: `string[]`, `string[][]`
+                    (?&name)(\[\])+
+                )
+                |
+                (?<constant> # single constant value (case insensitive), e.g.: 1, `\'a\'`
+                    (?i)
+                    null | true | false
+                    | [\d.]+
+                    | \'[^\']+?\' | "[^"]+?"
+                    | [@$]?(?:this | self | static)
+                    (?-i)
+                )
+                |
+                (?<name> # single type, e.g.: `null`, `int`, `\Foo\Bar`
+                    [\\\\\w-]++
+                )
             )
+            (?: # intersection
+                \h*&\h*
+                (?&type)
+            )*
         )
         (?:
-            \|
-            (?:(?&simple)|(?&array)|(?&generic))
+            \h*\|\h*
+            (?&type)
         )*
     )
     ';
@@ -84,7 +126,11 @@ public function __construct($value, $namespace, array $namespaceUses)
             );
 
             $this->types[] = $matches['type'];
-            $value = substr($value, \strlen($matches['type']) + 1);
+            $value = Preg::replace(
+                '/^'.preg_quote($matches['type'], '/').'(\h*\|\h*)?/',
+                '',
+                $value
+            );
         }
 
         $this->namespace = $namespace;
diff --git a/src/Fixer/ClassNotation/FinalInternalClassFixer.php b/src/Fixer/ClassNotation/FinalInternalClassFixer.php
index 32a9217f2..91a630e09 100644
--- a/src/Fixer/ClassNotation/FinalInternalClassFixer.php
+++ b/src/Fixer/ClassNotation/FinalInternalClassFixer.php
@@ -205,9 +205,7 @@ private function isClassCandidate(Tokens $tokens, $index)
         $tags = [];
 
         foreach ($doc->getAnnotations() as $annotation) {
-            if (1 !== Preg::match('/@\S+(?=\s|$)/', $annotation->getContent(), $matches)) {
-                continue;
-            }
+            Preg::match('/@\S+(?=\s|$)/', $annotation->getContent(), $matches);
             $tag = strtolower(substr(array_shift($matches), 1));
             foreach ($this->configuration['annotation_exclude'] as $tagStart => $true) {
                 if (0 === strpos($tag, $tagStart)) {
diff --git a/src/Fixer/ClassUsage/DateTimeImmutableFixer.php b/src/Fixer/ClassUsage/DateTimeImmutableFixer.php
index 53248c171..a43d81173 100644
--- a/src/Fixer/ClassUsage/DateTimeImmutableFixer.php
+++ b/src/Fixer/ClassUsage/DateTimeImmutableFixer.php
@@ -88,11 +88,6 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens)
                 continue;
             }
 
-            $prevIndex = $tokens->getPrevMeaningfulToken($index);
-            if ($tokens[$prevIndex]->isGivenKind(T_FUNCTION)) {
-                continue;
-            }
-
             $lowercaseContent = strtolower($token->getContent());
 
             if ('datetime' === $lowercaseContent) {
diff --git a/src/Fixer/Comment/CommentToPhpdocFixer.php b/src/Fixer/Comment/CommentToPhpdocFixer.php
index 5e463ea3c..3d8d068af 100644
--- a/src/Fixer/Comment/CommentToPhpdocFixer.php
+++ b/src/Fixer/Comment/CommentToPhpdocFixer.php
@@ -210,11 +210,7 @@ private function fixCommentMultiLine(Tokens $tokens, array $indices)
             if (false !== strpos($tokens[$index]->getContent(), '*/')) {
                 return;
             }
-            $message = $this->getMessage($tokens[$index]->getContent());
-            if ('' !== trim(substr($message, 0, 1))) {
-                $message = ' '.$message;
-            }
-            $newContent .= $indent.' *'.$message.$this->whitespacesConfig->getLineEnding();
+            $newContent .= $indent.' *'.$this->getMessage($tokens[$index]->getContent()).$this->whitespacesConfig->getLineEnding();
         }
 
         for ($index = $startIndex; $index <= $count; ++$index) {
diff --git a/src/Fixer/FunctionNotation/RegularCallableCallFixer.php b/src/Fixer/FunctionNotation/RegularCallableCallFixer.php
index 0ed8f844d..b51618932 100644
--- a/src/Fixer/FunctionNotation/RegularCallableCallFixer.php
+++ b/src/Fixer/FunctionNotation/RegularCallableCallFixer.php
@@ -118,7 +118,7 @@ private function processCall(Tokens $tokens, $index, array $arguments)
                 return; // first argument is an expression like `call_user_func("foo"."bar", ...)`, not supported!
             }
 
-            $newCallTokens = Tokens::fromCode('<?php '.substr(str_replace('\\\\', '\\', $firstArgToken->getContent()), 1, -1).'();');
+            $newCallTokens = Tokens::fromCode('<?php '.substr($firstArgToken->getContent(), 1, -1).'();');
             $newCallTokensSize = $newCallTokens->count();
             $newCallTokens->clearAt(0);
             $newCallTokens->clearRange($newCallTokensSize - 3, $newCallTokensSize - 1);
diff --git a/src/Fixer/FunctionNotation/UseArrowFunctionsFixer.php b/src/Fixer/FunctionNotation/UseArrowFunctionsFixer.php
index 74c0afb7d..46ce014ef 100644
--- a/src/Fixer/FunctionNotation/UseArrowFunctionsFixer.php
+++ b/src/Fixer/FunctionNotation/UseArrowFunctionsFixer.php
@@ -199,17 +199,11 @@ private function isMultilined(Tokens $tokens, $start, $end)
      */
     private function transform(Tokens $tokens, $index, $useStart, $useEnd, $braceOpen, $return, $semicolon, $braceClose)
     {
-        $tokensToInsert = [new Token([T_DOUBLE_ARROW, '=>'])];
-        if ($tokens->getNextMeaningfulToken($return) === $semicolon) {
-            $tokensToInsert[] = new Token([T_WHITESPACE, ' ']);
-            $tokensToInsert[] = new Token([T_STRING, 'null']);
-        }
-
         $tokens->clearRange($semicolon, $braceClose);
 
         $tokens->clearRange($braceOpen + 1, $return);
 
-        $tokens->overrideRange($braceOpen, $braceOpen, $tokensToInsert);
+        $tokens[$braceOpen] = new Token([T_DOUBLE_ARROW, '=>']);
 
         if ($useStart) {
             $tokens->clearRange($useStart, $useEnd);
diff --git a/src/Fixer/PhpUnit/PhpUnitNamespacedFixer.php b/src/Fixer/PhpUnit/PhpUnitNamespacedFixer.php
index 2a341cded..ddf57404c 100644
--- a/src/Fixer/PhpUnit/PhpUnitNamespacedFixer.php
+++ b/src/Fixer/PhpUnit/PhpUnitNamespacedFixer.php
@@ -153,7 +153,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens)
             }
 
             $prevIndex = $tokens->getPrevMeaningfulToken($currIndex);
-            if ($tokens[$prevIndex]->isGivenKind([T_CONST, T_DOUBLE_COLON])) {
+            if ($tokens[$prevIndex]->isGivenKind(T_CONST)) {
                 continue;
             }
 
diff --git a/src/Fixer/Phpdoc/PhpdocTagTypeFixer.php b/src/Fixer/Phpdoc/PhpdocTagTypeFixer.php
index d2aa63539..6289fc442 100644
--- a/src/Fixer/Phpdoc/PhpdocTagTypeFixer.php
+++ b/src/Fixer/Phpdoc/PhpdocTagTypeFixer.php
@@ -29,19 +29,6 @@
  */
 final class PhpdocTagTypeFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
 {
-    /**
-     * @internal
-     */
-    const TAG_REGEX = '/^(?:
-        (?<tag>
-            (?:@(?<tag_name>.+?)(?:\s.+)?)
-        )
-        |
-        {(?<inlined_tag>
-            (?:@(?<inlined_tag_name>.+?)(?:\s.+)?)
-        )}
-    )$/x';
-
     /**
      * {@inheritdoc}
      */
@@ -110,31 +97,23 @@ function ($tag) {
             );
 
             for ($i = 1, $max = \count($parts) - 1; $i < $max; $i += 2) {
-                if (!Preg::match(self::TAG_REGEX, $parts[$i], $matches)) {
+                if (!Preg::match('/^{?(@(.*?)(?:\s[^}]*)?)}?$/', $parts[$i], $matches)) {
                     continue;
                 }
 
-                if ('' !== $matches['tag']) {
-                    $tag = $matches['tag'];
-                    $tagName = $matches['tag_name'];
-                } else {
-                    $tag = $matches['inlined_tag'];
-                    $tagName = $matches['inlined_tag_name'];
-                }
-
-                $tagName = strtolower($tagName);
-                if (!isset($this->configuration['tags'][$tagName])) {
+                $tag = strtolower($matches[2]);
+                if (!isset($this->configuration['tags'][$tag])) {
                     continue;
                 }
 
-                if ('inline' === $this->configuration['tags'][$tagName]) {
-                    $parts[$i] = '{'.$tag.'}';
+                if ('inline' === $this->configuration['tags'][$tag]) {
+                    $parts[$i] = '{'.$matches[1].'}';
 
                     continue;
                 }
 
                 if (!$this->tagIsSurroundedByText($parts, $i)) {
-                    $parts[$i] = $tag;
+                    $parts[$i] = $matches[1];
                 }
             }
 
diff --git a/src/Fixer/Strict/StrictParamFixer.php b/src/Fixer/Strict/StrictParamFixer.php
index dba06a9fd..0f3a93632 100644
--- a/src/Fixer/Strict/StrictParamFixer.php
+++ b/src/Fixer/Strict/StrictParamFixer.php
@@ -15,7 +15,6 @@
 use PhpCsFixer\AbstractFixer;
 use PhpCsFixer\FixerDefinition\CodeSample;
 use PhpCsFixer\FixerDefinition\FixerDefinition;
-use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
 use PhpCsFixer\Tokenizer\CT;
 use PhpCsFixer\Tokenizer\Token;
 use PhpCsFixer\Tokenizer\Tokens;
@@ -69,8 +68,6 @@ public function getPriority()
      */
     protected function applyFix(\SplFileInfo $file, Tokens $tokens)
     {
-        $functionsAnalyzer = new FunctionsAnalyzer();
-
         static $map = null;
 
         if (null === $map) {
@@ -94,7 +91,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens)
             }
 
             $lowercaseContent = strtolower($token->getContent());
-            if (isset($map[$lowercaseContent]) && $functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
+            if ($token->isGivenKind(T_STRING) && isset($map[$lowercaseContent])) {
                 $this->fixFunction($tokens, $index, $map[$lowercaseContent]);
             }
         }
diff --git a/src/Utils.php b/src/Utils.php
index 39b4525a0..cc3389484 100644
--- a/src/Utils.php
+++ b/src/Utils.php
@@ -24,9 +24,6 @@
  */
 final class Utils
 {
-    /**
-     * @var array<string,true>
-     */
     private static $deprecations = [];
 
     /**
@@ -200,15 +197,12 @@ public static function triggerDeprecation($message, $exceptionClass = \RuntimeEx
             throw new $exceptionClass("{$message} This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
         }
 
-        self::$deprecations[$message] = true;
+        self::$deprecations[] = $message;
         @trigger_error($message, E_USER_DEPRECATED);
     }
 
     public static function getTriggeredDeprecations()
     {
-        $triggeredDeprecations = array_keys(self::$deprecations);
-        sort($triggeredDeprecations);
-
-        return $triggeredDeprecations;
+        return self::$deprecations;
     }
 }


Test patch:
diff --git a/tests/DocBlock/AnnotationTest.php b/tests/DocBlock/AnnotationTest.php
index c70a89cf5..25475cf2b 100644
--- a/tests/DocBlock/AnnotationTest.php
+++ b/tests/DocBlock/AnnotationTest.php
@@ -380,6 +380,106 @@ public function provideTypeParsingCases()
                 " * @return int\r\n",
                 ['int'],
             ],
+            [
+                '/** @var Collection<Foo<Bar>, Foo<Baz>>',
+                ['Collection<Foo<Bar>, Foo<Baz>>'],
+            ],
+            [
+                '/** @var int | string',
+                ['int', 'string'],
+            ],
+            [
+                '/** @var Foo::*',
+                ['Foo::*'],
+            ],
+            [
+                '/** @var Foo::A',
+                ['Foo::A'],
+            ],
+            [
+                '/** @var Foo::A|Foo::B',
+                ['Foo::A', 'Foo::B'],
+            ],
+            [
+                '/** @var Foo::A*',
+                ['Foo::A*'],
+            ],
+            [
+                '/** @var array<Foo::A*>|null',
+                ['array<Foo::A*>', 'null'],
+            ],
+            [
+                '/** @var null|true|false|1|1.5|\'a\'|"b"',
+                ['null', 'true', 'false', '1', '1.5', "'a'", '"b"'],
+            ],
+            [
+                '/** @param int | "a" | A<B<C, D>, E<F::*|G[]>> $foo */',
+                ['int', '"a"', 'A<B<C, D>, E<F::*|G[]>>'],
+            ],
+            [
+                '/** @var class-string<Foo> */',
+                ['class-string<Foo>'],
+            ],
+            [
+                '/** @var A&B */',
+                ['A&B'],
+            ],
+            [
+                '/** @var A & B */',
+                ['A & B'],
+            ],
+            [
+                '/** @var array{1: bool, 2: bool} */',
+                ['array{1: bool, 2: bool}'],
+            ],
+            [
+                '/** @var array{a: int|string, b?: bool} */',
+                ['array{a: int|string, b?: bool}'],
+            ],
+            [
+                '/** @var array{\'a\': "a", "b"?: \'b\'} */',
+                ['array{\'a\': "a", "b"?: \'b\'}'],
+            ],
+            [
+                '/** @var array { a : int | string , b ? : A<B, C> } */',
+                ['array { a : int | string , b ? : A<B, C> }'],
+            ],
+            [
+                '/** @param callable(string) $function',
+                ['callable(string)'],
+            ],
+            [
+                '/** @param callable(string): bool $function',
+                ['callable(string): bool'],
+            ],
+            [
+                '/** @param callable(array<int, string>, array<int, Foo>): bool $function',
+                ['callable(array<int, string>, array<int, Foo>): bool'],
+            ],
+            [
+                '/** @param array<int, callable(string): bool> $function',
+                ['array<int, callable(string): bool>'],
+            ],
+            [
+                '/** @param callable(string): callable(int) $function',
+                ['callable(string): callable(int)'],
+            ],
+            [
+                '/** @param callable(string) : callable(int) : bool $function',
+                ['callable(string) : callable(int) : bool'],
+            ],
+            [
+                '* @param TheCollection<callable(Foo, Bar,Baz): Foo[]>|string[]|null $x',
+                ['TheCollection<callable(Foo, Bar,Baz): Foo[]>', 'string[]', 'null'],
+            ],
+            [
+                '/** @param Closure(string) $function',
+                ['Closure(string)'],
+            ],
+            [
+                '/** @param   array  <  int   , callable  (  string  )  :   bool  > $function',
+                ['array  <  int   , callable  (  string  )  :   bool  >'],
+            ],
         ];
     }
 
diff --git a/tests/DocBlock/TypeExpressionTest.php b/tests/DocBlock/TypeExpressionTest.php
index 7eac187d2..f7f66efaa 100644
--- a/tests/DocBlock/TypeExpressionTest.php
+++ b/tests/DocBlock/TypeExpressionTest.php
@@ -58,6 +58,31 @@ public function provideGetTypesCases()
         yield ['@this', ['@this']];
         yield ['$SELF|int', ['$SELF', 'int']];
         yield ['array<string|int, string>', ['array<string|int, string>']];
+        yield ['Collection<Foo<Bar>, Foo<Baz>>', ['Collection<Foo<Bar>, Foo<Baz>>']];
+        yield ['int | string', ['int', 'string']];
+        yield ['Foo::*', ['Foo::*']];
+        yield ['Foo::A', ['Foo::A']];
+        yield ['Foo::A|Foo::B', ['Foo::A', 'Foo::B']];
+        yield ['Foo::A*', ['Foo::A*']];
+        yield ['array<Foo::A*>|null', ['array<Foo::A*>', 'null']];
+        yield ['null|true|false|1|1.5|\'a\'|"b"', ['null', 'true', 'false', '1', '1.5', "'a'", '"b"']];
+        yield ['int | "a" | A<B<C, D>, E<F::*|G[]>>', ['int', '"a"', 'A<B<C, D>, E<F::*|G[]>>']];
+        yield ['class-string<Foo>', ['class-string<Foo>']];
+        yield ['A&B', ['A&B']];
+        yield ['A & B', ['A & B']];
+        yield ['array{1: bool, 2: bool}', ['array{1: bool, 2: bool}']];
+        yield ['array{a: int|string, b?: bool}', ['array{a: int|string, b?: bool}']];
+        yield ['array{\'a\': "a", "b"?: \'b\'}', ['array{\'a\': "a", "b"?: \'b\'}']];
+        yield ['array { a : int | string , b ? : A<B, C> }', ['array { a : int | string , b ? : A<B, C> }']];
+        yield ['callable(string)', ['callable(string)']];
+        yield ['callable(string): bool', ['callable(string): bool']];
+        yield ['callable(array<int, string>, array<int, Foo>): bool', ['callable(array<int, string>, array<int, Foo>): bool']];
+        yield ['array<int, callable(string): bool>', ['array<int, callable(string): bool>']];
+        yield ['callable(string): callable(int)', ['callable(string): callable(int)']];
+        yield ['callable(string) : callable(int) : bool', ['callable(string) : callable(int) : bool']];
+        yield ['TheCollection<callable(Foo, Bar,Baz): Foo[]>|string[]|null', ['TheCollection<callable(Foo, Bar,Baz): Foo[]>', 'string[]', 'null']];
+        yield ['Closure(string)', ['Closure(string)']];
+        yield ['array  <  int   , callable  (  string  )  :   bool  >', ['array  <  int   , callable  (  string  )  :   bool  >']];
     }
 
     /**
diff --git a/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php b/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php
index c4406fb3e..b5ad2d60f 100644
--- a/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php
+++ b/tests/Fixer/ClassNotation/FinalInternalClassFixerTest.php
@@ -127,14 +127,6 @@ class class3
  * @internal
  */
 abstract class class4 {}
-',
-            ],
-            [
-                '<?php
-                    /**
-                     * @ annotation_with_space_after_at_sign
-                     */
-                    class A {}
 ',
             ],
         ];
diff --git a/tests/Fixer/ClassUsage/DateTimeImmutableFixerTest.php b/tests/Fixer/ClassUsage/DateTimeImmutableFixerTest.php
index c09caacd1..1dc5f64ba 100644
--- a/tests/Fixer/ClassUsage/DateTimeImmutableFixerTest.php
+++ b/tests/Fixer/ClassUsage/DateTimeImmutableFixerTest.php
@@ -147,15 +147,6 @@ public function provideFixCases()
             [
                 '<?php new Foo\date_create();',
             ],
-            [
-                '<?php class Foo { public function datetime() {} }',
-            ],
-            [
-                '<?php class Foo { public function date_create() {} }',
-            ],
-            [
-                '<?php namespace Foo; use DateTime; class Bar { public function datetime() {} }',
-            ],
             [
                 '<?php
                 namespace Foo;
diff --git a/tests/Fixer/Comment/CommentToPhpdocFixerTest.php b/tests/Fixer/Comment/CommentToPhpdocFixerTest.php
index 290cc8726..0e404fec0 100644
--- a/tests/Fixer/Comment/CommentToPhpdocFixerTest.php
+++ b/tests/Fixer/Comment/CommentToPhpdocFixerTest.php
@@ -311,30 +311,6 @@ public function provideTestCases()
                 ,
                 ['ignored_tags' => ['todo']],
             ],
-            [
-                '<?php // header
-                /** /@foo */
-                namespace Foo\Bar;
-',
-                '<?php // header
-                ///@foo
-                namespace Foo\Bar;
-',
-            ],
-            [
-                '<?php // header
-                /**
-                 * / @foo
-                 * / @bar
-                 */
-                namespace Foo\Bar;
-',
-                '<?php // header
-                /// @foo
-                /// @bar
-                namespace Foo\Bar;
-',
-            ],
         ];
     }
 }
diff --git a/tests/Fixer/FunctionNotation/RegularCallableCallFixerTest.php b/tests/Fixer/FunctionNotation/RegularCallableCallFixerTest.php
index f27d6a24b..7b6a20d34 100644
--- a/tests/Fixer/FunctionNotation/RegularCallableCallFixerTest.php
+++ b/tests/Fixer/FunctionNotation/RegularCallableCallFixerTest.php
@@ -205,16 +205,6 @@ function call_user_func($foo){}
                 }
             ',
         ];
-
-        yield 'function name with escaped slash' => [
-            '<?php \pack(...$args);',
-            '<?php call_user_func_array("\\\\pack", $args);',
-        ];
-
-        yield 'function call_user_func_array with leading slash' => [
-            '<?php \pack(...$args);',
-            '<?php \call_user_func_array("\\\\pack", $args);',
-        ];
     }
 
     /**
diff --git a/tests/Fixer/FunctionNotation/UseArrowFunctionsFixerTest.php b/tests/Fixer/FunctionNotation/UseArrowFunctionsFixerTest.php
index 697e79b09..d418e3ee6 100644
--- a/tests/Fixer/FunctionNotation/UseArrowFunctionsFixerTest.php
+++ b/tests/Fixer/FunctionNotation/UseArrowFunctionsFixerTest.php
@@ -177,18 +177,6 @@ public function provideFixCases()
     };
 EXPECTED
             ],
-            [
-                '<?php $testDummy = fn () => null;',
-                '<?php $testDummy = function () { return; };',
-            ],
-            [
-                '<?php $testDummy = fn () => null ;',
-                '<?php $testDummy = function () { return ; };',
-            ],
-            [
-                '<?php $testDummy = fn () => null/* foo */;',
-                '<?php $testDummy = function () { return/* foo */; };',
-            ],
         ];
     }
 }
diff --git a/tests/Fixer/PhpUnit/PhpUnitNamespacedFixerTest.php b/tests/Fixer/PhpUnit/PhpUnitNamespacedFixerTest.php
index 77c432c8d..057067e3b 100644
--- a/tests/Fixer/PhpUnit/PhpUnitNamespacedFixerTest.php
+++ b/tests/Fixer/PhpUnit/PhpUnitNamespacedFixerTest.php
@@ -242,13 +242,6 @@ final class MyTest extends TestCase
                     const PHPUNIT_FOO = "foo";
                 }',
             ],
-            [
-                '<?php
-                final class MyTest extends TestCase
-                {
-                    const FOO = Bar::PHPUNIT_FOO;
-                }',
-            ],
         ];
     }
 
diff --git a/tests/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixerTest.php b/tests/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixerTest.php
index fd017d195..c29d76ec6 100644
--- a/tests/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixerTest.php
+++ b/tests/Fixer/Phpdoc/NoSuperfluousPhpdocTagsFixerTest.php
@@ -1068,6 +1068,20 @@ class Foo {
      * @return foo:bar
      */
     public function foo($foo) {}
+}',
+            ],
+            'with constant values as type' => [
+                '<?php
+class Foo {
+    /**
+     * @var Bar::A|Bar::B|Baz::*|null
+     */
+    private $foo;
+
+    /**
+     * @var 1|\'a\'|\'b\'
+     */
+    private $bar;
 }',
             ],
         ];
diff --git a/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php b/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php
index c23c3c736..dc777502e 100644
--- a/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php
+++ b/tests/Fixer/Phpdoc/PhpdocTagTypeFixerTest.php
@@ -343,12 +343,6 @@ public function provideFixCases()
  *
  * {@inheritdoc}
  *
- */',
-            ],
-            [
-                '<?php
-/**
- * @return array{0: float, 1: int}
  */',
             ],
         ];
diff --git a/tests/Fixer/Strict/StrictParamFixerTest.php b/tests/Fixer/Strict/StrictParamFixerTest.php
index fcc44c87a..e977c0797 100644
--- a/tests/Fixer/Strict/StrictParamFixerTest.php
+++ b/tests/Fixer/Strict/StrictParamFixerTest.php
@@ -43,12 +43,6 @@ public function provideFixCases()
     in_array(1, $a, false);
     in_array(1, $a, $useStrict);',
             ],
-            [
-                '<?php class Foo
-                {
-                    public function in_array($needle, $haystack) {}
-                }',
-            ],
             [
                 '<?php
     in_array(1, $a, true);',