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

keradus / PHP-CS-Fixer / 22042339290

15 Feb 2026 08:14PM UTC coverage: 92.957% (-0.2%) from 93.171%
22042339290

push

github

keradus
test: check PHP env in CI jobs

29302 of 31522 relevant lines covered (92.96%)

44.04 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\Future;
29
use PhpCsFixer\Preg;
30
use PhpCsFixer\Tokenizer\CT;
31
use PhpCsFixer\Tokenizer\FCT;
32
use PhpCsFixer\Tokenizer\Token;
33
use PhpCsFixer\Tokenizer\Tokens;
34
use PhpCsFixer\Tokenizer\TokensAnalyzer;
35

36
/**
37
 * @phpstan-type _AutogeneratedInputConfiguration array{
38
 *  allow_single_line_anonymous_functions?: bool,
39
 *  allow_single_line_empty_anonymous_classes?: bool,
40
 *  anonymous_classes_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
41
 *  anonymous_functions_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
42
 *  classes_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
43
 *  control_structures_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
44
 *  functions_opening_brace?: 'next_line_unless_newline_at_signature_end'|'same_line',
45
 * }
46
 * @phpstan-type _AutogeneratedComputedConfiguration array{
47
 *  allow_single_line_anonymous_functions: bool,
48
 *  allow_single_line_empty_anonymous_classes: bool,
49
 *  anonymous_classes_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
50
 *  anonymous_functions_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
51
 *  classes_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
52
 *  control_structures_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
53
 *  functions_opening_brace: 'next_line_unless_newline_at_signature_end'|'same_line',
54
 * }
55
 *
56
 * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
57
 *
58
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
59
 */
60
final class BracesPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
61
{
62
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
63
    use ConfigurableFixerTrait;
64

65
    use IndentationTrait;
66

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

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

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

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

90
                        function foo() {
91
                        }
92

93
                        $foo = function()
94
                        {
95
                        };
96

97
                        if (foo())
98
                        {
99
                            bar();
100
                        }
101

102
                        $foo = new class
103
                        {
104
                        };
105

106
                        PHP,
3✔
107
                ),
3✔
108
                new CodeSample(
3✔
109
                    <<<'PHP'
3✔
110
                        <?php
111
                        if (foo()) {
112
                            bar();
113
                        }
114

115
                        PHP,
3✔
116
                    ['control_structures_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END],
3✔
117
                ),
3✔
118
                new CodeSample(
3✔
119
                    <<<'PHP'
3✔
120
                        <?php
121
                        function foo()
122
                        {
123
                        }
124

125
                        PHP,
3✔
126
                    ['functions_opening_brace' => self::SAME_LINE],
3✔
127
                ),
3✔
128
                new CodeSample(
3✔
129
                    <<<'PHP'
3✔
130
                        <?php
131
                        $foo = function () {
132
                        };
133

134
                        PHP,
3✔
135
                    ['anonymous_functions_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END],
3✔
136
                ),
3✔
137
                new CodeSample(
3✔
138
                    <<<'PHP'
3✔
139
                        <?php
140
                        class Foo
141
                        {
142
                        }
143

144
                        PHP,
3✔
145
                    ['classes_opening_brace' => self::SAME_LINE],
3✔
146
                ),
3✔
147
                new CodeSample(
3✔
148
                    <<<'PHP'
3✔
149
                        <?php
150
                        $foo = new class {
151
                        };
152

153
                        PHP,
3✔
154
                    ['anonymous_classes_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END],
3✔
155
                ),
3✔
156
                new CodeSample(
3✔
157
                    <<<'PHP'
3✔
158
                        <?php
159
                        $foo = new class { };
160
                        $bar = new class { private $baz; };
161

162
                        PHP,
3✔
163
                    ['allow_single_line_empty_anonymous_classes' => true],
3✔
164
                ),
3✔
165
                new CodeSample(
3✔
166
                    <<<'PHP'
3✔
167
                        <?php
168
                        $foo = function () { return true; };
169
                        $bar = function () { $result = true;
170
                            return $result; };
171

172
                        PHP,
3✔
173
                    ['allow_single_line_anonymous_functions' => true],
3✔
174
                ),
3✔
175
            ],
3✔
176
        );
3✔
177
    }
