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

keradus / PHP-CS-Fixer / 17377459942

01 Sep 2025 12:19PM UTC coverage: 94.684% (-0.009%) from 94.693%
17377459942

push

github

web-flow
chore: `Tokens::offsetSet` - explicit validation of input (#9004)

1 of 5 new or added lines in 1 file covered. (20.0%)

306 existing lines in 60 files now uncovered.

28390 of 29984 relevant lines covered (94.68%)

45.5 hits per line

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

98.67
/src/Fixer/ClassNotation/SelfStaticAccessorFixer.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\FixerDefinition\CodeSample;
19
use PhpCsFixer\FixerDefinition\FixerDefinition;
20
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
21
use PhpCsFixer\FixerDefinition\VersionSpecification;
22
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
23
use PhpCsFixer\Tokenizer\FCT;
24
use PhpCsFixer\Tokenizer\Token;
25
use PhpCsFixer\Tokenizer\Tokens;
26
use PhpCsFixer\Tokenizer\TokensAnalyzer;
27

28
/**
29
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
30
 */
31
final class SelfStaticAccessorFixer extends AbstractFixer
32
{
33
    private const CLASSY_TYPES = [\T_CLASS, FCT::T_ENUM];
34
    private const CLASSY_TOKENS_OF_INTEREST = [[\T_CLASS], [FCT::T_ENUM]];
35
    private TokensAnalyzer $tokensAnalyzer;
36

37
    public function getDefinition(): FixerDefinitionInterface
38
    {
39
        return new FixerDefinition(
3✔
40
            'Inside an enum or `final`/anonymous class, `self` should be preferred over `static`.',
3✔
41
            [
3✔
42
                new CodeSample(
3✔
43
                    <<<'PHP'
3✔
44
                        <?php
45
                        final class Sample
46
                        {
47
                            private static $A = 1;
48

49
                            public function getBar()
50
                            {
51
                                return static::class.static::test().static::$A;
52
                            }
53

54
                            private static function test()
55
                            {
56
                                return 'test';
57
                            }
58
                        }
59

60
                        PHP
3✔
61
                ),
3✔
62
                new CodeSample(
3✔
63
                    <<<'PHP'
3✔
64
                        <?php
65
                        final class Foo
66
                        {
67
                            public function bar()
68
                            {
69
                                return new static();
70
                            }
71
                        }
72

73
                        PHP
3✔
74
                ),
3✔
75
                new CodeSample(
3✔
76
                    <<<'PHP'
3✔
77
                        <?php
78
                        final class Foo
79
                        {
80
                            public function isBar()
81
                            {
82
                                return $foo instanceof static;
83
                            }
84
                        }
85

86
                        PHP
3✔
87
                ),
3✔
88
                new CodeSample(
3✔
89
                    <<<'PHP'
3✔
90
                        <?php
91
                        $a = new class() {
92
                            public function getBar()
93
                            {
94
                                return static::class;
95
                            }
96
                        };
97

98
                        PHP
3✔
99
                ),
3✔
100
                new VersionSpecificCodeSample(
3✔
101
                    <<<'PHP'
3✔
102
                        <?php
103
                        enum Foo
104
                        {
105
                            public const A = 123;
106

107
                            public static function bar(): void
108
                            {
109
                                echo static::A;
110
                            }
111
                        }
112

113
                        PHP,
3✔
114
                    new VersionSpecification(8_01_00)
3✔
115
                ),
3✔
116
            ]
3✔
117
        );
3✔
118
    }
119

120
    public function isCandidate(Tokens $tokens): bool
121
    {
122
        return $tokens->isTokenKindFound(\T_STATIC)
19✔
123
            && $tokens->isAnyTokenKindsFound(self::CLASSY_TYPES)
19✔
124
            && $tokens->isAnyTokenKindsFound([\T_DOUBLE_COLON, \T_NEW, \T_INSTANCEOF]);
19✔
125
    }
126

127
    /**
128
     * {@inheritdoc}
129
     *
130
     * Must run after FinalClassFixer, FinalInternalClassFixer, FunctionToConstantFixer, PhpUnitTestCaseStaticMethodCallsFixer.
131
     */
132
    public function getPriority(): int
133
    {
134
        return -10;
1✔
135
    }
136

137
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
138
    {
139
        $this->tokensAnalyzer = new TokensAnalyzer($tokens);
18✔
140
        $classyIndex = $tokens->getNextTokenOfKind(0, self::CLASSY_TOKENS_OF_INTEREST);
18✔
141

142
        while (null !== $classyIndex) {
18✔
143
            if ($tokens[$classyIndex]->isGivenKind(\T_CLASS)) {
18✔
144
                $modifiers = $this->tokensAnalyzer->getClassyModifiers($classyIndex);
16✔
145

146
                if (
147
                    isset($modifiers['final'])
16✔
148
                    || $this->tokensAnalyzer->isAnonymousClass($classyIndex)
16✔
149
                ) {
150
                    $classyIndex = $this->fixClassy($tokens, $classyIndex);
14✔
151
                }
152
            } else {
153
                $classyIndex = $this->fixClassy($tokens, $classyIndex);
3✔
154
            }
155

156
            $classyIndex = $tokens->getNextTokenOfKind($classyIndex, self::CLASSY_TOKENS_OF_INTEREST);
18✔
157
        }
158
    }
159

160
    private function fixClassy(Tokens $tokens, int $index): int
161
    {
162
        $index = $tokens->getNextTokenOfKind($index, ['{']);
16✔
163
        $classOpenCount = 1;
16✔
164

165
        while ($classOpenCount > 0) {
16✔
166
            ++$index;
16✔
167

168
            if ($tokens[$index]->equals('{')) {
16✔
169
                ++$classOpenCount;
16✔
170

171
                continue;
16✔
172
            }
173

174
            if ($tokens[$index]->equals('}')) {
16✔
175
                --$classOpenCount;
16✔
176

177
                continue;
16✔
178
            }
179

180
            if ($tokens[$index]->isGivenKind(\T_FUNCTION)) {
16✔
181
                // do not fix inside lambda
182
                if ($this->tokensAnalyzer->isLambda($index)) {
12✔
183
                    // figure out where the lambda starts
184
                    $index = $tokens->getNextTokenOfKind($index, ['{']);
2✔
185
                    $openCount = 1;
2✔
186

187
                    do {
188
                        $index = $tokens->getNextTokenOfKind($index, ['}', '{', [\T_CLASS]]);
2✔
189
                        if ($tokens[$index]->equals('}')) {
2✔
190
                            --$openCount;
2✔
191
                        } elseif ($tokens[$index]->equals('{')) {
1✔
UNCOV
192
                            ++$openCount;
×
193
                        } else {
194
                            $index = $this->fixClassy($tokens, $index);
1✔
195
                        }
196
                    } while ($openCount > 0);
2✔
197
                }
198

199
                continue;
12✔
200
            }
201

202
            if ($tokens[$index]->isGivenKind([\T_NEW, \T_INSTANCEOF])) {
16✔
203
                $index = $tokens->getNextMeaningfulToken($index);
9✔
204

205
                if ($tokens[$index]->isGivenKind(\T_STATIC)) {
9✔
206
                    $tokens[$index] = new Token([\T_STRING, 'self']);
7✔
207
                }
208

209
                continue;
9✔
210
            }
211

212
            if (!$tokens[$index]->isGivenKind(\T_STATIC)) {
16✔
213
                continue;
16✔
214
            }
215

216
            $staticIndex = $index;
13✔
217
            $index = $tokens->getNextMeaningfulToken($index);
13✔
218

219
            if (!$tokens[$index]->isGivenKind(\T_DOUBLE_COLON)) {
13✔
220
                continue;
7✔
221
            }
222

223
            $tokens[$staticIndex] = new Token([\T_STRING, 'self']);
10✔
224
        }
225

226
        return $index;
16✔
227
    }
228
}
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