-
Notifications
You must be signed in to change notification settings - Fork 41
/
Copy pathCacheValueOverrideSniff.php
137 lines (107 loc) · 3.75 KB
/
CacheValueOverrideSniff.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php
/**
* WordPressVIPMinimum Coding Standard.
*
* @package VIPCS\WordPressVIPMinimum
*/
namespace WordPressVIPMinimum\Sniffs\Performance;
use PHP_CodeSniffer\Util\Tokens;
use WordPressVIPMinimum\Sniffs\Sniff;
/**
* This sniff check whether a cached value is being overridden.
*/
class CacheValueOverrideSniff extends Sniff {
/**
* Returns the token types that this sniff is interested in.
*
* @return array<int|string>
*/
public function register() {
return [ T_STRING ];
}
/**
* Processes the tokens that this sniff is interested in.
*
* @param int $stackPtr The position in the stack where the token was found.
*
* @return void
*/
public function process_token( $stackPtr ) {
$functionName = $this->tokens[ $stackPtr ]['content'];
if ( $functionName !== 'wp_cache_get' ) {
// Not a function we are looking for.
return;
}
if ( $this->isFunctionCall( $stackPtr ) === false ) {
// Not a function call.
return;
}
$variablePos = $this->isVariableAssignment( $stackPtr );
if ( $variablePos === false ) {
// Not a variable assignment.
return;
}
$variableToken = $this->tokens[ $variablePos ];
$variableName = $variableToken['content'];
// Find the next non-empty token.
$openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true );
// Find the closing bracket.
$closeBracket = $this->tokens[ $openBracket ]['parenthesis_closer'];
$nextVariableOccurrence = $this->phpcsFile->findNext( T_VARIABLE, $closeBracket + 1, null, false, $variableName );
$rightAfterNextVariableOccurence = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextVariableOccurrence + 1, null, true, null, true );
if ( $this->tokens[ $rightAfterNextVariableOccurence ]['code'] !== T_EQUAL ) {
// Not a value override.
return;
}
$valueAfterEqualSign = $this->phpcsFile->findNext( Tokens::$emptyTokens, $rightAfterNextVariableOccurence + 1, null, true, null, true );
if ( $this->tokens[ $valueAfterEqualSign ]['code'] === T_FALSE ) {
$message = 'Obtained cached value in `%s` is being overridden. Disabling caching?';
$data = [ $variableName ];
$this->phpcsFile->addError( $message, $nextVariableOccurrence, 'CacheValueOverride', $data );
}
}
/**
* Check whether the examined code is a function call.
*
* @param int $stackPtr The position of the current token in the stack.
*
* @return bool
*/
private function isFunctionCall( $stackPtr ) {
// Find the next non-empty token.
$openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true );
if ( $this->tokens[ $openBracket ]['code'] !== T_OPEN_PARENTHESIS ) {
// Not a function call.
return false;
}
// Find the previous non-empty token.
$search = Tokens::$emptyTokens;
$search[] = T_BITWISE_AND;
$previous = $this->phpcsFile->findPrevious( $search, $stackPtr - 1, null, true );
// It's a function definition, not a function call, so return false.
return ! ( $this->tokens[ $previous ]['code'] === T_FUNCTION );
}
/**
* Check whether the examined code is a variable assignment.
*
* @param int $stackPtr The position of the current token in the stack.
*
* @return int|false
*/
private function isVariableAssignment( $stackPtr ) {
// Find the previous non-empty token.
$search = Tokens::$emptyTokens;
$search[] = T_BITWISE_AND;
$previous = $this->phpcsFile->findPrevious( $search, $stackPtr - 1, null, true );
if ( $this->tokens[ $previous ]['code'] !== T_EQUAL ) {
// It's not a variable assignment.
return false;
}
$previous = $this->phpcsFile->findPrevious( $search, $previous - 1, null, true );
if ( $this->tokens[ $previous ]['code'] !== T_VARIABLE ) {
// It's not a variable assignment.
return false;
}
return $previous;
}
}