178

179
    public function isCandidate(Tokens $tokens): bool
180
    {
181
        return $tokens->isTokenKindFound('{');
60✔
182
    }
183

184
    /**
185
     * {@inheritdoc}
186
     *
187
     * Must run before SingleLineEmptyBodyFixer, StatementIndentationFixer.
188
     * Must run after ControlStructureBracesFixer, MultilinePromotedPropertiesFixer, NoMultipleStatementsPerLineFixer.
189
     */
190
    public function getPriority(): int
191
    {
192
        return -2;
1✔
193
    }
194

195
    /** @protected */
196
    public function createConfigurationDefinition(): FixerConfigurationResolverInterface
197
    {
198
        return new FixerConfigurationResolver([
69✔
199
            (new FixerOptionBuilder('control_structures_opening_brace', 'The position of the opening brace of control structures‘ body.'))
69✔
200
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
201
                ->setDefault(self::SAME_LINE)
69✔
202
                ->getOption(),
69✔
203
            (new FixerOptionBuilder('functions_opening_brace', 'The position of the opening brace of functions‘ body.'))
69✔
204
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
205
                ->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
69✔
206
                ->getOption(),
69✔
207
            (new FixerOptionBuilder('anonymous_functions_opening_brace', 'The position of the opening brace of anonymous functions‘ body.'))
69✔
208
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
209
                ->setDefault(self::SAME_LINE)
69✔
210
                ->getOption(),
69✔
211
            (new FixerOptionBuilder('classes_opening_brace', 'The position of the opening brace of classes‘ body.'))
69✔
212
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
213
                ->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
69✔
214
                ->getOption(),
69✔
215
            (new FixerOptionBuilder('anonymous_classes_opening_brace', 'The position of the opening brace of anonymous classes‘ body.'))
69✔
216
                ->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
69✔
217
                ->setDefault(self::SAME_LINE)
69✔
218
                ->getOption(),
69✔
219
            (new FixerOptionBuilder('allow_single_line_empty_anonymous_classes', 'Allow anonymous classes to have opening and closing braces on the same line.'))
69✔
220
                ->setAllowedTypes(['bool'])
69✔
221
                ->setDefault(true)
69✔
222
                ->getOption(),
69✔
223
            (new FixerOptionBuilder('allow_single_line_anonymous_functions', 'Allow anonymous functions to have opening and closing braces on the same line.'))
69✔
224
                ->setAllowedTypes(['bool'])
69✔
225
                ->setDefault(Future::getV4OrV3(false, true))
69✔
226
                ->getOption(),
69✔
227
        ]);
69✔
228
    }
229

