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

keradus / PHP-CS-Fixer / 17253322895

26 Aug 2025 11:52PM UTC coverage: 94.753% (+0.008%) from 94.745%
17253322895

push

github

keradus
add to git-blame-ignore-revs

28316 of 29884 relevant lines covered (94.75%)

45.64 hits per line

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

97.87
/src/Fixer/ClassNotation/PhpdocReadonlyClassCommentToKeywordFixer.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\ClassNotation;
16

17
use PhpCsFixer\AbstractFixer;
18
use PhpCsFixer\DocBlock\DocBlock;
19
use PhpCsFixer\FixerDefinition\FixerDefinition;
20
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
21
use PhpCsFixer\FixerDefinition\VersionSpecification;
22
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
23
use PhpCsFixer\Tokenizer\Token;
24
use PhpCsFixer\Tokenizer\Tokens;
25

26
/**
27
 * @author Marcel Behrmann <marcel@behrmann.dev>
28
 *
29
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
30
 */
31
final class PhpdocReadonlyClassCommentToKeywordFixer extends AbstractFixer
32
{
33
    /**
34
     * {@inheritdoc}
35
     *
36
     * Must run before NoEmptyPhpdocFixer, NoExtraBlankLinesFixer, PhpdocAlignFixer.
37
     * Must run after AlignMultilineCommentFixer, CommentToPhpdocFixer, PhpdocIndentFixer, PhpdocScalarFixer, PhpdocToCommentFixer, PhpdocTypesFixer.
38
     */
39
    public function getPriority(): int
40
    {
41
        return 4;
1✔
42
    }
43

44
    public function isCandidate(Tokens $tokens): bool
45
    {
46
        return \PHP_VERSION_ID >= 8_02_00 && $tokens->isTokenKindFound(\T_DOC_COMMENT);
8✔
47
    }
48

49
    public function isRisky(): bool
50
    {
51
        return true;
1✔
52
    }
53

54
    public function getDefinition(): FixerDefinitionInterface
55
    {
56
        return new FixerDefinition(
3✔
57
            'Converts readonly comment on classes to the readonly keyword.',
3✔
58
            [
3✔
59
                new VersionSpecificCodeSample(
3✔
60
                    <<<EOT
3✔
61
                            <?php
62
                            /** @readonly */
63
                            class C {
64
                            }\n
65
                        EOT,
3✔
66
                    new VersionSpecification(8_02_00)
3✔
67
                ),
3✔
68
            ],
3✔
69
            null,
3✔
70
            'If classes marked with `@readonly` annotation were extended anyway, applying this fixer may break the inheritance for their child classes.'
3✔
71
        );
3✔
72
    }
73

74
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
75
    {
76
        foreach ($tokens as $index => $token) {
8✔
77
            if (!$token->isGivenKind(\T_DOC_COMMENT)) {
8✔
78
                continue;
8✔
79
            }
80

81
            $doc = new DocBlock($token->getContent());
8✔
82

83
            $annotations = $doc->getAnnotationsOfType('readonly');
8✔
84

85
            if (0 === \count($annotations)) {
8✔
86
                continue;
6✔
87
            }
88

89
            foreach ($annotations as $annotation) {
7✔
90
                $annotation->remove();
7✔
91
            }
92

93
            $mainIndex = $index;
7✔
94
            $index = $tokens->getNextMeaningfulToken($index);
7✔
95
            $addReadonly = true;
7✔
96

97
            while ($tokens[$index]->isGivenKind([
7✔
98
                \T_ABSTRACT,
7✔
99
                \T_FINAL,
7✔
100
                \T_PRIVATE,
7✔
101
                \T_PUBLIC,
7✔
102
                \T_PROTECTED,
7✔
103
                \T_READONLY,
7✔
104
            ])) {
7✔
105
                if ($tokens[$index]->isGivenKind(\T_READONLY)) {
3✔
106
                    $addReadonly = false;
1✔
107
                }
108

109
                $index = $tokens->getNextMeaningfulToken($index);
3✔
110
            }
111

112
            if (!$tokens[$index]->isGivenKind(\T_CLASS)) {
7✔
113
                continue;
×
114
            }
115

116
            if ($addReadonly) {
7✔
117
                $tokens->insertAt($index, [new Token([\T_READONLY, 'readonly']), new Token([\T_WHITESPACE, ' '])]);
6✔
118
            }
119

120
            $newContent = $doc->getContent();
7✔
121

122
            if ('' === $newContent) {
7✔
123
                $tokens->clearTokenAndMergeSurroundingWhitespace($mainIndex);
2✔
124

125
                continue;
2✔
126
            }
127

128
            $tokens[$mainIndex] = new Token([\T_DOC_COMMENT, $doc->getContent()]);
5✔
129
        }
130
    }
131
}
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