findEndOfStatement() public method

Returns the position of the last non-whitespace token in a statement.
public findEndOfStatement ( integer $start, integer | array $ignore = null ) : integer
$start integer The position to start searching from in the token stack.
$ignore integer | array Token types that should not be considered stop points.
return integer
 /**
  * Processes single-line calls.
  *
  * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
  * @param int                  $stackPtr    The position of the current token
  *                                          in the stack passed in $tokens.
  * @param int                  $openBracket The position of the opening bracket
  *                                          in the stack passed in $tokens.
  * @param array                $tokens      The stack of tokens that make up
  *                                          the file.
  *
  * @return void
  */
 public function isMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens)
 {
     // If the first argument is on a new line, this is a multi-line
     // function call, even if there is only one argument.
     $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $openBracket + 1, null, true);
     if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) {
         return true;
     }
     $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
     $end = $phpcsFile->findEndOfStatement($openBracket + 1);
     while ($tokens[$end]['code'] === T_COMMA) {
         // If the next bit of code is not on the same line, this is a
         // multi-line function call.
         $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $end + 1, $closeBracket, true);
         if ($next === false) {
             return false;
         }
         if ($tokens[$next]['line'] !== $tokens[$end]['line']) {
             return true;
         }
         $end = $phpcsFile->findEndOfStatement($next);
     }
     // We've reached the last argument, so see if the next content
     // (should be the close bracket) is also on the same line.
     $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $end + 1, $closeBracket, true);
     if ($next !== false && $tokens[$next]['line'] !== $tokens[$end]['line']) {
         return true;
     }
     return false;
 }
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param   PHP_CodeSniffer_File  $phpcsFile  The file being scanned.
  * @param   integer               $stackPtr   The position of the current token in the stack passed in $tokens.
  *
  * @return  void
  */
 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 1, null, true);
     if ($tokens[$nextToken]['code'] === T_OPEN_PARENTHESIS) {
         $error = '"%s" is a statement not a function; no parentheses are required';
         $data = array($tokens[$stackPtr]['content']);
         $fix = $phpcsFile->addFixableError($error, $stackPtr, 'BracketsNotRequired', $data);
         if ($fix === true) {
             $end = $phpcsFile->findEndOfStatement($nextToken);
             $ignore = PHP_CodeSniffer_Tokens::$emptyTokens;
             $ignore[] = T_SEMICOLON;
             $closer = $phpcsFile->findPrevious($ignore, $end - 1, null, true);
             $phpcsFile->fixer->beginChangeset();
             $phpcsFile->fixer->replaceToken($nextToken, '');
             if ($tokens[$stackPtr + 1]['code'] === T_WHITESPACE) {
                 $phpcsFile->fixer->replaceToken($stackPtr + 1, '');
             }
             if ($tokens[$closer]['code'] === T_CLOSE_PARENTHESIS) {
                 $phpcsFile->fixer->replaceToken($closer, '');
             }
             $phpcsFile->fixer->addContent($stackPtr, ' ');
             $phpcsFile->fixer->endChangeset();
         }
     }
 }
 /**
  * Determine if this is a multi-line function declaration.
  *
  * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
  * @param int                  $stackPtr    The position of the current token
  *                                          in the stack passed in $tokens.
  * @param int                  $openBracket The position of the opening bracket
  *                                          in the stack passed in $tokens.
  * @param array                $tokens      The stack of tokens that make up
  *                                          the file.
  *
  * @return void
  */
 public function isMultiLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens)
 {
     $bracketsToCheck = array($stackPtr => $openBracket);
     // Closures may use the USE keyword and so be multi-line in this way.
     if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
         $use = $phpcsFile->findNext(T_USE, $tokens[$openBracket]['parenthesis_closer'] + 1, $tokens[$stackPtr]['scope_opener']);
         if ($use !== false) {
             $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $use + 1);
             if ($open !== false) {
                 $bracketsToCheck[$use] = $open;
             }
         }
     }
     foreach ($bracketsToCheck as $stackPtr => $openBracket) {
         // If the first argument is on a new line, this is a multi-line
         // function declaration, even if there is only one argument.
         $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $openBracket + 1, null, true);
         if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) {
             return true;
         }
         $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
         $end = $phpcsFile->findEndOfStatement($openBracket + 1);
         while ($tokens[$end]['code'] === T_COMMA) {
             // If the next bit of code is not on the same line, this is a
             // multi-line function declaration.
             $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $end + 1, $closeBracket, true);
             if ($next === false) {
                 continue 2;
             }
             if ($tokens[$next]['line'] !== $tokens[$end]['line']) {
                 return true;
             }
             $end = $phpcsFile->findEndOfStatement($next);
         }
         // We've reached the last argument, so see if the next content
         // (should be the close bracket) is also on the same line.
         $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $end + 1, $closeBracket, true);
         if ($next !== false && $tokens[$next]['line'] !== $tokens[$end]['line']) {
             return true;
         }
     }
     //end foreach
     return false;
 }
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token in
  *                                        the stack passed in $tokens.
  *
  * @return void
  */
 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     // Only check use statements in the global scope.
     if (empty($tokens[$stackPtr]['conditions']) === false) {
         return;
     }
     // Seek to the end of the statement and get the string before the semi colon.
     $semiColon = $phpcsFile->findEndOfStatement($stackPtr);
     if ($tokens[$semiColon]['code'] !== T_SEMICOLON) {
         return;
     }
     $classPtr = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $semiColon - 1, null, true);
     // Seek along the statement to get the last part, which is the
     // class/interface name.
     while (isset($tokens[$classPtr + 1]) === true && in_array($tokens[$classPtr + 1]['code'], array(T_STRING, T_NS_SEPARATOR)) === true) {
         $classPtr++;
     }
     if ($tokens[$classPtr]['code'] !== T_STRING) {
         return;
     }
     $classUsed = $phpcsFile->findNext(T_STRING, $classPtr + 1, null, false, $tokens[$classPtr]['content']);
     while ($classUsed !== false) {
         $beforeUsage = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $classUsed - 1, null, true);
         // If a backslash is used before the class name then this is some other
         // use statement.
         if ($tokens[$beforeUsage]['code'] !== T_USE && $tokens[$beforeUsage]['code'] !== T_NS_SEPARATOR) {
             return;
         }
         // Trait use statement within a class.
         if ($tokens[$beforeUsage]['code'] === T_USE && empty($tokens[$beforeUsage]['conditions']) === false) {
             return;
         }
         $classUsed = $phpcsFile->findNext(T_STRING, $classUsed + 1, null, false, $tokens[$classPtr]['content']);
     }
     //end while
     $warning = 'Unused use statement';
     $fix = $phpcsFile->addFixableWarning($warning, $stackPtr, 'UnusedUse');
     if ($fix === true) {
         // Remove the whole use statement line.
         $phpcsFile->fixer->beginChangeset();
         for ($i = $stackPtr; $i <= $semiColon; $i++) {
             $phpcsFile->fixer->replaceToken($i, '');
         }
         // Also remove whitespace after the semicolon (new lines).
         while (isset($tokens[$i]) === true && $tokens[$i]['code'] === T_WHITESPACE) {
             $phpcsFile->fixer->replaceToken($i, '');
             if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) !== false) {
                 break;
             }
             $i++;
         }
         $phpcsFile->fixer->endChangeset();
     }
 }
 /**
  * @param \PHP_CodeSniffer_File $phpCsFile
  * @param int $stackPointer
  *
  * @return bool
  */
 private function isFacadeNotInBridgeReturned(\PHP_CodeSniffer_File $phpCsFile, $stackPointer)
 {
     $tokens = $phpCsFile->getTokens();
     $returnPointer = $phpCsFile->findNext(T_RETURN, $stackPointer);
     $endOfLinePointer = $phpCsFile->findEndOfStatement($returnPointer);
     $statementTokens = array_slice($tokens, $returnPointer, $endOfLinePointer - $returnPointer);
     $statement = $this->parseTokensContent($statementTokens);
     if (preg_match('/return \\$container->getLocator\\(\\)->(.*?)\\(\\)->facade\\(\\)/', $statement)) {
         return true;
     }
     return false;
 }
 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     if ($phpcsFile->findNext(T_NAMESPACE, 0) === false) {
         return;
     }
     $tokens = $phpcsFile->getTokens();
     $endOfTryStatement = $phpcsFile->findEndOfStatement($stackPtr);
     $posOfCatchVariable = $phpcsFile->findNext(T_VARIABLE, $stackPtr, $endOfTryStatement);
     $posOfExceptionClassName = $phpcsFile->findNext(T_STRING, $stackPtr, $posOfCatchVariable);
     $posOfNsSeparator = $phpcsFile->findNext(T_NS_SEPARATOR, $stackPtr, $posOfExceptionClassName);
     if ($posOfNsSeparator === false) {
         $exceptionClassName = trim($tokens[$posOfExceptionClassName]['content']);
         $posOfClassInUse = $phpcsFile->findNext(T_STRING, 0, $stackPtr, false, $exceptionClassName);
         if ($posOfClassInUse === false || $tokens[$posOfClassInUse]['level'] != 0) {
             $phpcsFile->addError('Namespace for "' . $exceptionClassName . '" class is not specified.', $posOfExceptionClassName);
         }
     }
 }
 /**
  * @param int                  $stackPtr
  * @param PHP_CodeSniffer_File $phpcsFile
  *
  * @return array
  */
 protected function getMethods($stackPtr, $phpcsFile)
 {
     $methods = [];
     $classEnd = $phpcsFile->findEndOfStatement($stackPtr);
     while ($stackPtr < $classEnd) {
         $function = $phpcsFile->findNext([T_FUNCTION], $stackPtr, null);
         if (false === $function) {
             break;
         }
         $stackPtr = $function + 1;
         if (in_array($phpcsFile->getDeclarationName($function), ['setUp', 'tearDown'])) {
             continue;
         }
         $methodProperties = $phpcsFile->getMethodProperties($function);
         $methods[$methodProperties['scope']][] = $function;
     }
     return $methods;
 }
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document.
  * @param int                  $stackPtr  The position of the current token in
  *                                        the stack passed in $tokens.
  *
  * @return void
  */
 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $startToken = $tokens[$stackPtr]['parenthesis_opener'];
     $endToken = $tokens[$stackPtr]['parenthesis_closer'];
     $startToken = $phpcsFile->findNext(T_AS, $startToken, $endToken);
     $valueToken = $phpcsFile->findNext(T_VARIABLE, $startToken, $endToken);
     $tmpToken = $phpcsFile->findNext(T_VARIABLE, $valueToken + 1, $endToken);
     // If $tmpToken is not false, the foreach loop uses $key => $value.
     $keyToken = false;
     if ($tmpToken !== false) {
         $keyToken = $valueToken;
         $valueToken = $tmpToken;
         unset($tmpToken);
     }
     // If there are no scope_opener & scope_closer, the developer uses no parenthesis for the loop, like
     //      foreach($myArray as $key => $value)
     //          echo $key . ' - ' . $value;
     //
     // In this case we have to determine the next statement / scope_opener & scope_closer on our own.
     if (array_key_exists('scope_opener', $tokens[$stackPtr]) === false && array_key_exists('scope_closer', $tokens[$stackPtr]) === false) {
         $scopeOpener = $phpcsFile->findNext(array(T_WHITESPACE), $endToken + 1, null, true, null, true);
         $scopeCloser = $phpcsFile->findEndOfStatement($scopeOpener);
     } else {
         $scopeOpener = $tokens[$stackPtr]['scope_opener'];
         $scopeCloser = $tokens[$stackPtr]['scope_closer'];
     }
     // If a $key is used in foreach loop but not used in the foreach body.
     if ($keyToken !== false && $phpcsFile->findNext(T_VARIABLE, $scopeOpener, $scopeCloser, false, $tokens[$keyToken]['content']) === false) {
         $message = 'The usage of the key variable %s is not necessary. Please remove this.';
         $phpcsFile->addError($message, $stackPtr, 'KeyVariableNotNecessary', array($tokens[$keyToken]['content']));
     }
     // If the $value is named $_ AND used in the foreach body, this variable has to be renamed.
     if ($tokens[$valueToken]['content'] === '$_' && $phpcsFile->findNext(T_VARIABLE, $scopeOpener, $scopeCloser, false, $tokens[$valueToken]['content']) !== false) {
         $message = 'The variable $_ is used in the foreach body. Please rename this variable to a more useful name.';
         $phpcsFile->addError($message, $stackPtr, 'ValueVariableWrongName');
         // If the $value is NOT named $_, but no one will use this in the foreach body, this variable has to be renamed.
     } else {
         if ($tokens[$valueToken]['content'] !== '$_' && $phpcsFile->findNext(T_VARIABLE, $scopeOpener, $scopeCloser, false, $tokens[$valueToken]['content']) === false) {
             $message = 'The variable %s is NOT used in the foreach body. Please rename this variable to $_.';
             $phpcsFile->addError($message, $stackPtr, 'ValueVariableNotUsed', array($tokens[$valueToken]['content']));
         }
     }
 }
 /**
  * Is the code in the passes position a require(config.php) statement?
  *
  * @param PHP_CodeSniffer_File $file The file being scanned.
  * @param int $pointer The position in the stack.
  * @return bool true if is a config.php inclusion.
  */
 protected function is_config_php_incluson(PHP_CodeSniffer_File $file, $pointer)
 {
     $tokens = $file->getTokens();
     if ($tokens[$pointer]['code'] !== T_REQUIRE and $tokens[$pointer]['code'] !== T_REQUIRE_ONCE) {
         return false;
     }
     // It's a require() or require_once() statement. Is it require(config.php)?
     $requirecontent = $file->getTokensAsString($pointer, $file->findEndOfStatement($pointer) - $pointer);
     if (strpos($requirecontent, '/config.php') === false) {
         return false;
     }
     return true;
 }
 /**
  * Processes multi-line calls.
  *
  * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
  * @param int                  $stackPtr    The position of the current token
  *                                          in the stack passed in $tokens.
  * @param int                  $openBracket The position of the opening bracket
  *                                          in the stack passed in $tokens.
  * @param array                $tokens      The stack of tokens that make up
  *                                          the file.
  *
  * @return void
  */
 public function processMultiLineCall(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $openBracket, $tokens)
 {
     // We need to work out how far indented the function
     // call itself is, so we can work out how far to
     // indent the arguments.
     $start = $phpcsFile->findStartOfStatement($stackPtr);
     foreach (array('stackPtr', 'start') as $checkToken) {
         $x = ${$checkToken};
         for ($i = $x - 1; $i >= 0; $i--) {
             if ($tokens[$i]['line'] !== $tokens[$x]['line']) {
                 $i++;
                 break;
             }
         }
         if ($i <= 0) {
             $functionIndent = 0;
         } else {
             if ($tokens[$i]['code'] === T_WHITESPACE) {
                 $functionIndent = strlen($tokens[$i]['content']);
             } else {
                 if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING) {
                     $functionIndent = 0;
                 } else {
                     $trimmed = ltrim($tokens[$i]['content']);
                     if ($trimmed === '') {
                         if ($tokens[$i]['code'] === T_INLINE_HTML) {
                             $functionIndent = strlen($tokens[$i]['content']);
                         } else {
                             $functionIndent = $tokens[$i]['column'] - 1;
                         }
                     } else {
                         $functionIndent = strlen($tokens[$i]['content']) - strlen($trimmed);
                     }
                 }
             }
         }
         $varName = $checkToken . 'Indent';
         ${$varName} = $functionIndent;
     }
     //end foreach
     $functionIndent = max($startIndent, $stackPtrIndent);
     $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $openBracket + 1, null, true);
     if ($tokens[$next]['line'] === $tokens[$openBracket]['line']) {
         $error = 'Opening parenthesis of a multi-line function call must be the last content on the line';
         $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentAfterOpenBracket');
         if ($fix === true) {
             $phpcsFile->fixer->addContent($openBracket, $phpcsFile->eolChar . str_repeat(' ', $functionIndent + $this->indent));
         }
     }
     $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
     $prev = $phpcsFile->findPrevious(T_WHITESPACE, $closeBracket - 1, null, true);
     if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
         $error = 'Closing parenthesis of a multi-line function call must be on a line by itself';
         $fix = $phpcsFile->addFixableError($error, $closeBracket, 'CloseBracketLine');
         if ($fix === true) {
             $phpcsFile->fixer->addContentBefore($closeBracket, $phpcsFile->eolChar . str_repeat(' ', $functionIndent + $this->indent));
         }
     }
     // Each line between the parenthesis should be indented n spaces.
     $lastLine = $tokens[$openBracket]['line'];
     $argStart = null;
     $argEnd = null;
     $inArg = false;
     for ($i = $openBracket + 1; $i < $closeBracket; $i++) {
         if ($i > $argStart && $i < $argEnd) {
             $inArg = true;
         } else {
             $inArg = false;
         }
         if ($tokens[$i]['line'] !== $lastLine) {
             $lastLine = $tokens[$i]['line'];
             // Ignore heredoc indentation.
             if (isset(PHP_CodeSniffer_Tokens::$heredocTokens[$tokens[$i]['code']]) === true) {
                 continue;
             }
             // Ignore multi-line string indentation.
             if (isset(PHP_CodeSniffer_Tokens::$stringTokens[$tokens[$i]['code']]) === true && $tokens[$i]['code'] === $tokens[$i - 1]['code']) {
                 continue;
             }
             // Ignore inline HTML.
             if ($tokens[$i]['code'] === T_INLINE_HTML) {
                 continue;
             }
             // We changed lines, so this should be a whitespace indent token, but first make
             // sure it isn't a blank line because we don't need to check indent unless there
             // is actually some code to indent.
             if ($tokens[$i]['code'] === T_WHITESPACE) {
                 $nextCode = $phpcsFile->findNext(T_WHITESPACE, $i + 1, $closeBracket + 1, true);
                 if ($tokens[$nextCode]['line'] !== $lastLine) {
                     if ($inArg === false) {
                         $error = 'Empty lines are not allowed in multi-line function calls';
                         $fix = $phpcsFile->addFixableError($error, $i, 'EmptyLine');
                         if ($fix === true) {
                             $phpcsFile->fixer->replaceToken($i, '');
                         }
                     }
                     continue;
                 }
             } else {
                 $nextCode = $i;
             }
             if ($tokens[$nextCode]['line'] === $tokens[$closeBracket]['line']) {
                 // Closing brace needs to be indented to the same level
                 // as the function call.
                 $inArg = false;
                 $expectedIndent = $functionIndent;
             } else {
                 $expectedIndent = $functionIndent + $this->indent;
             }
             if ($tokens[$i]['code'] !== T_WHITESPACE && $tokens[$i]['code'] !== T_DOC_COMMENT_WHITESPACE) {
                 // Just check if it is a multi-line block comment. If so, we can
                 // calculate the indent from the whitespace before the content.
                 if ($tokens[$i]['code'] === T_COMMENT && $tokens[$i - 1]['code'] === T_COMMENT) {
                     $trimmed = ltrim($tokens[$i]['content']);
                     $foundIndent = strlen($tokens[$i]['content']) - strlen($trimmed);
                 } else {
                     $foundIndent = 0;
                 }
             } else {
                 $foundIndent = strlen($tokens[$i]['content']);
             }
             if ($foundIndent < $expectedIndent || $inArg === false && $expectedIndent !== $foundIndent) {
                 $error = 'Multi-line function call not indented correctly; expected %s spaces but found %s';
                 $data = array($expectedIndent, $foundIndent);
                 $fix = $phpcsFile->addFixableError($error, $i, 'Indent', $data);
                 if ($fix === true) {
                     $padding = str_repeat(' ', $expectedIndent);
                     if ($foundIndent === 0) {
                         $phpcsFile->fixer->addContentBefore($i, $padding);
                     } else {
                         if ($tokens[$i]['code'] === T_COMMENT) {
                             $comment = $padding . ltrim($tokens[$i]['content']);
                             $phpcsFile->fixer->replaceToken($i, $comment);
                         } else {
                             $phpcsFile->fixer->replaceToken($i, $padding);
                         }
                     }
                 }
             }
             //end if
             if ($inArg === false) {
                 $argStart = $nextCode;
                 $argEnd = $phpcsFile->findEndOfStatement($nextCode);
             }
         }
         //end if
         // If we are within an argument we should be ignoring commas
         // as these are not signaling the end of an argument.
         if ($inArg === false && $tokens[$i]['code'] === T_COMMA) {
             $next = $phpcsFile->findNext(array(T_WHITESPACE, T_COMMENT), $i + 1, $closeBracket, true);
             if ($next === false) {
                 continue;
             }
             if ($this->allowMultipleArguments === false) {
                 // Comma has to be the last token on the line.
                 if ($tokens[$i]['line'] === $tokens[$next]['line']) {
                     $error = 'Only one argument is allowed per line in a multi-line function call';
                     $fix = $phpcsFile->addFixableError($error, $next, 'MultipleArguments');
                     if ($fix === true) {
                         $phpcsFile->fixer->beginChangeset();
                         for ($x = $next - 1; $x > $i; $x--) {
                             if ($tokens[$x]['code'] !== T_WHITESPACE) {
                                 break;
                             }
                             $phpcsFile->fixer->replaceToken($x, '');
                         }
                         $phpcsFile->fixer->addContentBefore($next, $phpcsFile->eolChar . str_repeat(' ', $functionIndent + $this->indent));
                         $phpcsFile->fixer->endChangeset();
                     }
                 }
             }
             //end if
             $argStart = $next;
             $argEnd = $phpcsFile->findEndOfStatement($next);
         }
         //end if
     }
     //end for
 }
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token in the
  *                                        stack passed in $tokens.
  *
  * @return void
  */
 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     // We can't process SWITCH statements unless we know where they start and end.
     if (isset($tokens[$stackPtr]['scope_opener']) === false || isset($tokens[$stackPtr]['scope_closer']) === false) {
         return;
     }
     $switch = $tokens[$stackPtr];
     $nextCase = $stackPtr;
     $caseAlignment = $switch['column'] + $this->indent;
     $caseCount = 0;
     $foundDefault = false;
     while (($nextCase = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_SWITCH), $nextCase + 1, $switch['scope_closer'])) !== false) {
         // Skip nested SWITCH statements; they are handled on their own.
         if ($tokens[$nextCase]['code'] === T_SWITCH) {
             $nextCase = $tokens[$nextCase]['scope_closer'];
             continue;
         }
         if ($tokens[$nextCase]['code'] === T_DEFAULT) {
             $type = 'Default';
             $foundDefault = true;
         } else {
             $type = 'Case';
             $caseCount++;
         }
         if ($tokens[$nextCase]['content'] !== strtolower($tokens[$nextCase]['content'])) {
             $expected = strtolower($tokens[$nextCase]['content']);
             $error = strtoupper($type) . ' keyword must be lowercase; expected "%s" but found "%s"';
             $data = array($expected, $tokens[$nextCase]['content']);
             $fix = $phpcsFile->addFixableError($error, $nextCase, $type . 'NotLower', $data);
             if ($fix === true) {
                 $phpcsFile->fixer->replaceToken($nextCase, $expected);
             }
         }
         if ($tokens[$nextCase]['column'] !== $caseAlignment) {
             $error = strtoupper($type) . ' keyword must be indented ' . $this->indent . ' spaces from SWITCH keyword';
             $fix = $phpcsFile->addFixableError($error, $nextCase, $type . 'Indent');
             if ($fix === true) {
                 $padding = str_repeat(' ', $caseAlignment - 1);
                 if ($tokens[$nextCase]['column'] === 1 || $tokens[$nextCase - 1]['code'] !== T_WHITESPACE) {
                     $phpcsFile->fixer->addContentBefore($nextCase, $padding);
                 } else {
                     $phpcsFile->fixer->replaceToken($nextCase - 1, $padding);
                 }
             }
         }
         if ($type === 'Case' && ($tokens[$nextCase + 1]['type'] !== 'T_WHITESPACE' || $tokens[$nextCase + 1]['content'] !== ' ')) {
             $error = 'CASE keyword must be followed by a single space';
             $fix = $phpcsFile->addFixableError($error, $nextCase, 'SpacingAfterCase');
             if ($fix === true) {
                 if ($tokens[$nextCase + 1]['type'] !== 'T_WHITESPACE') {
                     $phpcsFile->fixer->addContent($nextCase, ' ');
                 } else {
                     $phpcsFile->fixer->replaceToken($nextCase + 1, ' ');
                 }
             }
         }
         if (isset($tokens[$nextCase]['scope_opener']) === false) {
             $error = 'Possible parse error: CASE missing opening colon';
             $phpcsFile->addWarning($error, $nextCase, 'MissingColon');
             continue;
         }
         $opener = $tokens[$nextCase]['scope_opener'];
         if ($tokens[$opener - 1]['type'] === 'T_WHITESPACE') {
             $error = 'There must be no space before the colon in a ' . strtoupper($type) . ' statement';
             $fix = $phpcsFile->addFixableError($error, $nextCase, 'SpaceBeforeColon' . $type);
             if ($fix === true) {
                 $phpcsFile->fixer->replaceToken($opener - 1, '');
             }
         }
         $nextBreak = $tokens[$nextCase]['scope_closer'];
         if ($tokens[$nextBreak]['code'] === T_BREAK || $tokens[$nextBreak]['code'] === T_RETURN || $tokens[$nextBreak]['code'] === T_CONTINUE || $tokens[$nextBreak]['code'] === T_THROW || $tokens[$nextBreak]['code'] === T_EXIT) {
             if ($tokens[$nextBreak]['scope_condition'] === $nextCase) {
                 // Only need to check a couple of things once, even if the
                 // break is shared between multiple case statements, or even
                 // the default case.
                 if ($tokens[$nextBreak]['column'] !== $caseAlignment) {
                     $error = 'Case breaking statement must be indented ' . $this->indent . ' spaces from SWITCH keyword';
                     $fix = $phpcsFile->addFixableError($error, $nextBreak, 'BreakIndent');
                     if ($fix === true) {
                         $padding = str_repeat(' ', $caseAlignment - 1);
                         if ($tokens[$nextBreak]['column'] === 1 || $tokens[$nextBreak - 1]['code'] !== T_WHITESPACE) {
                             $phpcsFile->fixer->addContentBefore($nextBreak, $padding);
                         } else {
                             $phpcsFile->fixer->replaceToken($nextBreak - 1, $padding);
                         }
                     }
                 }
                 $prev = $phpcsFile->findPrevious(T_WHITESPACE, $nextBreak - 1, $stackPtr, true);
                 if ($tokens[$prev]['line'] !== $tokens[$nextBreak]['line'] - 1) {
                     $error = 'Blank lines are not allowed before case breaking statements';
                     $phpcsFile->addError($error, $nextBreak, 'SpacingBeforeBreak');
                 }
                 $nextLine = $tokens[$tokens[$stackPtr]['scope_closer']]['line'];
                 $semicolon = $phpcsFile->findEndOfStatement($nextBreak);
                 for ($i = $semicolon + 1; $i < $tokens[$stackPtr]['scope_closer']; $i++) {
                     if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
                         $nextLine = $tokens[$i]['line'];
                         break;
                     }
                 }
                 if ($type === 'Case') {
                     // Ensure the BREAK statement is followed by
                     // a single blank line, or the end switch brace.
                     if ($nextLine !== $tokens[$semicolon]['line'] + 2 && $i !== $tokens[$stackPtr]['scope_closer']) {
                         $error = 'Case breaking statements must be followed by a single blank line';
                         $fix = $phpcsFile->addFixableError($error, $nextBreak, 'SpacingAfterBreak');
                         if ($fix === true) {
                             $phpcsFile->fixer->beginChangeset();
                             for ($i = $semicolon + 1; $i <= $tokens[$stackPtr]['scope_closer']; $i++) {
                                 if ($tokens[$i]['line'] === $nextLine) {
                                     $phpcsFile->fixer->addNewlineBefore($i);
                                     break;
                                 }
                                 if ($tokens[$i]['line'] === $tokens[$semicolon]['line']) {
                                     continue;
                                 }
                                 $phpcsFile->fixer->replaceToken($i, '');
                             }
                             $phpcsFile->fixer->endChangeset();
                         }
                     }
                     //end if
                 } else {
                     // Ensure the BREAK statement is not followed by a blank line.
                     if ($nextLine !== $tokens[$semicolon]['line'] + 1) {
                         $error = 'Blank lines are not allowed after the DEFAULT case\'s breaking statement';
                         $phpcsFile->addError($error, $nextBreak, 'SpacingAfterDefaultBreak');
                     }
                 }
                 //end if
                 $caseLine = $tokens[$nextCase]['line'];
                 $nextLine = $tokens[$nextBreak]['line'];
                 for ($i = $opener + 1; $i < $nextBreak; $i++) {
                     if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
                         $nextLine = $tokens[$i]['line'];
                         break;
                     }
                 }
                 if ($nextLine !== $caseLine + 1) {
                     $error = 'Blank lines are not allowed after ' . strtoupper($type) . ' statements';
                     $phpcsFile->addError($error, $nextCase, 'SpacingAfter' . $type);
                 }
             }
             //end if
             if ($tokens[$nextBreak]['code'] === T_BREAK) {
                 if ($type === 'Case') {
                     // Ensure empty CASE statements are not allowed.
                     // They must have some code content in them. A comment is not enough.
                     // But count RETURN statements as valid content if they also
                     // happen to close the CASE statement.
                     $foundContent = false;
                     for ($i = $tokens[$nextCase]['scope_opener'] + 1; $i < $nextBreak; $i++) {
                         if ($tokens[$i]['code'] === T_CASE) {
                             $i = $tokens[$i]['scope_opener'];
                             continue;
                         }
                         if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$i]['code']]) === false) {
                             $foundContent = true;
                             break;
                         }
                     }
                     if ($foundContent === false) {
                         $error = 'Empty CASE statements are not allowed';
                         $phpcsFile->addError($error, $nextCase, 'EmptyCase');
                     }
                 } else {
                     // Ensure empty DEFAULT statements are not allowed.
                     // They must (at least) have a comment describing why
                     // the default case is being ignored.
                     $foundContent = false;
                     for ($i = $tokens[$nextCase]['scope_opener'] + 1; $i < $nextBreak; $i++) {
                         if ($tokens[$i]['type'] !== 'T_WHITESPACE') {
                             $foundContent = true;
                             break;
                         }
                     }
                     if ($foundContent === false) {
                         $error = 'Comment required for empty DEFAULT case';
                         $phpcsFile->addError($error, $nextCase, 'EmptyDefault');
                     }
                 }
                 //end if
             }
             //end if
         } else {
             if ($type === 'Default') {
                 $error = 'DEFAULT case must have a breaking statement';
                 $phpcsFile->addError($error, $nextCase, 'DefaultNoBreak');
             }
         }
         //end if
     }
     //end while
     if ($foundDefault === false) {
         $error = 'All SWITCH statements must contain a DEFAULT case';
         $phpcsFile->addError($error, $stackPtr, 'MissingDefault');
     }
     if ($tokens[$switch['scope_closer']]['column'] !== $switch['column']) {
         $error = 'Closing brace of SWITCH statement must be aligned with SWITCH keyword';
         $phpcsFile->addError($error, $switch['scope_closer'], 'CloseBraceAlign');
     }
     if ($caseCount === 0) {
         $error = 'SWITCH statements must contain at least one CASE statement';
         $phpcsFile->addError($error, $stackPtr, 'MissingCase');
     }
 }
 /**
  * @param \PHP_CodeSniffer_File $phpCsFile
  *
  * @return array
  */
 protected function parseUseStatements(\PHP_CodeSniffer_File $phpCsFile)
 {
     $useStatements = [];
     $tokens = $phpCsFile->getTokens();
     foreach ($tokens as $id => $token) {
         if ($token['type'] !== 'T_USE') {
             continue;
         }
         $endIndex = $phpCsFile->findEndOfStatement($id);
         $useStatement = '';
         for ($i = $id + 2; $i < $endIndex; $i++) {
             $useStatement .= $tokens[$i]['content'];
         }
         $useStatement = trim($useStatement);
         if (strpos($useStatement, ' as ') !== false) {
             list($useStatement, $className) = explode(' as ', $useStatement);
         } else {
             $className = $useStatement;
             if (strpos($useStatement, '\\') !== false) {
                 $lastSeparator = strrpos($useStatement, '\\');
                 $className = substr($useStatement, $lastSeparator + 1);
             }
         }
         $useStatement = '\\' . ltrim($useStatement, '\\');
         $useStatements[$className] = $useStatement;
     }
     return $useStatements;
 }
 /**
  * @param \PHP_CodeSniffer_File $phpCsFile
  * @param int $stackPointer
  *
  * @return string
  */
 protected function getNamespace(\PHP_CodeSniffer_File $phpCsFile, $stackPointer)
 {
     $namespacePosition = $phpCsFile->findPrevious(T_NAMESPACE, $stackPointer);
     $endOfNamespacePosition = $phpCsFile->findEndOfStatement($namespacePosition);
     $tokens = $phpCsFile->getTokens();
     $namespaceTokens = array_splice($tokens, $namespacePosition + 2, $endOfNamespacePosition - $namespacePosition - 2);
     $namespace = '';
     foreach ($namespaceTokens as $token) {
         $namespace .= $token['content'];
     }
     return $namespace;
 }
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token in
  *                                        the stack passed in $tokens.
  *
  * @return void
  */
 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     // If this token is preceded with an "or", it only relates to one line
     // and should be ignored. For example: fopen() or die().
     $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr - 1, null, true);
     if ($tokens[$prev]['code'] === T_LOGICAL_OR || $tokens[$prev]['code'] === T_BOOLEAN_OR) {
         return;
     }
     // Check if this token is actually part of a one-line IF or ELSE statement.
     for ($i = $stackPtr - 1; $i > 0; $i--) {
         if ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS) {
             $i = $tokens[$i]['parenthesis_opener'];
             continue;
         } else {
             if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
                 continue;
             }
         }
         break;
     }
     if ($tokens[$i]['code'] === T_IF || $tokens[$i]['code'] === T_ELSE || $tokens[$i]['code'] === T_ELSEIF) {
         return;
     }
     if ($tokens[$stackPtr]['code'] === T_RETURN) {
         $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true);
         if ($tokens[$next]['code'] === T_SEMICOLON) {
             $next = $phpcsFile->findNext(T_WHITESPACE, $next + 1, null, true);
             if ($tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) {
                 // If this is the closing brace of a function
                 // then this return statement doesn't return anything
                 // and is not required anyway.
                 $owner = $tokens[$next]['scope_condition'];
                 if ($tokens[$owner]['code'] === T_FUNCTION) {
                     $warning = 'Empty return statement not required here';
                     $phpcsFile->addWarning($warning, $stackPtr, 'ReturnNotRequired');
                     return;
                 }
             }
         }
     }
     if (isset($tokens[$stackPtr]['scope_opener']) === true) {
         $owner = $tokens[$stackPtr]['scope_condition'];
         if ($tokens[$owner]['code'] === T_CASE || $tokens[$owner]['code'] === T_DEFAULT) {
             // This token closes the scope of a CASE or DEFAULT statement
             // so any code between this statement and the next CASE, DEFAULT or
             // end of SWITCH token will not be executable.
             $end = $phpcsFile->findEndOfStatement($stackPtr);
             $next = $phpcsFile->findNext(array(T_CASE, T_DEFAULT, T_CLOSE_CURLY_BRACKET), $end + 1);
             if ($next !== false) {
                 $lastLine = $tokens[$end]['line'];
                 for ($i = $stackPtr + 1; $i < $next; $i++) {
                     if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
                         continue;
                     }
                     $line = $tokens[$i]['line'];
                     if ($line > $lastLine) {
                         $type = substr($tokens[$stackPtr]['type'], 2);
                         $warning = 'Code after %s statement cannot be executed';
                         $data = array($type);
                         $phpcsFile->addWarning($warning, $i, 'Unreachable', $data);
                         $lastLine = $line;
                     }
                 }
             }
             //end if
             // That's all we have to check for these types of statements.
             return;
         }
         //end if
     }
     //end if
     // This token may be part of an inline condition.
     // If we find a closing parenthesis that belongs to a condition
     // we should ignore this token.
     $prev = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr - 1, null, true);
     if (isset($tokens[$prev]['parenthesis_owner']) === true) {
         $owner = $tokens[$prev]['parenthesis_owner'];
         $ignore = array(T_IF => true, T_ELSE => true, T_ELSEIF => true);
         if (isset($ignore[$tokens[$owner]['code']]) === true) {
             return;
         }
     }
     $ourConditions = array_keys($tokens[$stackPtr]['conditions']);
     if (empty($ourConditions) === false) {
         $condition = array_pop($ourConditions);
         if (isset($tokens[$condition]['scope_closer']) === false) {
             return;
         }
         // Special case for BREAK statements sitting directly inside SWITCH
         // statements. If we get to this point, we know the BREAK is not being
         // used to close a CASE statement, so it is most likely non-executable
         // code itself (as is the case when you put return; break; at the end of
         // a case). So we need to ignore this token.
         if ($tokens[$condition]['code'] === T_SWITCH && $tokens[$stackPtr]['code'] === T_BREAK) {
             return;
         }
         $closer = $tokens[$condition]['scope_closer'];
         // If the closer for our condition is shared with other openers,
         // we will need to throw errors from this token to the next
         // shared opener (if there is one), not to the scope closer.
         $nextOpener = null;
         for ($i = $stackPtr + 1; $i < $closer; $i++) {
             if (isset($tokens[$i]['scope_closer']) === true) {
                 if ($tokens[$i]['scope_closer'] === $closer) {
                     // We found an opener that shares the same
                     // closing token as us.
                     $nextOpener = $i;
                     break;
                 }
             }
         }
         //end for
         if ($nextOpener === null) {
             $end = $closer;
         } else {
             $end = $nextOpener - 1;
         }
     } else {
         // This token is in the global scope.
         if ($tokens[$stackPtr]['code'] === T_BREAK) {
             return;
         }
         // Throw an error for all lines until the end of the file.
         $end = $phpcsFile->numTokens - 1;
     }
     //end if
     // Find the semicolon that ends this statement, skipping
     // nested statements like FOR loops and closures.
     for ($start = $stackPtr + 1; $start < $phpcsFile->numTokens; $start++) {
         if ($start === $end) {
             break;
         }
         if ($tokens[$start]['code'] === T_OPEN_PARENTHESIS) {
             $start = $tokens[$start]['parenthesis_closer'];
             continue;
         }
         if ($tokens[$start]['code'] === T_OPEN_CURLY_BRACKET) {
             $start = $tokens[$start]['bracket_closer'];
             continue;
         }
         if ($tokens[$start]['code'] === T_SEMICOLON) {
             break;
         }
     }
     //end for
     $lastLine = $tokens[$start]['line'];
     for ($i = $start + 1; $i < $end; $i++) {
         if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$i]['code']]) === true || isset(PHP_CodeSniffer_Tokens::$bracketTokens[$tokens[$i]['code']]) === true) {
             continue;
         }
         // Skip whole functions and classes/interfaces because they are not
         // technically executed code, but rather declarations that may be used.
         if ($tokens[$i]['code'] === T_FUNCTION || $tokens[$i]['code'] === T_CLASS || $tokens[$i]['code'] === T_INTERFACE) {
             $i = $tokens[$i]['scope_closer'];
             continue;
         }
         $line = $tokens[$i]['line'];
         if ($line > $lastLine) {
             $type = substr($tokens[$stackPtr]['type'], 2);
             $warning = 'Code after %s statement cannot be executed';
             $data = array($type);
             $phpcsFile->addWarning($warning, $i, 'Unreachable', $data);
             $lastLine = $line;
         }
     }
     //end for
 }
 /**
  * Process the return comment of this function comment.
  *
  * @param PHP_CodeSniffer_File $phpcsFile    The file being scanned.
  * @param int                  $stackPtr     The position of the current token
  *                                           in the stack passed in $tokens.
  * @param int                  $commentStart The position in the stack where the comment started.
  *
  * @return void
  */
 protected function processReturnCore(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
 {
     $tokens = $phpcsFile->getTokens();
     $methodName = $phpcsFile->getDeclarationName($stackPtr);
     $isSpecialMethod = $methodName === '__construct' || $methodName === '__destruct' || 'test' === substr($methodName, 0, 4);
     $return = null;
     foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
         if ($tokens[$tag]['content'] === '@return') {
             if ($return !== null) {
                 $error = 'Only 1 @return tag is allowed in a function comment';
                 $phpcsFile->addError($error, $tag, 'DuplicateReturn');
                 return;
             }
             $return = $tag;
         }
     }
     if ($isSpecialMethod === true) {
         return;
     }
     if ($return !== null) {
         $content = $tokens[$return + 2]['content'];
         if (empty($content) === true || $tokens[$return + 2]['code'] !== T_DOC_COMMENT_STRING) {
             $error = 'Return type missing for @return tag in function comment';
             $phpcsFile->addError($error, $return, 'MissingReturnType');
         }
     } else {
         $methodOpener = $phpcsFile->findNext([T_OPEN_CURLY_BRACKET], $tokens[$commentStart]['comment_closer']);
         $methodClosener = $phpcsFile->findEndOfStatement($methodOpener);
         if ($this->checkClosureFunctions($methodOpener, $methodClosener, $phpcsFile, $tokens) === true) {
             return;
         }
         $error = 'Missing @return tag in function comment';
         $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn');
     }
 }
 /**
  * @param \PHP_CodeSniffer_File $phpCsFile
  * @param int $stackPointer
  * @param string $missingUse
  *
  * @return void
  */
 protected function addMissingUse(\PHP_CodeSniffer_File $phpCsFile, $stackPointer, $missingUse)
 {
     $previousUsePosition = $phpCsFile->findPrevious(T_USE, $stackPointer);
     if ($previousUsePosition !== false) {
         $endOfLastUse = $phpCsFile->findEndOfStatement($previousUsePosition);
         $phpCsFile->fixer->addNewline($endOfLastUse);
         $phpCsFile->fixer->addContent($endOfLastUse, 'use ' . $missingUse . ';');
     }
 }