Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
341 / 341
100.00% covered (success)
100.00%
27 / 27
CRAP
100.00% covered (success)
100.00%
1 / 1
AFPTreeParser
100.00% covered (success)
100.00%
341 / 341
100.00% covered (success)
100.00%
27 / 27
112
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 setFilter
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 resetState
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 move
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNextToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getState
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setState
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 parse
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 buildSyntaxTree
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 doLevelEntry
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 doLevelSemicolon
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
7
 doLevelSet
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
1 / 1
13
 doLevelConditions
100.00% covered (success)
100.00%
56 / 56
100.00% covered (success)
100.00%
1 / 1
13
 doLevelBoolOps
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 doLevelCompares
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 doLevelSumRels
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 doLevelMulRels
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 doLevelPow
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 doLevelBoolInvert
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 doLevelKeywordOperators
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 doLevelUnarys
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 doLevelArrayElements
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 doLevelParenthesis
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
7
 doLevelFunction
100.00% covered (success)
100.00%
37 / 37
100.00% covered (success)
100.00%
1 / 1
10
 doLevelAtom
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
1 / 1
16
 checkLogDeprecatedVar
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 functionIsVariadic
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3/**
4 * A version of the abuse filter parser that separates parsing the filter and
5 * evaluating it into different passes, allowing the parse tree to be cached.
6 *
7 * @file
8 * @phan-file-suppress PhanPossiblyInfiniteRecursionSameParams Recursion controlled by class props
9 */
10
11namespace MediaWiki\Extension\AbuseFilter\Parser;
12
13use IBufferingStatsdDataFactory;
14use InvalidArgumentException;
15use MediaWiki\Extension\AbuseFilter\KeywordsManager;
16use MediaWiki\Extension\AbuseFilter\Parser\Exception\UserVisibleException;
17use Psr\Log\LoggerInterface;
18
19/**
20 * A parser that transforms the text of the filter into a parse tree.
21 */
22class AFPTreeParser {
23    /**
24     * @var array[] Contains the AFPTokens for the code being parsed
25     * @phan-var array<int,array{0:AFPToken,1:int}>
26     */
27    private $mTokens;
28    /**
29     * @var AFPToken The current token
30     */
31    private $mCur;
32    /** @var int The position of the current token */
33    private $mPos;
34
35    /**
36     * @var string|null The ID of the filter being parsed, if available. Can also be "global-$ID"
37     */
38    private $mFilter;
39
40    public const CACHE_VERSION = 2;
41
42    /**
43     * @var LoggerInterface Used for debugging
44     */
45    private $logger;
46
47    /**
48     * @var IBufferingStatsdDataFactory
49     */
50    private $statsd;
51
52    /** @var KeywordsManager */
53    private $keywordsManager;
54
55    /**
56     * @param LoggerInterface $logger Used for debugging
57     * @param IBufferingStatsdDataFactory $statsd
58     * @param KeywordsManager $keywordsManager
59     */
60    public function __construct(
61        LoggerInterface $logger,
62        IBufferingStatsdDataFactory $statsd,
63        KeywordsManager $keywordsManager
64    ) {
65        $this->logger = $logger;
66        $this->statsd = $statsd;
67        $this->keywordsManager = $keywordsManager;
68        $this->resetState();
69    }
70
71    /**
72     * @param string $filter
73     */
74    public function setFilter( $filter ) {
75        $this->mFilter = $filter;
76    }
77
78    /**
79     * Resets the state
80     */
81    private function resetState() {
82        $this->mTokens = [];
83        $this->mPos = 0;
84        $this->mFilter = null;
85    }
86
87    /**
88     * Advances the parser to the next token in the filter code.
89     */
90    private function move() {
91        [ $this->mCur, $this->mPos ] = $this->mTokens[$this->mPos];
92    }
93
94    /**
95     * Get the next token. This is similar to move() but doesn't change class members,
96     *   allowing to look ahead without rolling back the state.
97     *
98     * @return AFPToken
99     */
100    private function getNextToken() {
101        return $this->mTokens[$this->mPos][0];
102    }
103
104    /**
105     * getState() function allows parser state to be rollbacked to several tokens
106     * back.
107     *
108     * @return AFPParserState
109     */
110    private function getState() {
111        return new AFPParserState( $this->mCur, $this->mPos );
112    }
113
114    /**
115     * setState() function allows parser state to be rollbacked to several tokens
116     * back.
117     *
118     * @param AFPParserState $state
119     */
120    private function setState( AFPParserState $state ) {
121        $this->mCur = $state->token;