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

PHP-CS-Fixer / PHP-CS-Fixer / 3825623956

pending completion
3825623956

Pull #6734

github

GitHub
Merge f402171a0 into f5726f543
Pull Request #6734: bug: Fix type error when using paths intersection mode

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

22556 of 24273 relevant lines covered (92.93%)

39.1 hits per line

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

68.06
/src/Fixer/Casing/ClassReferenceNameCasingFixer.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\Casing;
16

17
use PhpCsFixer\AbstractFixer;
18
use PhpCsFixer\FixerDefinition\CodeSample;
19
use PhpCsFixer\FixerDefinition\FixerDefinition;
20
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
21
use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
22
use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
23
use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
24
use PhpCsFixer\Tokenizer\CT;
25
use PhpCsFixer\Tokenizer\Token;
26
use PhpCsFixer\Tokenizer\Tokens;
27

28
final class ClassReferenceNameCasingFixer extends AbstractFixer
29
{
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function getDefinition(): FixerDefinitionInterface
34
    {
35
        return new FixerDefinition(
3✔
36
            'When referencing an internal class it must be written using the correct casing.',
3✔
37
            [
3✔
38
                new CodeSample("<?php\nthrow new \\exception();\n"),
3✔
39
            ]
3✔
40
        );
3✔
41
    }
42

43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function isCandidate(Tokens $tokens): bool
47
    {
48
        return $tokens->isTokenKindFound(T_STRING);
29✔
49
    }
50

51
    /**
52
     * {@inheritdoc}
53
     */
54
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
55
    {
56
        $namespacesAnalyzer = new NamespacesAnalyzer();
29✔
57
        $namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
29✔
58
        $classNames = $this->getClassNames();
29✔
59

60
        foreach ($namespacesAnalyzer->getDeclarations($tokens) as $namespace) {
29✔
61
            $uses = [];
29✔
62

63
            foreach ($namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace) as $use) {
29✔
64
                $uses[strtolower($use->getShortName())] = true;
3✔
65
            }
66

67
            foreach ($this->getClassReference($tokens, $namespace) as $reference) {
29✔
68
                $currentContent = $tokens[$reference]->getContent();
16✔
69
                $lowerCurrentContent = strtolower($currentContent);
16✔
70

71
                if (isset($classNames[$lowerCurrentContent]) && $currentContent !== $classNames[$lowerCurrentContent] && !isset($uses[$lowerCurrentContent])) {
16✔
72
                    $tokens[$reference] = new Token([T_STRING, $classNames[$lowerCurrentContent]]);
12✔
73
                }
74
            }
75
        }
76
    }
77

78
    private function getClassReference(Tokens $tokens, NamespaceAnalysis $namespace): \Generator
79
    {
80
        static $notBeforeKinds;
29✔
81
        static $blockKinds;
29✔
82

83
        if (null === $notBeforeKinds) {
29✔
84
            $notBeforeKinds = [
×
85
                CT::T_USE_TRAIT,
×
86
                T_AS,
×
87
                T_CASE, // PHP 8.1 trait enum-case
×
88
                T_CLASS,
×
89
                T_CONST,
×
90
                T_DOUBLE_ARROW,
×
91
                T_DOUBLE_COLON,
×
92
                T_FUNCTION,
×
93
                T_INTERFACE,
×
94
                T_OBJECT_OPERATOR,
×
95
                T_TRAIT,
×
96
            ];
×
97

98
            if (\defined('T_ENUM')) { // @TODO: drop condition when PHP 8.1+ is required
×
99
                $notBeforeKinds[] = T_ENUM;
×
100
            }
101
        }
102

103
        if (null === $blockKinds) {
29✔
104
            $blockKinds = ['before' => [','], 'after' => [',']];
×
105

106
            foreach (Tokens::getBlockEdgeDefinitions() as $definition) {
×
107
                $blockKinds['before'][] = $definition['start'];
×
108
                $blockKinds['after'][] = $definition['end'];
×
109
            }
110
        }
111

112
        $namespaceIsGlobal = $namespace->isGlobalNamespace();
29✔
113

114
        for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex(); ++$index) {
29✔
115
            if (!$tokens[$index]->isGivenKind(T_STRING)) {
29✔
116
                continue;
29✔
117
            }
118

119
            $nextIndex = $tokens->getNextMeaningfulToken($index);
29✔
120

121
            if ($tokens[$nextIndex]->isGivenKind(T_NS_SEPARATOR)) {
29✔
122
                continue;
3✔
123
            }
124

125
            $prevIndex = $tokens->getPrevMeaningfulToken($index);
29✔
126
            $nextIndex = $tokens->getNextMeaningfulToken($index);
29✔
127

128
            $isNamespaceSeparator = $tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR);
29✔
129

130
            if (!$isNamespaceSeparator && !$namespaceIsGlobal) {
29✔
131
                continue;
3✔
132
            }
133

134
            if ($isNamespaceSeparator) {
29✔
135
                $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
12✔
136

137
                if ($tokens[$prevIndex]->isGivenKind(T_STRING)) {
12✔
138
                    continue;
12✔
139
                }
140
            } elseif ($tokens[$prevIndex]->isGivenKind($notBeforeKinds)) {
26✔
141
                continue;
17✔
142
            }
143

144
            if ($tokens[$prevIndex]->equalsAny($blockKinds['before']) && $tokens[$nextIndex]->equalsAny($blockKinds['after'])) {
20✔
145
                continue;
3✔
146
            }
147

148
            if (!$tokens[$prevIndex]->isGivenKind(T_NEW) && $tokens[$nextIndex]->equalsAny(['(', ';', [T_CLOSE_TAG]])) {
20✔
149
                continue;
8✔
150
            }
151

152
            yield $index;
16✔
153
        }
154
    }
155

156
    /**
157
     * @return array<string, string>
158
     */
159
    private function getClassNames(): array
160
    {
161
        static $classes = null;
29✔
162

163
        if (null === $classes) {
29✔
164
            $classes = [];
×
165

166
            foreach (get_declared_classes() as $class) {
×
167
                if ((new \ReflectionClass($class))->isInternal()) {
×
168
                    $classes[strtolower($class)] = $class;
×
169
                }
170
            }
171
        }
172

173
        return $classes;
29✔
174
    }
175
}
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

© 2025 Coveralls, Inc