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

keradus / PHP-CS-Fixer / 16303177127

15 Jul 2025 06:22PM UTC coverage: 94.758% (-0.05%) from 94.806%
16303177127

push

github

keradus
bumped version

28199 of 29759 relevant lines covered (94.76%)

45.91 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
final class NoUnneededBracesFixer extends AbstractFixer implements ConfigurableFixerInterface
40
{
41
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
42
    use ConfigurableFixerTrait;
43

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

54
switch ($b) {
55
    case 1: {
56
        break;
57
    }
58
}
59
'
3✔
60
                ),
3✔
61
                new CodeSample(
3✔
62
                    '<?php
3✔
63
namespace Foo {
64
    function Bar(){}
65
}
66
',
3✔
67
                    ['namespaces' => true]
3✔
68
                ),
3✔
69
            ]
3✔
70
        );
3✔
71
    }
72

73
    /**
74
     * {@inheritdoc}
75
     *
76
     * Must run before NoUselessElseFixer, NoUselessReturnFixer, ReturnAssignmentFixer, SimplifiedIfReturnFixer.
77
     */
78
    public function getPriority(): int
79
    {
80
        return 40;
1✔
81
    }
82

83
    public function isCandidate(Tokens $tokens): bool
84
    {
85
        return $tokens->isTokenKindFound('}');
15✔
86
    }
87

88
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
89
    {
90
        foreach ($this->findBraceOpen($tokens) as $index) {
15✔
91
            if ($this->isOverComplete($tokens, $index)) {
15✔
92
                $this->clearOverCompleteBraces($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
4✔
93
            }
94
        }
95

96
        if (true === $this->configuration['namespaces']) {
15✔
97
            $this->clearIfIsOverCompleteNamespaceBlock($tokens);
7✔
98
        }
99
    }
100

101
    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
102
    {
103
        return new FixerConfigurationResolver([
24✔
104
            (new FixerOptionBuilder('namespaces', 'Remove unneeded braces from bracketed namespaces.'))
24✔
105
                ->setAllowedTypes(['bool'])
24✔
106
                ->setDefault(false)
24✔
107
                ->getOption(),
24✔
108
        ]);
24✔
109
    }
110

111
    /**
112
     * @param int $openIndex  index of `{` token
113
     * @param int $closeIndex index of `}` token
114
     */
115
    private function clearOverCompleteBraces(Tokens $tokens, int $openIndex, int $closeIndex): void
116
    {
117
        $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
4✔
118
        $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
4✔
119
    }
120

121
    /**
122
     * @return iterable<int>
123
     */
124
    private function findBraceOpen(Tokens $tokens): iterable
125
    {
126
        for ($i = \count($tokens) - 1; $i > 0; --$i) {
15✔
127
            if ($tokens[$i]->equals('{')) {
15✔
128
                yield $i;
15✔
129
            }
130
        }
131
    }
132

133
    /**
134
     * @param int $index index of `{` token
135
     */
136
    private function isOverComplete(Tokens $tokens, int $index): bool
137
    {
138
        return $tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny(['{', '}', [\T_OPEN_TAG], ':', ';']);
15✔
139
    }
140

141
    private function clearIfIsOverCompleteNamespaceBlock(Tokens $tokens): void
142
    {
143
        if (1 !== $tokens->countTokenKind(\T_NAMESPACE)) {
7✔
144
            return; // fast check, we never fix if multiple namespaces are defined
1✔
145
        }
146

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

149
        $namespaceIsNamed = false;
6✔
150

151
        $index = $tokens->getNextMeaningfulToken($index);
6✔
152
        while ($tokens[$index]->isGivenKind([\T_STRING, \T_NS_SEPARATOR])) {
6✔
153
            $index = $tokens->getNextMeaningfulToken($index);
5✔
154
            $namespaceIsNamed = true;
5✔
155
        }
156

157
        if (!$namespaceIsNamed) {
6✔
158
            return;
1✔
159
        }
160

161
        if (!$tokens[$index]->equals('{')) {
5✔
162
            return; // `;`
4✔
163
        }
164

165
        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
5✔
166
        $afterCloseIndex = $tokens->getNextMeaningfulToken($closeIndex);
5✔
167

168
        if (null !== $afterCloseIndex && (!$tokens[$afterCloseIndex]->isGivenKind(\T_CLOSE_TAG) || null !== $tokens->getNextMeaningfulToken($afterCloseIndex))) {
5✔
169
            return;
×
170
        }
171

172
        // clear up
173
        $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
5✔
174
        $tokens[$index] = new Token(';');
5✔
175

176
        if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
5✔
177
            $tokens->clearTokenAndMergeSurroundingWhitespace($index - 1);
5✔
178
        }
179
    }
180
}
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