230
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
231
    {
232
        $classyTokens = Token::getClassyTokenKinds();
60✔
233
        $tokensAnalyzer = new TokensAnalyzer($tokens);
60✔
234

235
        $allowSingleLineUntil = null;
60✔
236

237
        foreach ($tokens as $index => $token) {
60✔
238
            $allowSingleLine = false;
60✔
239
            $allowSingleLineIfEmpty = false;
60✔
240

241
            if ($token->isGivenKind($classyTokens)) {
60✔
242
                $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
15✔
243

244
                if ($tokensAnalyzer->isAnonymousClass($index)) {
15✔
245
                    $allowSingleLineIfEmpty = true === $this->configuration['allow_single_line_empty_anonymous_classes'];
4✔
246
                    $positionOption = 'anonymous_classes_opening_brace';
4✔
247
                } else {
248
                    $positionOption = 'classes_opening_brace';
12✔
249
                }
250
            } elseif ($token->isGivenKind(\T_FUNCTION)) {
60✔
251
                $openBraceIndex = $tokens->getNextTokenOfKind($index, ['{', ';', [CT::T_PROPERTY_HOOK_BRACE_OPEN]]);
25✔
252

253
                if (!$tokens[$openBraceIndex]->equals('{')) {
25✔
254
                    continue;
2✔
255
                }
256

257
                if ($tokensAnalyzer->isLambda($index)) {
23✔
258
                    $allowSingleLine = true === $this->configuration['allow_single_line_anonymous_functions'];
4✔
259
                    $positionOption = 'anonymous_functions_opening_brace';
4✔
260
                } else {
261
                    $positionOption = 'functions_opening_brace';
21✔
262
                }
263
            } elseif ($token->isGivenKind(self::CONTROL_STRUCTURE_TOKENS)) {
60✔
264
                $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
30✔
265
                $openBraceIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
30✔
266

267
                if (!$tokens[$openBraceIndex]->equals('{')) {
30✔
268
                    continue;
4✔
269
                }
270

271
                $positionOption = 'control_structures_opening_brace';
30✔
272
            } elseif ($token->isGivenKind(\T_VARIABLE)) {
60✔
273
                // handle default value - explicitly skip array as default value
274
                $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($index);
47✔
275
                if ($tokens[$nextMeaningfulIndex]->equals('=')) {
47✔
276
                    $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($nextMeaningfulIndex);
9✔
277

278
                    if ($tokens[$nextMeaningfulIndex]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
9✔
279
                        $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $nextMeaningfulIndex);
1✔
280
                    } elseif ($tokens[$nextMeaningfulIndex]->isGivenKind(\T_ARRAY)) {
9✔
281
                        $nextMeaningfulIndex = $tokens->getNextMeaningfulToken($nextMeaningfulIndex);
1✔
282
                        if ($tokens[$nextMeaningfulIndex]->equals('(')) {
1✔
283
                            $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextMeaningfulIndex);
1✔
284
                        }
285
                    }
286
                }
287

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

290
                if (!$tokens[$openBraceIndex]->isGivenKind(CT::T_PROPERTY_HOOK_BRACE_OPEN)) {
47✔
291
                    continue;
46✔
292
                }
293

294
                $closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PROPERTY_HOOK, $openBraceIndex);
5✔
295
                if (!$tokens->isPartialCodeMultiline($openBraceIndex, $closeBraceIndex)) {
5✔
296
                    continue;
1✔
297
                }
298

299
                $positionOption = 'control_structures_opening_brace';
4✔
300
            } elseif ($token->isGivenKind(\T_STRING)) {
60✔
301
                $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
54✔
302
                $openBraceIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
54✔
303
                if (!$tokens[$openBraceIndex]->equals('{')) {
54✔
304
                    continue;
46✔
305
                }
306

307
                $prevIndex = $tokens->getPrevMeaningfulToken($index);
27✔
308
                if (!$tokens[$prevIndex]->equalsAny(['}', ';', [CT::T_ATTRIBUTE_CLOSE], [CT::T_PROPERTY_HOOK_BRACE_OPEN]])) {
27✔
309
                    continue;
27✔
310
                }
311
                $allowSingleLine = true === $this->configuration['allow_single_line_anonymous_functions'];
4✔
312
                $positionOption = 'control_structures_opening_brace';
4✔
313
            } else {
314
                continue;
60✔
315
            }
316

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

319
            $addNewlinesInsideBraces = true;
60✔
320
            if ($allowSingleLine || $allowSingleLineIfEmpty || $index < $allowSingleLineUntil) {
60✔
321
                $addNewlinesInsideBraces = false;
11✔
322

323
                for ($indexInsideBraces = $openBraceIndex + 1; $indexInsideBraces < $closeBraceIndex; ++$indexInsideBraces) {
11✔
324
                    $tokenInsideBraces = $tokens[$indexInsideBraces];
10✔
325

326
                    if (
327
                        ($allowSingleLineIfEmpty && !$tokenInsideBraces->isWhitespace() && !$tokenInsideBraces->isComment())
10✔
328
                        || ($tokenInsideBraces->isWhitespace() && Preg::match('/\R/', $tokenInsideBraces->getContent()))
10✔
329
                    ) {
330
                        $addNewlinesInsideBraces = true;
9✔
331

332
                        break;
9✔
333
                    }
334
                }
335

336
                if (!$addNewlinesInsideBraces && null === $allowSingleLineUntil) {
11✔
337
                    $allowSingleLineUntil = $closeBraceIndex;
3✔
338
                }
339
            }
