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

keradus / PHP-CS-Fixer / 19958239208

05 Dec 2025 09:13AM UTC coverage: 93.181% (-1.0%) from 94.158%
19958239208

push

github

keradus
chore: .php-cs-fixer.dist.php - remove no longer needed rule, 'expectedDeprecation' annotation does not exist for long time

28928 of 31045 relevant lines covered (93.18%)

44.49 hits per line

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

98.36
/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\CT;
27
use PhpCsFixer\Tokenizer\Token;
28
use PhpCsFixer\Tokenizer\Tokens;
29
use PhpCsFixer\Tokenizer\TokensAnalyzer;
30

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

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

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

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

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

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

91
    public function isCandidate(Tokens $tokens): bool
92
    {
93
        return $tokens->isAnyTokenKindsFound(['}', CT::T_GROUP_IMPORT_BRACE_CLOSE]);
16✔
94
    }
95

96
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
97
    {
98
        foreach ($this->findBraceOpen($tokens) as $index) {
16✔
99
            if ($this->isOverComplete($tokens, $index)) {
16✔
100
                $this->clearOverCompleteBraces($tokens, $index);
5✔
101
            }
102
        }
103

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

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

119
    /**
120
     * @param int $openIndex index of `{` token
121
     */
122
    private function clearOverCompleteBraces(Tokens $tokens, int $openIndex): void
123
    {
124
        $blockType = Tokens::detectBlockType($tokens[$openIndex]);
5✔
125

126
        $closeIndex = $tokens->findBlockEnd($blockType['type'], $openIndex);
5✔
127

128
        $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
5✔
129
        $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
5✔
130
    }
131

132
    /**
133
     * @return iterable<int>
134
     */
135
    private function findBraceOpen(Tokens $tokens): iterable
136
    {
137
        for ($i = \count($tokens) - 1; $i > 0; --$i) {
16✔
138
            if ($tokens[$i]->equalsAny(['{', [CT::T_GROUP_IMPORT_BRACE_OPEN]])) {
16✔
139
                yield $i;
16✔
140
            }
141
        }
142
    }
143

144
    /**
145
     * @param int $index index of `{` token
146
     */
147
    private function isOverComplete(Tokens $tokens, int $index): bool
148
    {
149
        if ($tokens[$index]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
16✔
150
            $commaOrCloseBraceIndex = $tokens->getNextTokenOfKind($index, [',', [CT::T_GROUP_IMPORT_BRACE_CLOSE]]);
2✔
151

152
            $analyzer = new TokensAnalyzer($tokens);
2✔
153
            if ($analyzer->isBlockMultiline($tokens, $index)) {
2✔
154
                return false;
1✔
155
            }
156

157
            return $tokens[$commaOrCloseBraceIndex]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE);
2✔
158
        }
159

160
        return $tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny(['{', '}', [\T_OPEN_TAG], ':', ';']);
15✔
161
    }
162

163
    private function clearIfIsOverCompleteNamespaceBlock(Tokens $tokens): void
164
    {
165
        if (1 !== $tokens->countTokenKind(\T_NAMESPACE)) {
7✔
166
            return; // fast check, we never fix if multiple namespaces are defined
1✔
167
        }
168

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

171
        $namespaceIsNamed = false;
6✔
172

173
        $index = $tokens->getNextMeaningfulToken($index);
6✔
174
        while ($tokens[$index]->isGivenKind([\T_STRING, \T_NS_SEPARATOR])) {
6✔
175
            $index = $tokens->getNextMeaningfulToken($index);
5✔
176
            $namespaceIsNamed = true;
5✔
177
        }
178

179
        if (!$namespaceIsNamed) {
6✔
180
            return;
1✔
181
        }
182

183
        if (!$tokens[$index]->equals('{')) {
5✔
184
            return; // `;`
4✔
185
        }
186

187
        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
5✔
188
        $afterCloseIndex = $tokens->getNextMeaningfulToken($closeIndex);
5✔
189

190
        if (null !== $afterCloseIndex && (!$tokens[$afterCloseIndex]->isGivenKind(\T_CLOSE_TAG) || null !== $tokens->getNextMeaningfulToken($afterCloseIndex))) {
5✔
191
            return;
×
192
        }
193

194
        // clear up
195
        $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
5✔
196
        $tokens[$index] = new Token(';');
5✔
197

198
        if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
5✔
199
            $tokens->clearTokenAndMergeSurroundingWhitespace($index - 1);
5✔
200
        }
201
    }
202
}
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