• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

keradus / PHP-CS-Fixer / 17252691116

26 Aug 2025 11:09PM UTC coverage: 94.743% (-0.01%) from 94.755%
17252691116

push

github

keradus
chore: apply phpdoc_tag_no_named_arguments

28313 of 29884 relevant lines covered (94.74%)

45.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.4
/src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz RumiƄski <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\Fixer\Phpdoc;
16

17
use PhpCsFixer\AbstractFixer;
18
use PhpCsFixer\DocBlock\DocBlock;
19
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
20
use PhpCsFixer\Fixer\ConfigurableFixerTrait;
21
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
22
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
23
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
24
use PhpCsFixer\FixerDefinition\CodeSample;
25
use PhpCsFixer\FixerDefinition\FixerDefinition;
26
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
27
use PhpCsFixer\Tokenizer\Token;
28
use PhpCsFixer\Tokenizer\Tokens;
29
use PhpCsFixer\Tokenizer\TokensAnalyzer;
30
use PhpCsFixer\Utils;
31
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
32
use Symfony\Component\OptionsResolver\Options;
33

34
/**
35
 * @phpstan-type _AutogeneratedInputConfiguration array{
36
 *  replacements?: array<string, string>,
37
 * }
38
 * @phpstan-type _AutogeneratedComputedConfiguration array{
39
 *  replacements: array<string, string>,
40
 * }
41
 *
42
 * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
43
 *
44
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
45
 */