340

341
            if (
342
                $addNewlinesInsideBraces
60✔
343
                && !$this->isFollowedByNewLine($tokens, $openBraceIndex)
60✔
344
                && !$this->hasCommentOnSameLine($tokens, $openBraceIndex)
60✔
345
                && !$tokens[$tokens->getNextMeaningfulToken($openBraceIndex)]->isGivenKind(\T_CLOSE_TAG)
60✔
346
            ) {
347
                $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
2✔
348
                if ($tokens->ensureWhitespaceAtIndex($openBraceIndex + 1, 0, $whitespace)) {
2✔
349
                    ++$closeBraceIndex;
×
350
                }
351
            }
352

353
            $whitespace = ' ';
60✔
354
            if (self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END === $this->configuration[$positionOption]) {
60✔
355
                $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $index);
40✔
356

357
                $previousTokenIndex = $openBraceIndex;
40✔
358
                do {
359
                    $previousTokenIndex = $tokens->getPrevMeaningfulToken($previousTokenIndex);
40✔
360
                } 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✔
361

362
                if ($tokens[$previousTokenIndex]->equals(')')) {
40✔
363
                    if ($tokens[--$previousTokenIndex]->isComment()) {
33✔
364
                        --$previousTokenIndex;
×
365
                    }
366
                    if (
367
                        $tokens[$previousTokenIndex]->isWhitespace()
33✔
368
                        && Preg::match('/\R/', $tokens[$previousTokenIndex]->getContent())
33✔
369
                    ) {
370
                        $whitespace = ' ';
13✔
371
                    }
372
                }
373
            }
374

375
            $moveBraceToIndex = null;
60✔
376

377
            if (' ' === $whitespace) {
60✔
378
                $previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($openBraceIndex);
41✔
379
                for ($indexBeforeOpenBrace = $openBraceIndex - 1; $indexBeforeOpenBrace > $previousMeaningfulIndex; --$indexBeforeOpenBrace) {
41✔
380
                    if (!$tokens[$indexBeforeOpenBrace]->isComment()) {
41✔
381
                        continue;
41✔
382
                    }
383

384
                    $tokenBeforeOpenBrace = $tokens[--$indexBeforeOpenBrace];
4✔
385
                    if ($tokenBeforeOpenBrace->isWhitespace()) {
4✔
386
                        $moveBraceToIndex = $indexBeforeOpenBrace;
3✔
387
                    } elseif ($indexBeforeOpenBrace === $previousMeaningfulIndex) {
1✔
388
                        $moveBraceToIndex = $previousMeaningfulIndex + 1;
1✔
389
                    }
390
                }
391
            } elseif (!$tokens[$openBraceIndex - 1]->isWhitespace() || !Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
28✔
392
                for ($indexAfterOpenBrace = $openBraceIndex + 1; $indexAfterOpenBrace < $closeBraceIndex; ++$indexAfterOpenBrace) {
22✔
393
                    if ($tokens[$indexAfterOpenBrace]->isWhitespace() && Preg::match('/\R/', $tokens[$indexAfterOpenBrace]->getContent())) {
22✔
394
                        break;
22✔
395
                    }
396

397
                    if ($tokens[$indexAfterOpenBrace]->isComment() && !str_starts_with($tokens[$indexAfterOpenBrace]->getContent(), '/*')) {
3✔
398
                        $moveBraceToIndex = $indexAfterOpenBrace + 1;
3✔
399
                    }
400
                }
401
            }
402

