diff --git a/src/Parser/ConstExprParser.php b/src/Parser/ConstExprParser.php index b0ee83d9..70a45f63 100644 --- a/src/Parser/ConstExprParser.php +++ b/src/Parser/ConstExprParser.php @@ -56,15 +56,29 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) { $classConstantName = ''; - if ($tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) { - $classConstantName .= $tokens->currentTokenValue(); - $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); - if ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) { + $lastType = null; + while (true) { + if ($lastType !== Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) { + $classConstantName .= $tokens->currentTokenValue(); + $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); + $lastType = Lexer::TOKEN_IDENTIFIER; + + continue; + } + + if ($lastType !== Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) { $classConstantName .= '*'; + $lastType = Lexer::TOKEN_WILDCARD; + + continue; } - } else { - $tokens->consumeTokenType(Lexer::TOKEN_WILDCARD); - $classConstantName .= '*'; + + if ($lastType === null) { + // trigger parse error if nothing valid was consumed + $tokens->consumeTokenType(Lexer::TOKEN_WILDCARD); + } + + break; } return new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName); diff --git a/tests/PHPStan/Parser/TypeParserTest.php b/tests/PHPStan/Parser/TypeParserTest.php index 2ae85a3e..d42a290c 100644 --- a/tests/PHPStan/Parser/TypeParserTest.php +++ b/tests/PHPStan/Parser/TypeParserTest.php @@ -858,6 +858,22 @@ public function provideParseData(): array 'Foo::FOO_*', new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*')), ], + [ + 'Foo::FOO_*BAR', + new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*BAR')), + ], + [ + 'Foo::*FOO*', + new ConstTypeNode(new ConstFetchNode('Foo', '*FOO*')), + ], + [ + 'Foo::A*B*C', + new ConstTypeNode(new ConstFetchNode('Foo', 'A*B*C')), + ], + [ + 'self::*BAR', + new ConstTypeNode(new ConstFetchNode('self', '*BAR')), + ], [ 'Foo::*', new ConstTypeNode(new ConstFetchNode('Foo', '*')), @@ -869,8 +885,7 @@ public function provideParseData(): array ], [ 'Foo::*a', - new ConstTypeNode(new ConstFetchNode('Foo', '*')), // fails later in PhpDocParser - Lexer::TOKEN_IDENTIFIER, + new ConstTypeNode(new ConstFetchNode('Foo', '*a')), ], [ '( "foo" | Foo::FOO_* )',