Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Drupal_Sniffs_Semantics_FunctionCall.
|
Chris@0
|
4 *
|
Chris@0
|
5 * @category PHP
|
Chris@0
|
6 * @package PHP_CodeSniffer
|
Chris@0
|
7 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 /**
|
Chris@0
|
11 * Helper class to sniff for specific function calls.
|
Chris@0
|
12 *
|
Chris@0
|
13 * @category PHP
|
Chris@0
|
14 * @package PHP_CodeSniffer
|
Chris@0
|
15 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
16 */
|
Chris@0
|
17 abstract class Drupal_Sniffs_Semantics_FunctionCall implements PHP_CodeSniffer_Sniff
|
Chris@0
|
18 {
|
Chris@0
|
19
|
Chris@0
|
20 /**
|
Chris@0
|
21 * The currently processed file.
|
Chris@0
|
22 *
|
Chris@0
|
23 * @var PHP_CodeSniffer_File
|
Chris@0
|
24 */
|
Chris@0
|
25 protected $phpcsFile;
|
Chris@0
|
26
|
Chris@0
|
27 /**
|
Chris@0
|
28 * The token position of the function call.
|
Chris@0
|
29 *
|
Chris@0
|
30 * @var int
|
Chris@0
|
31 */
|
Chris@0
|
32 protected $functionCall;
|
Chris@0
|
33
|
Chris@0
|
34 /**
|
Chris@0
|
35 * The token position of the opening bracket of the function call.
|
Chris@0
|
36 *
|
Chris@0
|
37 * @var int
|
Chris@0
|
38 */
|
Chris@0
|
39 protected $openBracket;
|
Chris@0
|
40
|
Chris@0
|
41 /**
|
Chris@0
|
42 * The token position of the closing bracket of the function call.
|
Chris@0
|
43 *
|
Chris@0
|
44 * @var int
|
Chris@0
|
45 */
|
Chris@0
|
46 protected $closeBracket;
|
Chris@0
|
47
|
Chris@0
|
48 /**
|
Chris@0
|
49 * Internal cache to save the calculated arguments of the function call.
|
Chris@0
|
50 *
|
Chris@0
|
51 * @var array
|
Chris@0
|
52 */
|
Chris@0
|
53 protected $arguments;
|
Chris@0
|
54
|
Chris@0
|
55 /**
|
Chris@0
|
56 * Whether method invocations with the same function name should be processed,
|
Chris@0
|
57 * too.
|
Chris@0
|
58 *
|
Chris@0
|
59 * @var bool
|
Chris@0
|
60 */
|
Chris@0
|
61 protected $includeMethodCalls = false;
|
Chris@0
|
62
|
Chris@0
|
63
|
Chris@0
|
64 /**
|
Chris@0
|
65 * Returns an array of tokens this test wants to listen for.
|
Chris@0
|
66 *
|
Chris@0
|
67 * @return array
|
Chris@0
|
68 */
|
Chris@0
|
69 public function register()
|
Chris@0
|
70 {
|
Chris@0
|
71 return array(T_STRING);
|
Chris@0
|
72
|
Chris@0
|
73 }//end register()
|
Chris@0
|
74
|
Chris@0
|
75
|
Chris@0
|
76 /**
|
Chris@0
|
77 * Processes this test, when one of its tokens is encountered.
|
Chris@0
|
78 *
|
Chris@0
|
79 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
Chris@0
|
80 * @param int $stackPtr The position of the current token
|
Chris@0
|
81 * in the stack passed in $tokens.
|
Chris@0
|
82 *
|
Chris@0
|
83 * @return void
|
Chris@0
|
84 */
|
Chris@0
|
85 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
|
Chris@0
|
86 {
|
Chris@0
|
87 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
88 $functionName = $tokens[$stackPtr]['content'];
|
Chris@0
|
89 if (in_array($functionName, $this->registerFunctionNames()) === false) {
|
Chris@0
|
90 // Not interested in this function.
|
Chris@0
|
91 return;
|
Chris@0
|
92 }
|
Chris@0
|
93
|
Chris@0
|
94 if ($this->isFunctionCall($phpcsFile, $stackPtr) === false) {
|
Chris@0
|
95 return;
|
Chris@0
|
96 }
|
Chris@0
|
97
|
Chris@0
|
98 // Find the next non-empty token.
|
Chris@0
|
99 $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
|
Chris@0
|
100
|
Chris@0
|
101 $this->phpcsFile = $phpcsFile;
|
Chris@0
|
102 $this->functionCall = $stackPtr;
|
Chris@0
|
103 $this->openBracket = $openBracket;
|
Chris@0
|
104 $this->closeBracket = $tokens[$openBracket]['parenthesis_closer'];
|
Chris@0
|
105 $this->arguments = array();
|
Chris@0
|
106
|
Chris@0
|
107 $this->processFunctionCall($phpcsFile, $stackPtr, $openBracket, $this->closeBracket);
|
Chris@0
|
108
|
Chris@0
|
109 }//end process()
|
Chris@0
|
110
|
Chris@0
|
111
|
Chris@0
|
112 /**
|
Chris@0
|
113 * Checks if this is a function call.
|
Chris@0
|
114 *
|
Chris@0
|
115 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
Chris@0
|
116 * @param int $stackPtr The position of the current token
|
Chris@0
|
117 * in the stack passed in $tokens.
|
Chris@0
|
118 *
|
Chris@0
|
119 * @return bool
|
Chris@0
|
120 */
|
Chris@0
|
121 protected function isFunctionCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
|
Chris@0
|
122 {
|
Chris@0
|
123 $tokens = $phpcsFile->getTokens();
|
Chris@0
|
124 // Find the next non-empty token.
|
Chris@0
|
125 $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
|
Chris@0
|
126
|
Chris@0
|
127 if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
|
Chris@0
|
128 // Not a function call.
|
Chris@0
|
129 return false;
|
Chris@0
|
130 }
|
Chris@0
|
131
|
Chris@0
|
132 if (isset($tokens[$openBracket]['parenthesis_closer']) === false) {
|
Chris@0
|
133 // Not a function call.
|
Chris@0
|
134 return false;
|
Chris@0
|
135 }
|
Chris@0
|
136
|
Chris@0
|
137 // Find the previous non-empty token.
|
Chris@0
|
138 $search = PHP_CodeSniffer_Tokens::$emptyTokens;
|
Chris@0
|
139 $search[] = T_BITWISE_AND;
|
Chris@0
|
140 $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true);
|
Chris@0
|
141 if ($tokens[$previous]['code'] === T_FUNCTION) {
|
Chris@0
|
142 // It's a function definition, not a function call.
|
Chris@0
|
143 return false;
|
Chris@0
|
144 }
|
Chris@0
|
145
|
Chris@0
|
146 if ($tokens[$previous]['code'] === T_OBJECT_OPERATOR && $this->includeMethodCalls === false) {
|
Chris@0
|
147 // It's a method invocation, not a function call.
|
Chris@0
|
148 return false;
|
Chris@0
|
149 }
|
Chris@0
|
150
|
Chris@0
|
151 if ($tokens[$previous]['code'] === T_DOUBLE_COLON && $this->includeMethodCalls === false) {
|
Chris@0
|
152 // It's a static method invocation, not a function call.
|
Chris@0
|
153 return false;
|
Chris@0
|
154 }
|
Chris@0
|
155
|
Chris@0
|
156 return true;
|
Chris@0
|
157
|
Chris@0
|
158 }//end isFunctionCall()
|
Chris@0
|
159
|
Chris@0
|
160
|
Chris@0
|
161 /**
|
Chris@0
|
162 * Returns start and end token for a given argument number.
|
Chris@0
|
163 *
|
Chris@0
|
164 * @param int $number Indicates which argument should be examined, starting with
|
Chris@0
|
165 * 1 for the first argument.
|
Chris@0
|
166 *
|
Chris@0
|
167 * @return array(string => int)
|
Chris@0
|
168 */
|
Chris@0
|
169 public function getArgument($number)
|
Chris@0
|
170 {
|
Chris@0
|
171 // Check if we already calculated the tokens for this argument.
|
Chris@0
|
172 if (isset($this->arguments[$number]) === true) {
|
Chris@0
|
173 return $this->arguments[$number];
|
Chris@0
|
174 }
|
Chris@0
|
175
|
Chris@0
|
176 $tokens = $this->phpcsFile->getTokens();
|
Chris@0
|
177 // Start token of the first argument.
|
Chris@0
|
178 $start = $this->phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($this->openBracket + 1), null, true);
|
Chris@0
|
179 if ($start === $this->closeBracket) {
|
Chris@0
|
180 // Function call has no arguments, so return false.
|
Chris@0
|
181 return false;
|
Chris@0
|
182 }
|
Chris@0
|
183
|
Chris@0
|
184 // End token of the last argument.
|
Chris@0
|
185 $end = $this->phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($this->closeBracket - 1), null, true);
|
Chris@0
|
186 $lastArgEnd = $end;
|
Chris@0
|
187 $nextSeperator = $this->openBracket;
|
Chris@0
|
188 $counter = 1;
|
Chris@0
|
189 while (($nextSeperator = $this->phpcsFile->findNext(T_COMMA, ($nextSeperator + 1), $this->closeBracket)) !== false) {
|
Chris@0
|
190 // Make sure the comma belongs directly to this function call,
|
Chris@0
|
191 // and is not inside a nested function call or array.
|
Chris@0
|
192 $brackets = $tokens[$nextSeperator]['nested_parenthesis'];
|
Chris@0
|
193 $lastBracket = array_pop($brackets);
|
Chris@0
|
194 if ($lastBracket !== $this->closeBracket) {
|
Chris@0
|
195 continue;
|
Chris@0
|
196 }
|
Chris@0
|
197
|
Chris@0
|
198 // Update the end token of the current argument.
|
Chris@0
|
199 $end = $this->phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($nextSeperator - 1), null, true);
|
Chris@0
|
200 // Save the calculated findings for the current argument.
|
Chris@0
|
201 $this->arguments[$counter] = array(
|
Chris@0
|
202 'start' => $start,
|
Chris@0
|
203 'end' => $end,
|
Chris@0
|
204 );
|
Chris@0
|
205 if ($counter === $number) {
|
Chris@0
|
206 break;
|
Chris@0
|
207 }
|
Chris@0
|
208
|
Chris@0
|
209 $counter++;
|
Chris@0
|
210 $start = $this->phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($nextSeperator + 1), null, true);
|
Chris@0
|
211 $end = $lastArgEnd;
|
Chris@0
|
212 }//end while
|
Chris@0
|
213
|
Chris@0
|
214 // If the counter did not reach the passed number something is wrong.
|
Chris@0
|
215 if ($counter !== $number) {
|
Chris@0
|
216 return false;
|
Chris@0
|
217 }
|
Chris@0
|
218
|
Chris@0
|
219 $this->arguments[$counter] = array(
|
Chris@0
|
220 'start' => $start,
|
Chris@0
|
221 'end' => $end,
|
Chris@0
|
222 );
|
Chris@0
|
223 return $this->arguments[$counter];
|
Chris@0
|
224
|
Chris@0
|
225 }//end getArgument()
|
Chris@0
|
226
|
Chris@0
|
227
|
Chris@0
|
228 }//end class
|