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

keradus / PHP-CS-Fixer / 16999983712

15 Aug 2025 09:42PM UTC coverage: 94.75% (-0.09%) from 94.839%
16999983712

push

github

keradus
ci: more self-fixing checks on lowest/highest PHP

28263 of 29829 relevant lines covered (94.75%)

45.88 hits per line

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

97.82
/src/Fixer/Basic/BracesPositionFixer.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\Basic;
16

17
use PhpCsFixer\AbstractFixer;
18
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
19
use PhpCsFixer\Fixer\ConfigurableFixerTrait;
20
use PhpCsFixer\Fixer\Indentation;
21
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
22
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
23
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
24
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
25
use PhpCsFixer\FixerDefinition\CodeSample;
26
use PhpCsFixer\FixerDefinition\FixerDefinition;
27
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
28
use PhpCsFixer\Preg;
29
use PhpCsFixer\Tokenizer\CT;
30
use PhpCsFixer\Tokenizer\FCT;
31
use PhpCsFixer\Tokenizer\Token;
32
use PhpCsFixer\Tokenizer\Tokens;
33
use PhpCsFixer\Tokenizer\TokensAnalyzer;
34

35
/**
36
 * @phpstan-type _AutogeneratedInputConfiguration array{
37
 *  allow_single_line_anonymous_functions?: bool,
38
 *  allow_single_line_empty_anonymous_classes?: bool,
39
 *  anonymous_classes_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
40
 *  anonymous_functions_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
41
 *  classes_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
42
 *  control_structures_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
43
 *  functions_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
44
 * }
45
 * @phpstan-type _AutogeneratedComputedConfiguration array{
46
 *  allow_single_line_anonymous_functions: bool,
47
 *  allow_single_line_empty_anonymous_classes: bool,
48
 *  anonymous_classes_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
49
 *  anonymous_functions_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
50
 *  classes_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
51
 *  control_structures_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
52
 *  functions_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
53
 * }
54
 *
55
 * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
56
 */