46
final class PhpdocReturnSelfReferenceFixer extends AbstractFixer implements ConfigurableFixerInterface
47
{
48
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
49
    use ConfigurableFixerTrait;
50

51
    /**
52
     * @var non-empty-list<string>
53
     */
54
    private const TO_TYPES = [
55
        '$this',
56
        'static',
57
        'self',
58
    ];
59

60
    public function getDefinition(): FixerDefinitionInterface
61
    {
62
        return new FixerDefinition(
3✔
63
            'The type of `@return` annotations of methods returning a reference to itself must the configured one.',
3✔
64
            [
3✔
65
                new CodeSample(
3✔
66
                    '<?php
3✔
67
class Sample
68
{
69
    /**
70
     * @return this
71
     */
72
    public function test1()
73
    {
74
        return $this;
75
    }
76

77
    /**
78
     * @return $self
79
     */
80
    public function test2()
81
    {
82
        return $this;
83
    }
84
}
85
'
3✔
86
                ),
3✔
87
                new CodeSample(
3✔
88
                    '<?php
3✔
89
class Sample
90
{
91
    /**
92
     * @return this
93
     */
94
    public function test1()
95
    {
96
        return $this;
97
    }
98

99
    /**
100
     * @return $self
101
     */
102
    public function test2()
103
    {
104
        return $this;
105
    }
106
}
107
',
3✔
108
                    ['replacements' => ['this' => 'self']]
3✔
109
                ),
3✔
110
            ]
3✔
111
        );
3✔
112
    }
113

114
    public function isCandidate(Tokens $tokens): bool
115
    {
116
        return \count($tokens) > 10 && $tokens->isAllTokenKindsFound([\T_DOC_COMMENT, \T_FUNCTION]) && $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
15✔
117
    }
118

119
    /**
120
     * {@inheritdoc}
121
     *
122
     * Must run before NoSuperfluousPhpdocTagsFixer, PhpdocAlignFixer.
123
     * Must run after AlignMultilineCommentFixer, CommentToPhpdocFixer, PhpdocIndentFixer, PhpdocScalarFixer, PhpdocToCommentFixer, PhpdocTypesFixer.
124
     */
125
    public function getPriority(): int
126
    {
127
        return 10;
1✔
128
    }
129

130
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
131
    {
132
        $tokensAnalyzer = new TokensAnalyzer($tokens);
13✔
133

134
        foreach ($tokensAnalyzer->getClassyElements() as $index => $element) {
13✔
135
            if ('method' === $element['type']) {
13✔
136
                $this->fixMethod($tokens, $index);
13✔
137
            }
138
        }
139
    }
140

141
    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
142
    {
143
        $default = [
26✔
144
            'this' => '$this',
26✔
145
            '@this' => '$this',
26✔
146
            '$self' => 'self',
26✔
147
            '@self' => 'self',
26✔
148
            '$static' => 'static',
26✔
149
            '@static' => 'static',
26✔
150
        ];
26✔
151

152
        return new FixerConfigurationResolver([
26✔
153
            (new FixerOptionBuilder('replacements', 'Mapping between replaced return types with new ones.'))
26✔
154
                ->setAllowedTypes(['array<string, string>'])
26✔
155
                ->setNormalizer(static function (Options $options, array $value) use ($default): array {
26✔
156
                    $normalizedValue = [];
26✔
157

158
                    foreach ($value as $from => $to) {
26✔
159
                        if (\is_string($from)) {
26✔
160
                            $from = strtolower($from);
26✔
161
                        }
162

163
                        if (!isset($default[$from])) {
26✔
164
                            throw new InvalidOptionsException(\sprintf(
1✔
165
                                'Unknown key "%s", expected any of %s.',
1✔
166
                                \gettype($from).'#'.$from,
1✔
167
                                Utils::naturalLanguageJoin(array_keys($default))
1✔
168
                            ));
1✔
169
                        }
170

171
                        if (!\in_array($to, self::TO_TYPES, true)) {
26✔
172
                            throw new InvalidOptionsException(\sprintf(
1✔
173
                                'Unknown value "%s", expected any of %s.',
1✔
174
                                \is_object($to) ? \get_class($to) : \gettype($to).(\is_resource($to) ? '' : '#'.$to),
1✔
175
                                Utils::naturalLanguageJoin(self::TO_TYPES)
1✔
176
                            ));
1✔
177
                        }
178

179
                        $normalizedValue[$from] = $to;
26✔
180
                    }
181

182
                    return $normalizedValue;
26✔
183
                })
26✔
184
                ->setDefault($default)
26✔
185
                ->getOption(),
26✔
186
        ]);
26✔
187
    }
188

189
    private function fixMethod(Tokens $tokens, int $index): void
190
    {
191
        // find PHPDoc of method (if any)
192
        while (true) {
13✔
193
            $tokenIndex = $tokens->getPrevMeaningfulToken($index);
13✔
194
            if (!$tokens[$tokenIndex]->isGivenKind([\T_STATIC, \T_FINAL, \T_ABSTRACT, \T_PRIVATE, \T_PROTECTED, \T_PUBLIC])) {
13✔
195
                break;
13✔
196
            }
197

198
            $index = $tokenIndex;
11✔
199
        }
200

201
        $docIndex = $tokens->getPrevNonWhitespace($index);
13✔
202
        if (!$tokens[$docIndex]->isGivenKind(\T_DOC_COMMENT)) {
13✔
203
            return;
1✔
204
        }
205

206
        // find @return
207
        $docBlock = new DocBlock($tokens[$docIndex]->getContent());
13✔
208
        $returnsBlock = $docBlock->getAnnotationsOfType('return');
13✔
209

210
        if (0 === \count($returnsBlock)) {
13✔
211
            return; // no return annotation found
×
212
        }
213

214
        $returnsBlock = $returnsBlock[0];
13✔
215
        $types = $returnsBlock->getTypes();
13✔
216

217
        if (0 === \count($types)) {
13✔
218
            return; // no return type(s) found
×
219
        }
220

221
        $newTypes = [];
13✔
222

223
        foreach ($types as $type) {
13✔
224
            $newTypes[] = $this->configuration['replacements'][strtolower($type)] ?? $type;
13✔
225
        }
226

227
        if ($types === $newTypes) {
13✔
228
            return;
13✔
229
        }
230

231
        $returnsBlock->setTypes($newTypes);
12✔
232
        $tokens[$docIndex] = new Token([\T_DOC_COMMENT, $docBlock->getContent()]);
12✔
233
    }
234
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc