1: <?php declare(strict_types = 1);
2:
3: namespace ApiGen\Analyzer;
4:
5: use PhpParser\ErrorHandler;
6: use PhpParser\Lexer;
7: use PhpParser\Token;
8:
9: use function count;
10:
11: use const T_CURLY_OPEN;
12: use const T_DOLLAR_OPEN_CURLY_BRACES;
13: use const T_FUNCTION;
14: use const T_USE;
15: use const T_WHITESPACE;
16:
17:
18: class BodySkippingLexer extends Lexer
19: {
20: private const CURLY_BRACE_OPEN = 0x7B;
21: private const CURLY_BRACE_CLOSE = 0x7D;
22: private const SEMICOLON = 0x3B;
23:
24:
25: /**
26: * @param list<Token> $tokens
27: */
28: protected function postprocessTokens(array &$tokens, ErrorHandler $errorHandler): void
29: {
30: parent::postprocessTokens($tokens, $errorHandler);
31:
32: $tokenCount = count($tokens);
33: for ($i = 0; $i < $tokenCount; $i++) { // looking for function start
34: if ($tokens[$i]->id === T_FUNCTION && $tokens[$i - 2]->id !== T_USE) {
35: for ($i++; $i < $tokenCount; $i++) { // looking for opening curly brace of function body or semicolon
36: switch ($tokens[$i]->id) {
37: case self::SEMICOLON:
38: continue 3; // look for next function
39:
40: case self::CURLY_BRACE_OPEN:
41: break 2;
42: }
43: }
44:
45: for ($i++, $level = 0; $i < $tokenCount; $i++) { // looking for closing curly brace of function body
46: switch ($tokens[$i]->id) {
47: case T_WHITESPACE:
48: continue 2;
49:
50: case self::CURLY_BRACE_OPEN:
51: case T_CURLY_OPEN:
52: case T_DOLLAR_OPEN_CURLY_BRACES:
53: $level++;
54: break;
55:
56: case self::CURLY_BRACE_CLOSE:
57: if ($level === 0) {
58: continue 3; // look for next function
59: }
60:
61: $level--;
62: break;
63: }
64:
65: $tokens[$i] = new Token(T_WHITESPACE, ' '); // @phpstan-ignore parameterByRef.type
66: }
67: }
68: }
69: }
70: }
71: