• 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.15
/src/Fixer/Comment/SingleLineCommentStyleFixer.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\Comment;
16

17
use PhpCsFixer\AbstractFixer;
18
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
19
use PhpCsFixer\Fixer\ConfigurableFixerTrait;
20
use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
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\Preg;
28
use PhpCsFixer\Tokenizer\Token;
29
use PhpCsFixer\Tokenizer\Tokens;
30

31
/**
32
 * @phpstan-type _AutogeneratedInputConfiguration array{
33
 *  comment_types?: list<'asterisk'|'hash'>,
34
 * }
35
 * @phpstan-type _AutogeneratedComputedConfiguration array{
36
 *  comment_types: list<'asterisk'|'hash'>,
37
 * }
38
 *
39
 * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
40
 *
41
 * @author Filippo Tessarotto <zoeslam@gmail.com>
42
 *
43
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
44
 */
45
final class SingleLineCommentStyleFixer extends AbstractFixer implements ConfigurableFixerInterface
46
{
47
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
48
    use ConfigurableFixerTrait;
49

50
    private bool $asteriskEnabled;
51

52
    private bool $hashEnabled;
53

54
    public function getDefinition(): FixerDefinitionInterface
55
    {
56
        return new FixerDefinition(
3✔
57
            'Single-line comments and multi-line comments with only one line of actual content should use the `//` syntax.',
3✔
58
            [
3✔
59
                new CodeSample(
3✔
60
                    <<<'PHP'
3✔
61
                        <?php
62
                        /* asterisk comment */
63
                        $a = 1;
64

65
                        # hash comment
66
                        $b = 2;
67

68
                        /*
69
                         * multi-line
70
                         * comment
71
                         */
72
                        $c = 3;
73

74
                        PHP
3✔
75
                ),
3✔
76
                new CodeSample(
3✔
77
                    <<<'PHP'
3✔
78
                        <?php
79
                        /* first comment */
80
                        $a = 1;
81

82
                        /*
83
                         * second comment
84
                         */
85
                        $b = 2;
86

87
                        /*
88
                         * third
89
                         * comment
90
                         */
91
                        $c = 3;
92

93
                        PHP,
3✔
94
                    ['comment_types' => ['asterisk']]
3✔
95
                ),
3✔
96
                new CodeSample(
3✔
97
                    "<?php # comment\n",
3✔
98
                    ['comment_types' => ['hash']]
3✔
99
                ),
3✔
100
            ]
3✔
101
        );
3✔
102
    }
103

104
    /**
105
     * {@inheritdoc}
106
     *
107
     * Must run after HeaderCommentFixer, NoUselessReturnFixer, PhpdocToCommentFixer.
108
     */
109
    public function getPriority(): int
110
    {
111
        return -31;
1✔
112
    }
113

114
    public function isCandidate(Tokens $tokens): bool
115
    {
116
        return $tokens->isTokenKindFound(\T_COMMENT);
37✔
117
    }
118

119
    protected function configurePostNormalisation(): void
120
    {
121
        $this->asteriskEnabled = \in_array('asterisk', $this->configuration['comment_types'], true);
47✔
122
        $this->hashEnabled = \in_array('hash', $this->configuration['comment_types'], true);
47✔
123
    }
124

125
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
126
    {
127
        foreach ($tokens as $index => $token) {
35✔
128
            if (!$token->isGivenKind(\T_COMMENT)) {
35✔
129
                continue;
35✔
130
            }
131

132
            $content = $token->getContent();
35✔
133

134
            /** @TODO PHP 8.0 - no more need for `?: ''` */
135
            $commentContent = substr($content, 2, -2) ?: ''; // @phpstan-ignore-line
35✔
136

137
            if ($this->hashEnabled && str_starts_with($content, '#')) {
35✔
138
                if (isset($content[1]) && '[' === $content[1]) {
7✔
UNCOV
139
                    continue; // This might be an attribute on PHP8, do not change
×
140
                }
141

142
                $tokens[$index] = new Token([$token->getId(), '//'.substr($content, 1)]);
7✔
143

144
                continue;
7✔
145
            }
146

147
            if (
148
                !$this->asteriskEnabled
35✔
149
                || str_contains($commentContent, '?>')
35✔
150
                || !str_starts_with($content, '/*')
35✔
151
                || Preg::match('/[^\s\*].*\R.*[^\s\*]/s', $commentContent)
35✔
152
            ) {
153
                continue;
31✔
154
            }
155

156
            $nextTokenIndex = $index + 1;
21✔
157
            if (isset($tokens[$nextTokenIndex])) {
21✔
158
                $nextToken = $tokens[$nextTokenIndex];
15✔
159
                if (!$nextToken->isWhitespace() || !Preg::match('/\R/', $nextToken->getContent())) {
15✔
160
                    continue;
6✔
161
                }
162

163
                $tokens[$nextTokenIndex] = new Token([$nextToken->getId(), ltrim($nextToken->getContent(), " \t")]);
10✔
164
            }
165

166
            $content = '//';
17✔
167
            if (Preg::match('/[^\s\*]/', $commentContent)) {
17✔
168
                $content = '// '.Preg::replace('/[\s\*]*([^\s\*](?:.+[^\s\*])?)[\s\*]*/', '\1', $commentContent);
15✔
169
            }
170
            $tokens[$index] = new Token([$token->getId(), $content]);
17✔
171
        }
172
    }
173

174
    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
175
    {
176
        return new FixerConfigurationResolver([
47✔
177
            (new FixerOptionBuilder('comment_types', 'List of comment types to fix.'))
47✔
178
                ->setAllowedTypes(['string[]'])
47✔
179
                ->setAllowedValues([new AllowedValueSubset(['asterisk', 'hash'])])
47✔
180
                ->setDefault(['asterisk', 'hash'])
47✔
181
                ->getOption(),
47✔
182
        ]);
47✔
183
    }
184
}
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