57
final class BracesPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
58
{
59
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
60
    use ConfigurableFixerTrait;
61

62
    use Indentation;
63

64
    /**
65
     * @internal
66
     */
67
    public const NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END = 'next_line_unless_newline_at_signature_end';
68

69
    /**
70
     * @internal
71
     */
72
    public const SAME_LINE = 'same_line';
73

74
    private const CONTROL_STRUCTURE_TOKENS = [\T_DECLARE, \T_DO, \T_ELSE, \T_ELSEIF, \T_FINALLY, \T_FOR, \T_FOREACH, \T_IF, \T_WHILE, \T_TRY, \T_CATCH, \T_SWITCH, FCT::T_MATCH];
75

76
    public function getDefinition(): FixerDefinitionInterface
77
    {
78
        return new FixerDefinition(
3✔
79
            'Braces must be placed as configured.',
3✔
80
            [
3✔
81
                new CodeSample(
3✔
82
                    '<?php
3✔
83
class Foo {
84
}
85

86
function foo() {
87
}
88

89
$foo = function()
90
{
91
};
92

93
if (foo())
94
{
95
    bar();
96
}
97

98
$foo = new class
99
{
100
};
101
'
3✔
102
                ),
3✔
103
                new CodeSample(
3✔
104
                    '<?php
3✔
105
if (foo()) {
106
    bar();
107
}
108
',
3✔
109
                    ['control_structures_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
3✔
110
                ),
3✔
111
                new CodeSample(
3✔
112
                    '<?php
3✔
113
function foo()
114
{
115
}
116
',
3✔
117
                    ['functions_opening_brace' => self::SAME_LINE]
3✔
118
                ),
3✔
119
                new CodeSample(
3✔
120
                    '<?php
3✔
121
$foo = function () {
122
};
123
',
3✔
124
                    ['anonymous_functions_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
3✔
125
                ),
3✔
126
                new CodeSample(
3✔
127
                    '<?php
3✔
128
class Foo
129
{
130
}
131
',
3✔
132
                    ['classes_opening_brace' => self::SAME_LINE]
3✔
133
                ),
3✔
134
                new CodeSample(
3✔
135
                    '<?php
3✔
136
$foo = new class {
137
};
138
',
3✔
139
                    ['anonymous_classes_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
3✔
140
                ),
3✔
141
                new CodeSample(
3✔
142
                    '<?php
3✔
143
$foo = new class { };
144
$bar = new class { private $baz; };
145
',
3✔
146
                    ['allow_single_line_empty_anonymous_classes' => true]
3✔
147
                ),
3✔
148
                new CodeSample(
3✔
149
                    '<?php
3✔
150
$foo = function () { return true; };
151
$bar = function () { $result = true;
152
    return $result; };
153
',
3✔
154
                    ['allow_single_line_anonymous_functions' => true]
3✔
155
                ),
3✔
156
            ]
3✔
157
        );
3✔
158
    }
159

160
    public function isCandidate(Tokens $tokens): bool
161
    {
162
        return $tokens->isTokenKindFound('{');
60✔
163
    }
164

165
    /**
166
     * {@inheritdoc}
167
     *
168
     * Must run before SingleLineEmptyBodyFixer, StatementIndentationFixer.
169
     * Must run after ControlStructureBracesFixer, MultilinePromotedPropertiesFixer, NoMultipleStatementsPerLineFixer.
170
     */
171
    public function getPriority(): int
172
    {
173
        return -2;
1✔
174
    }
175

176
    /** @protected */
177
    public function createConfigurationDefinition(): FixerConfigurationResolverInterface
178
    {
179
        return new FixerConfigurationResolver([
69✔
180
            (new FixerOptionBuilder('control_structures_opening_brace', 'The position of the opening brace of control structures‘ body.'))
69✔
181
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
182
                ->setDefault(self::SAME_LINE)
69✔
183
                ->getOption(),
69✔
184
            (new FixerOptionBuilder('functions_opening_brace', 'The position of the opening brace of functions‘ body.'))
69✔
185
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
186
                ->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
69✔
187
                ->getOption(),
69✔
188
            (new FixerOptionBuilder('anonymous_functions_opening_brace', 'The position of the opening brace of anonymous functions‘ body.'))
69✔
189
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
190
                ->setDefault(self::SAME_LINE)
69✔
191
                ->getOption(),
69✔
192
            (new FixerOptionBuilder('classes_opening_brace', 'The position of the opening brace of classes‘ body.'))
69✔
193
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
194
                ->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
69✔
195
                ->getOption(),
69✔
196
            (new FixerOptionBuilder('anonymous_classes_opening_brace', 'The position of the opening brace of anonymous classes‘ body.'))
69✔
197
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
198
                ->setDefault(self::SAME_LINE)
69✔
199
                ->getOption(),
69✔
200
            (new FixerOptionBuilder('allow_single_line_empty_anonymous_classes', 'Allow anonymous classes to have opening and closing braces on the same line.'))
69✔
201
                ->setAllowedTypes(['bool'])
69✔
202
                ->setDefault(true)
69✔
203
                ->getOption(),
69✔
204
            (new FixerOptionBuilder('allow_single_line_anonymous_functions', 'Allow anonymous functions to have opening and closing braces on the same line.'))
69✔
205
                ->setAllowedTypes(['bool'])
69✔
206
                ->setDefault(true)
69✔
207
                ->getOption(),
69✔
208
        ]);
69✔
209
    }
210

211
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
212
    {
213
        $classyTokens = Token::getClassyTokenKinds();
60✔
214
        $tokensAnalyzer = new TokensAnalyzer($tokens);
60✔
215

216
        $allowSingleLineUntil = null;
60✔
217

218
        foreach ($tokens as $index => $token) {
60✔
219
            $allowSingleLine = false;
60✔
220
            $allowSingleLineIfEmpty = false;
60✔
221

222
            if ($token->isGivenKind($classyTokens)) {
60✔
223
                $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
15✔
224

225
                if ($tokensAnalyzer->isAnonymousClass($index)) {
15✔
226
                    $allowSingleLineIfEmpty = true === $this->configuration['allow_single_line_empty_anonymous_classes'];
4✔
227
                    $positionOption = 'anonymous_classes_opening_brace';
4✔
228
                } else {
229
                    $positionOption = 'classes_opening_brace';
12✔
230
                }
231
            } elseif ($token->isGivenKind(\T_FUNCTION)) {
60✔
232
                $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{', ';', [CT::T_PROPERTY_HOOK_BRACE_OPEN]]);
25✔
233

234
                if (!$tokens[$openBraceIndex]->equals('{')) {
25✔
235
                    continue;
2✔
236
                }
237

238
                if ($tokensAnalyzer->isLambda($index)) {
23✔
239
                    $allowSingleLine = true === $this->configuration['allow_single_line_anonymous_functions'];
4✔
240
                    $positionOption = 'anonymous_functions_opening_brace';
4✔
241
                } else {
242
                    $positionOption = 'functions_opening_brace';
21✔
243
                }
244
            } elseif ($token->isGivenKind(self::CONTROL_STRUCTURE_TOKENS)) {
60✔
245
                $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
30✔
246
                $openBraceIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
30✔
247

248
                if (!$tokens[$openBraceIndex]->equals('{')) {
30✔
249
                    continue;
4✔
250
                }
251

252
                $positionOption = 'control_structures_opening_brace';
30✔
253
            } elseif ($token->isGivenKind(\T_VARIABLE)) {
60✔
254
                // handle default value - explicitly skip array as default value
255
                $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($index);
47✔
256
                if ($tokens[$nextMeaningfulIndex]->equals('=')) {
47✔
257
                    $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($nextMeaningfulIndex);
9✔
258

259
                    if ($tokens[$nextMeaningfulIndex]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
9✔
260
                        $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $nextMeaningfulIndex);
1✔
261
                    } elseif ($tokens[$nextMeaningfulIndex]->isGivenKind(\T_ARRAY)) {
9✔
262
                        $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($nextMeaningfulIndex);
1✔
263
                        if ($tokens[$nextMeaningfulIndex]->equals('(')) {
1✔
264
                            $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextMeaningfulIndex);
1✔
265
                        }
266
                    }
267
                }
268

269
                $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{', ';', '.', [CT::T_CURLY_CLOSE], [CT::T_PROPERTY_HOOK_BRACE_OPEN], [\T_ENCAPSED_AND_WHITESPACE], [\T_CLOSE_TAG]]);
47✔
270

271
                if (!$tokens[$openBraceIndex]->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_OPEN)) {
47✔
272
                    continue;
46✔
273
                }
274

275
                $closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PROPERTY_HOOK, $openBraceIndex);
5✔
276
                if (!$tokens->isPartialCodeMultiline($openBraceIndex, $closeBraceIndex)) {
5✔
277
                    continue;
1✔
278
                }
279

280
                $positionOption = 'control_structures_opening_brace';
4✔
281
            } elseif ($token->isGivenKind(\T_STRING)) {
60✔
282
                $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
54✔
283
                $openBraceIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
54✔
284
                if (!$tokens[$openBraceIndex]->equals('{')) {
54✔
285
                    continue;
46✔
286
                }
287

288
                $prevIndex = $tokens->getPrevMeaningfulToken($index);
27✔
289
                if (!$tokens[$prevIndex]->equalsAny(['}', ';', [CT::T_ATTRIBUTE_CLOSE], [CT::T_PROPERTY_HOOK_BRACE_OPEN]])) {
27✔
290
                    continue;
27✔
291
                }
292
                $allowSingleLine = true === $this->configuration['allow_single_line_anonymous_functions'];
4✔
293
                $positionOption = 'control_structures_opening_brace';
4✔
294
            } else {
295
                continue;
60✔
296
            }
297

298
            $closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openBraceIndex);
60✔
299

300
            $addNewlinesInsideBraces = true;
60✔
301
            if ($allowSingleLine || $allowSingleLineIfEmpty || $index < $allowSingleLineUntil) {
60✔
302
                $addNewlinesInsideBraces = false;
11✔
303

304
                for ($indexInsideBraces = $openBraceIndex + 1; $indexInsideBraces < $closeBraceIndex; ++$indexInsideBraces) {
11✔
305
                    $tokenInsideBraces = $tokens[$indexInsideBraces];
10✔
306

307
                    if (
308
                        ($allowSingleLineIfEmpty && !$tokenInsideBraces->isWhitespace() && !$tokenInsideBraces->isComment())
10✔
309
                        || ($tokenInsideBraces->isWhitespace() && Preg::match('/\R/', $tokenInsideBraces->getContent()))
10✔
310
                    ) {
311
                        $addNewlinesInsideBraces = true;
9✔
312

313
                        break;
9✔
314
                    }
315
                }
316

317
                if (!$addNewlinesInsideBraces && null === $allowSingleLineUntil) {
11✔
318
                    $allowSingleLineUntil = $closeBraceIndex;
3✔
319
                }
320
            }
321

322
            if (
323
                $addNewlinesInsideBraces
60✔
324
                && !$this->isFollowedByNewLine($tokens, $openBraceIndex)
60✔
325
                && !$this->hasCommentOnSameLine($tokens, $openBraceIndex)
60✔
326
                && !$tokens[$tokens->getNextMeaningfulToken($openBraceIndex)]->isGivenKind(\T_CLOSE_TAG)
60✔
327
            ) {
328
                $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
2✔
329
                if ($tokens->ensureWhitespaceAtIndex($openBraceIndex + 1, 0, $whitespace)) {
2✔
330
                    ++$closeBraceIndex;
×
331
                }
332
            }
333

334
            $whitespace = ' ';
60✔
335
            if (self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END === $this->configuration[$positionOption]) {
60✔
336
                $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $index);
40✔
337

338
                $previousTokenIndex = $openBraceIndex;
40✔
339
                do {
340
                    $previousTokenIndex = $tokens->getPrevMeaningfulToken($previousTokenIndex);
40✔
341
                } while ($tokens[$previousTokenIndex]->isGivenKind([CT::T_TYPE_COLON, CT::T_NULLABLE_TYPE, \T_STRING, \T_NS_SEPARATOR, CT::T_ARRAY_TYPEHINT, \T_STATIC, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, \T_CALLABLE, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE]));
40✔
342

343
                if ($tokens[$previousTokenIndex]->equals(')')) {
40✔
344
                    if ($tokens[--$previousTokenIndex]->isComment()) {
33✔
345
                        --$previousTokenIndex;
×
346
                    }
347
                    if (
348
                        $tokens[$previousTokenIndex]->isWhitespace()
33✔
349
                        && Preg::match('/\R/', $tokens[$previousTokenIndex]->getContent())
33✔
350
                    ) {
351
                        $whitespace = ' ';
13✔
352
                    }
353
                }
354
            }
355

356
            $moveBraceToIndex = null;
60✔
357

358
            if (' ' === $whitespace) {
60✔
359
                $previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($openBraceIndex);
41✔
360
                for ($indexBeforeOpenBrace = $openBraceIndex - 1; $indexBeforeOpenBrace > $previousMeaningfulIndex; --$indexBeforeOpenBrace) {
41✔
361
                    if (!$tokens[$indexBeforeOpenBrace]->isComment()) {
41✔
362
                        continue;
41✔
363
                    }
364

365
                    $tokenBeforeOpenBrace = $tokens[--$indexBeforeOpenBrace];
4✔
366
                    if ($tokenBeforeOpenBrace->isWhitespace()) {
4✔
367
                        $moveBraceToIndex = $indexBeforeOpenBrace;
3✔
368
                    } elseif ($indexBeforeOpenBrace === $previousMeaningfulIndex) {
1✔
369
                        $moveBraceToIndex = $previousMeaningfulIndex + 1;
1✔
370
                    }
371
                }
372
            } elseif (!$tokens[$openBraceIndex - 1]->isWhitespace() || !Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
28✔
373
                for ($indexAfterOpenBrace = $openBraceIndex + 1; $indexAfterOpenBrace < $closeBraceIndex; ++$indexAfterOpenBrace) {
22✔
374
                    if ($tokens[$indexAfterOpenBrace]->isWhitespace() && Preg::match('/\R/', $tokens[$indexAfterOpenBrace]->getContent())) {
22✔
375
                        break;
22✔
376
                    }
377

378
                    if ($tokens[$indexAfterOpenBrace]->isComment() && !str_starts_with($tokens[$indexAfterOpenBrace]->getContent(), '/*')) {
3✔
379
                        $moveBraceToIndex = $indexAfterOpenBrace + 1;
3✔
380
                    }
381
                }
382
            }
383

384
            if (null !== $moveBraceToIndex) {
60✔
385
                $movedToken = clone $tokens[$openBraceIndex];
7✔
386

387
                $delta = $openBraceIndex < $moveBraceToIndex ? 1 : -1;
7✔
388

389
                if ($tokens[$openBraceIndex + $delta]->isWhitespace()) {
7✔
390
                    if (-1 === $delta && Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
6✔
391
                        $content = Preg::replace('/^(\h*?\R)?\h*/', '', $tokens[$openBraceIndex + 1]->getContent());
2✔
392
                        if ('' !== $content) {
2✔
393
                            $tokens[$openBraceIndex + 1] = new Token([\T_WHITESPACE, $content]);
1✔
394
                        } else {
395
                            $tokens->clearAt($openBraceIndex + 1);
1✔
396
                        }
397
                    } elseif ($tokens[$openBraceIndex - 1]->isWhitespace()) {
4✔
398
                        $tokens->clearAt($openBraceIndex - 1);
3✔
399
                    }
400
                }
401

402
                for ($i = $openBraceIndex; $i !== $moveBraceToIndex; $i += $delta) {
7✔
403
                    $siblingToken = $tokens[$i + $delta];
7✔
404
                    $tokens[$i] = $siblingToken;
7✔
405
                }
406

407
                $tokens[$i] = $movedToken;
7✔
408

409
                if ($tokens[$openBraceIndex]->isWhitespace() && $tokens[$openBraceIndex + 1]->isWhitespace()) {
7✔
410
                    $tokens[$openBraceIndex] = new Token([
4✔
411
                        \T_WHITESPACE,
4✔
412
                        $tokens[$openBraceIndex]->getContent().$tokens[$openBraceIndex + 1]->getContent(),
4✔
413
                    ]);
4✔
414
                    $tokens->clearAt($openBraceIndex + 1);
4✔
415
                }
416

417
                $openBraceIndex = $moveBraceToIndex;
7✔
418
            }
419

420
            if ($tokens->ensureWhitespaceAtIndex($openBraceIndex - 1, 1, $whitespace)) {
60✔
421
                ++$closeBraceIndex;
5✔
422
                if (null !== $allowSingleLineUntil) {
5✔
423
                    ++$allowSingleLineUntil;
×
424
                }
425
            }
426

427
            if (
428
                !$addNewlinesInsideBraces
60✔
429
                || $tokens[$tokens->getPrevMeaningfulToken($closeBraceIndex)]->isGivenKind(\T_OPEN_TAG)
60✔
430
            ) {
431
                continue;
3✔
432
            }
433

434
            $prevIndex = $closeBraceIndex - 1;
60✔
435
            while ($tokens->isEmptyAt($prevIndex)) {
60✔
436
                --$prevIndex;
×
437
            }
438

439
            $prevToken = $tokens[$prevIndex];
60✔
440

441
            if ($prevToken->isWhitespace() && Preg::match('/\R/', $prevToken->getContent())) {
60✔
442
                continue;
60✔
443
            }
444

445
            $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
5✔
446
            $tokens->ensureWhitespaceAtIndex($prevIndex, 1, $whitespace);
5✔
447
        }
448
    }
449

450
    private function findParenthesisEnd(Tokens $tokens, int $structureTokenIndex): int
451
    {
452
        $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
56✔
453
        $nextToken = $tokens[$nextIndex];
56✔
454

455
        // return if next token is not opening parenthesis
456
        if (!$nextToken->equals('(')) {
56✔
457
            return $structureTokenIndex;
32✔
458
        }
459

460
        return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
53✔
461
    }
462

463
    private function isFollowedByNewLine(Tokens $tokens, int $index): bool
464
    {
465
        for (++$index, $max = \count($tokens) - 1; $index < $max; ++$index) {
60✔
466
            $token = $tokens[$index];
60✔
467
            if (!$token->isComment()) {
60✔
468
                return $token->isWhitespace() && Preg::match('/\R/', $token->getContent());
60✔
469
            }
470
        }
471

472
        return false;
×
473
    }
474

475
    private function hasCommentOnSameLine(Tokens $tokens, int $index): bool
476
    {
477
        $token = $tokens[$index + 1];
7✔
478

479
        if ($token->isWhitespace() && !Preg::match('/\R/', $token->getContent())) {
7✔
480
            $token = $tokens[$index + 2];
7✔
481
        }
482

483
        return $token->isComment();
7✔
484
    }
485
}
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