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

keradus / PHP-CS-Fixer / 17678835382

12 Sep 2025 03:24PM UTC coverage: 94.69% (-0.06%) from 94.75%
17678835382

push

github

keradus
fix typo

1 of 1 new or added line in 1 file covered. (100.0%)

1042 existing lines in 177 files now uncovered.

28424 of 30018 relevant lines covered (94.69%)

45.5 hits per line

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

98.11
/src/Fixer/ControlStructure/NoUnneededBracesFixer.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\ControlStructure;
16

17
use PhpCsFixer\AbstractFixer;
18
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
19
use PhpCsFixer\Fixer\ConfigurableFixerTrait;
20
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
21
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
22
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
23
use PhpCsFixer\FixerDefinition\CodeSample;
24
use PhpCsFixer\FixerDefinition\FixerDefinition;
25
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
26
use PhpCsFixer\Tokenizer\Token;
27
use PhpCsFixer\Tokenizer\Tokens;
28

29
/**
30
 * @phpstan-type _AutogeneratedInputConfiguration array{
31
 *  namespaces?: bool,
32
 * }
33
 * @phpstan-type _AutogeneratedComputedConfiguration array{
34
 *  namespaces: bool,
35
 * }
36
 *
37
 * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
38
 *
39
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
40
 */
41
final class NoUnneededBracesFixer extends AbstractFixer implements ConfigurableFixerInterface
42
{
43
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
44
    use ConfigurableFixerTrait;
45

46
    public function getDefinition(): FixerDefinitionInterface
47
    {
48
        return new FixerDefinition(
3✔
49
            'Removes unneeded braces that are superfluous and aren\'t part of a control structure\'s body.',
3✔
50
            [
3✔
51
                new CodeSample(
3✔
52
                    <<<'PHP'
3✔
53
                        <?php {
54
                            echo 1;
55
                        }
56

57
                        switch ($b) {
58
                            case 1: {
59
                                break;
60
                            }
61
                        }
62

63
                        PHP
3✔
64
                ),
3✔
65
                new CodeSample(
3✔
66
                    <<<'PHP'
3✔
67
                        <?php
68
                        namespace Foo {
69
                            function Bar(){}
70
                        }
71

72
                        PHP,
3✔
73
                    ['namespaces' => true]
3✔
74
                ),
3✔
75
            ]
3✔
76
        );
3✔
77
    }
78

79
    /**
80
     * {@inheritdoc}
81
     *
82
     * Must run before NoUselessElseFixer, NoUselessReturnFixer, ReturnAssignmentFixer, SimplifiedIfReturnFixer.
83
     */
84
    public function getPriority(): int
85
    {
86
        return 40;
1✔
87
    }
88

89
    public function isCandidate(Tokens $tokens): bool
90
    {
91
        return $tokens->isTokenKindFound('}');
15✔
92
    }
93

94
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
95
    {
96
        foreach ($this->findBraceOpen($tokens) as $index) {
15✔
97
            if ($this->isOverComplete($tokens, $index)) {
15✔
98
                $this->clearOverCompleteBraces($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
4✔
99
            }
100
        }
101

102
        if (true === $this->configuration['namespaces']) {
15✔
103
            $this->clearIfIsOverCompleteNamespaceBlock($tokens);
7✔
104
        }
105
    }
106

107
    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
108
    {
109
        return new FixerConfigurationResolver([
24✔
110
            (new FixerOptionBuilder('namespaces', 'Remove unneeded braces from bracketed namespaces.'))
24✔
111
                ->setAllowedTypes(['bool'])
24✔
112
                ->setDefault(false)
24✔
113
                ->getOption(),
24✔
114
        ]);
24✔
115
    }
116

117
    /**
118
     * @param int $openIndex  index of `{` token
119
     * @param int $closeIndex index of `}` token
120
     */
121
    private function clearOverCompleteBraces(Tokens $tokens, int $openIndex, int $closeIndex): void
122
    {
123
        $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
4✔
124
        $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
4✔
125
    }
126

127
    /**
128
     * @return iterable<int>
129
     */
130
    private function findBraceOpen(Tokens $tokens): iterable
131
    {
132
        for ($i = \count($tokens) - 1; $i > 0; --$i) {
15✔
133
            if ($tokens[$i]->equals('{')) {
15✔
134
                yield $i;
15✔
135
            }
136
        }
137
    }
138

139
    /**
140
     * @param int $index index of `{` token
141
     */
142
    private function isOverComplete(Tokens $tokens, int $index): bool
143
    {
144
        return $tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny(['{', '}', [\T_OPEN_TAG], ':', ';']);
15✔
145
    }
146

147
    private function clearIfIsOverCompleteNamespaceBlock(Tokens $tokens): void
148
    {
149
        if (1 !== $tokens->countTokenKind(\T_NAMESPACE)) {
7✔
150
            return; // fast check, we never fix if multiple namespaces are defined
1✔
151
        }
152

153
        $index = $tokens->getNextTokenOfKind(0, [[\T_NAMESPACE]]);
6✔
154

155
        $namespaceIsNamed = false;
6✔
156

157
        $index = $tokens->getNextMeaningfulToken($index);
6✔
158
        while ($tokens[$index]->isGivenKind([\T_STRING, \T_NS_SEPARATOR])) {
6✔
159
            $index = $tokens->getNextMeaningfulToken($index);
5✔
160
            $namespaceIsNamed = true;
5✔
161
        }
162

163
        if (!$namespaceIsNamed) {
6✔
164
            return;
1✔
165
        }
166

167
        if (!$tokens[$index]->equals('{')) {
5✔
168
            return; // `;`
4✔
169
        }
170

171
        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
5✔
172
        $afterCloseIndex = $tokens->getNextMeaningfulToken($closeIndex);
5✔
173

174
        if (null !== $afterCloseIndex && (!$tokens[$afterCloseIndex]->isGivenKind(\T_CLOSE_TAG) || null !== $tokens->getNextMeaningfulToken($afterCloseIndex))) {
5✔
UNCOV
175
            return;
×
176
        }
177

178
        // clear up
179
        $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
5✔
180
        $tokens[$index] = new Token(';');
5✔
181

182
        if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
5✔
183
            $tokens->clearTokenAndMergeSurroundingWhitespace($index - 1);
5✔
184
        }
185
    }
186
}
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