annotate vendor/drupal/coder/coder_sniffer/Drupal/Sniffs/Semantics/FunctionCall.php @ 19:fa3358dc1485 tip

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