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

keradus / PHP-CS-Fixer / 17319949156

29 Aug 2025 09:20AM UTC coverage: 94.696% (-0.05%) from 94.744%
17319949156

push

github

keradus
CS

28333 of 29920 relevant lines covered (94.7%)

45.63 hits per line

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

97.78
/src/Tokenizer/Analyzer/AlternativeSyntaxAnalyzer.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\Tokenizer\Analyzer;
16

17
use PhpCsFixer\Tokenizer\Tokens;
18

19
/**
20
 * @internal
21
 *
22
 * @TODO 4.0 remove this analyzer and move this logic into a transformer
23
 *
24
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
25
 */
26
final class AlternativeSyntaxAnalyzer
27
{
28
    private const ALTERNATIVE_SYNTAX_BLOCK_EDGES = [
29
        \T_IF => [\T_ENDIF, \T_ELSE, \T_ELSEIF],
30
        \T_ELSE => [\T_ENDIF],
31
        \T_ELSEIF => [\T_ENDIF, \T_ELSE, \T_ELSEIF],
32
        \T_FOR => [\T_ENDFOR],
33
        \T_FOREACH => [\T_ENDFOREACH],
34
        \T_WHILE => [\T_ENDWHILE],
35
        \T_SWITCH => [\T_ENDSWITCH],
36
    ];
37

38
    public function belongsToAlternativeSyntax(Tokens $tokens, int $index): bool
39
    {
40
        if (!$tokens[$index]->equals(':')) {
7✔
41
            return false;
7✔
42
        }
43

44
        $prevIndex = $tokens->getPrevMeaningfulToken($index);
7✔
45

46
        if ($tokens[$prevIndex]->isGivenKind(\T_ELSE)) {
7✔
47
            return true;
2✔
48
        }
49

50
        if (!$tokens[$prevIndex]->equals(')')) {
7✔
51
            return false;
2✔
52
        }
53

54
        $openParenthesisIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevIndex);
7✔
55
        $beforeOpenParenthesisIndex = $tokens->getPrevMeaningfulToken($openParenthesisIndex);
7✔
56

57
        return $tokens[$beforeOpenParenthesisIndex]->isGivenKind([
7✔
58
            \T_DECLARE,
7✔
59
            \T_ELSEIF,
7✔
60
            \T_FOR,
7✔
61
            \T_FOREACH,
7✔
62
            \T_IF,
7✔
63
            \T_SWITCH,
7✔
64
            \T_WHILE,
7✔
65
        ]);
7✔
66
    }
67

68
    public function findAlternativeSyntaxBlockEnd(Tokens $tokens, int $index): int
69
    {
70
        if (!isset($tokens[$index])) {
41✔
71
            throw new \InvalidArgumentException("There is no token at index {$index}.");
8✔
72
        }
73

74
        if (!$this->isStartOfAlternativeSyntaxBlock($tokens, $index)) {
33✔
75
            throw new \InvalidArgumentException("Token at index {$index} is not the start of an alternative syntax block.");
16✔
76
        }
77

78
        $startTokenKind = $tokens[$index]->getId();
17✔
79

80
        if (!isset(self::ALTERNATIVE_SYNTAX_BLOCK_EDGES[$startTokenKind])) {
17✔
81
            throw new \LogicException(\sprintf('Unknown startTokenKind: %s', $tokens[$index]->toJson()));
×
82
        }
83

84
        $endTokenKinds = self::ALTERNATIVE_SYNTAX_BLOCK_EDGES[$startTokenKind];
17✔
85

86
        $findKinds = [[$startTokenKind]];
17✔
87
        foreach ($endTokenKinds as $endTokenKind) {
17✔
88
            $findKinds[] = [$endTokenKind];
17✔
89
        }
90

91
        while (true) {
17✔
92
            $index = $tokens->getNextTokenOfKind($index, $findKinds);
17✔
93

94
            if ($tokens[$index]->isGivenKind($endTokenKinds)) {
17✔
95
                return $index;
17✔
96
            }
97

98
            if ($this->isStartOfAlternativeSyntaxBlock($tokens, $index)) {
4✔
99
                $index = $this->findAlternativeSyntaxBlockEnd($tokens, $index);
3✔
100
            }
101
        }
102
    }
103

104
    private function isStartOfAlternativeSyntaxBlock(Tokens $tokens, int $index): bool
105
    {
106
        $map = self::ALTERNATIVE_SYNTAX_BLOCK_EDGES;
33✔
107
        $startTokenKind = $tokens[$index]->getId();
33✔
108

109
        if (null === $startTokenKind || !isset($map[$startTokenKind])) {
33✔
110
            return false;
16✔
111
        }
112

113
        $index = $tokens->getNextMeaningfulToken($index);
17✔
114

115
        if ($tokens[$index]->equals('(')) {
17✔
116
            $index = $tokens->getNextMeaningfulToken(
14✔
117
                $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index)
14✔
118
            );
14✔
119
        }
120

121
        return $tokens[$index]->equals(':');
17✔
122
    }
123
}
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