• 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.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\IndentationTrait;
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
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
58
 */
59
final class BracesPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
60
{
61
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
62
    use ConfigurableFixerTrait;
63

64
    use IndentationTrait;
65

66
    /**
67
     * @internal
68
     */
69
    public const NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END = 'next_line_unless_newline_at_signature_end';
70

71
    /**
72
     * @internal
73
     */
74
    public const SAME_LINE = 'same_line';
75

76
    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];
77

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

88
function foo() {
89
}
90

91
$foo = function()
92
{
93
};
94

95
if (foo())
96
{
97
    bar();
98
}
99

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

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

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

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

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

218
        $allowSingleLineUntil = null;
60✔
219

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

315
                        break;
9✔
316
                    }
317
                }
318

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

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

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

340
                $previousTokenIndex = $openBraceIndex;
40✔
341
                do {
342
                    $previousTokenIndex = $tokens->getPrevMeaningfulToken($previousTokenIndex);
40✔
343
                } 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✔
344

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

358
            $moveBraceToIndex = null;
60✔
359

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

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

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

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

389
                $delta = $openBraceIndex < $moveBraceToIndex ? 1 : -1;
7✔
390

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

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

409
                $tokens[$i] = $movedToken;
7✔
410

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

419
                $openBraceIndex = $moveBraceToIndex;
7✔
420
            }
421

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

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

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

441
            $prevToken = $tokens[$prevIndex];
60✔
442

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

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

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

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

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

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

474
        return false;
×
475
    }
476

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

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

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