403
            if (null !== $moveBraceToIndex) {
60✔
404
                $movedToken = clone $tokens[$openBraceIndex];
7✔
405

406
                $delta = $openBraceIndex < $moveBraceToIndex ? 1 : -1;
7✔
407

408
                if ($tokens[$openBraceIndex + $delta]->isWhitespace()) {
7✔
409
                    if (-1 === $delta && Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
6✔
410
                        $content = Preg::replace('/^(\h*?\R)?\h*/', '', $tokens[$openBraceIndex + 1]->getContent());
2✔
411
                        if ('' !== $content) {
2✔
412
                            $tokens[$openBraceIndex + 1] = new Token([\T_WHITESPACE, $content]);
1✔
413
                        } else {
414
                            $tokens->clearAt($openBraceIndex + 1);
1✔
415
                        }
416
                    } elseif ($tokens[$openBraceIndex - 1]->isWhitespace()) {
4✔
417
                        $tokens->clearAt($openBraceIndex - 1);
3✔
418
                    }
419
                }
420

421
                for ($i = $openBraceIndex; $i !== $moveBraceToIndex; $i += $delta) {
7✔
422
                    $siblingToken = $tokens[$i + $delta];
7✔
423
                    $tokens[$i] = $siblingToken;
7✔
424
                }
425

426
                $tokens[$i] = $movedToken;
7✔
427

428
                if ($tokens[$openBraceIndex]->isWhitespace() && $tokens[$openBraceIndex + 1]->isWhitespace()) {
7✔
429
                    $tokens[$openBraceIndex] = new Token([
4✔
430
                        \T_WHITESPACE,
4✔
431
                        $tokens[$openBraceIndex]->getContent().$tokens[$openBraceIndex + 1]->getContent(),
4✔
432
                    ]);
4✔
433
                    $tokens->clearAt($openBraceIndex + 1);
4✔
434
                }
435

436
                $openBraceIndex = $moveBraceToIndex;
7✔
437
            }
438

439
            if ($tokens->ensureWhitespaceAtIndex($openBraceIndex - 1, 1, $whitespace)) {
60✔
440
                ++$closeBraceIndex;
5✔
441
                if (null !== $allowSingleLineUntil) {
5✔
442
                    ++$allowSingleLineUntil;
×
443
                }
444
            }
445

446
            if (
447
                !$addNewlinesInsideBraces
60✔
448
                || $tokens[$tokens->getPrevMeaningfulToken($closeBraceIndex)]->isGivenKind(\T_OPEN_TAG)
60✔
449
            ) {
450
                continue;
3✔
451
            }
452

453
            $prevIndex = $closeBraceIndex - 1;
60✔
454
            while ($tokens->isEmptyAt($prevIndex)) {
60✔
455
                --$prevIndex;
×
456
            }
457

458
            $prevToken = $tokens[$prevIndex];
60✔
459

460
            if ($prevToken->isWhitespace() && Preg::match('/\R/', $prevToken->getContent())) {
60✔
461
                continue;
60✔
462
            }
463

464
            $whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
5✔
465
            $tokens->ensureWhitespaceAtIndex($prevIndex, 1, $whitespace);
5✔
466
        }
467
    }
468

469
    private function findParenthesisEnd(Tokens $tokens, int $structureTokenIndex): int
470
    {
471
        $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
56✔
472
        $nextToken = $tokens[$nextIndex];
56✔
473

474
        // return if next token is not opening parenthesis
475
        if (!$nextToken->equals('(')) {
56✔
476
            return $structureTokenIndex;
32✔
477
        }
478

479
        return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
53✔
480
    }
481

482
    private function isFollowedByNewLine(Tokens $tokens, int $index): bool
483
    {
484
        for (++$index, $max = \count($tokens) - 1; $index < $max; ++$index) {
60✔
485
            $token = $tokens[$index];
60✔
486
            if (!$token->isComment()) {
60✔
487
                return $token->isWhitespace() && Preg::match('/\R/', $token->getContent());
60✔
488
            }
489
        }
490

491
        return false;
×
492
    }
493

494
    private function hasCommentOnSameLine(Tokens $tokens, int $index): bool
495
    {
496
        $token = $tokens[$index + 1];
7✔
497

498
        if ($token->isWhitespace() && !Preg::match('/\R/', $token->getContent())) {
7✔
499
            $token = $tokens[$index + 2];
7✔
500
        }
501

502
        return $token->isComment();
7✔
503
    }
504
}
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