public function processAdditional(&$tokens, $eolChar)
{
if (PHP_CODESNIFFER_VERBOSITY > 1) {
echo "\t*** START ADDITIONAL PHP PROCESSING ***" . PHP_EOL;
}
$numTokens = count($tokens);
for ($i = $numTokens - 1; $i >= 0; $i--) {
// Check for any unset scope conditions due to alternate IF/ENDIF syntax.
if (isset($tokens[$i]['scope_opener']) === true && isset($tokens[$i]['scope_condition']) === false) {
$tokens[$i]['scope_condition'] = $tokens[$tokens[$i]['scope_opener']]['scope_condition'];
}
if ($tokens[$i]['code'] === T_FUNCTION) {
// Context sensitive keywords support.
for ($x = $i + 1; $x < $numTokens; $x++) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
// Non-whitespace content.
break;
}
}
if ($x === $numTokens) {
// We got to the end without finding any more
// non-whitespace content.
continue;
}
if (in_array($tokens[$x]['code'], array(T_STRING, T_OPEN_PARENTHESIS, T_BITWISE_AND), true) === false) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$x]['line'];
$type = $tokens[$x]['type'];
echo "\t* token {$x} on line {$line} changed from {$type} to T_STRING" . PHP_EOL;
}
$tokens[$x]['code'] = T_STRING;
$tokens[$x]['type'] = 'T_STRING';
}
/*
Detect functions that are actually closures and
assign them a different token.
*/
if (isset($tokens[$i]['scope_opener']) === true) {
for ($x = $i + 1; $x < $numTokens; $x++) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false && $tokens[$x]['code'] !== T_BITWISE_AND) {
break;
}
}
if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
$tokens[$i]['code'] = T_CLOSURE;
$tokens[$i]['type'] = 'T_CLOSURE';
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$i]['line'];
echo "\t* token {$i} on line {$line} changed from T_FUNCTION to T_CLOSURE" . PHP_EOL;
}
for ($x = $tokens[$i]['scope_opener'] + 1; $x < $tokens[$i]['scope_closer']; $x++) {
if (isset($tokens[$x]['conditions'][$i]) === false) {
continue;
}
$tokens[$x]['conditions'][$i] = T_CLOSURE;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$type = $tokens[$x]['type'];
echo "\t\t* cleaned {$x} ({$type}) *" . PHP_EOL;
}
}
}
$tokenAfterReturnTypeHint = $tokens[$i]['scope_opener'];
} else {
if (isset($tokens[$i]['parenthesis_closer']) === true) {
$tokenAfterReturnTypeHint = null;
for ($x = $tokens[$i]['parenthesis_closer'] + 1; $x < $numTokens; $x++) {
if ($tokens[$x]['code'] === T_SEMICOLON) {
$tokenAfterReturnTypeHint = $x;
break;
}
}
if ($tokenAfterReturnTypeHint === null) {
// Probably a syntax error.
continue;
}
} else {
// Probably a syntax error.
continue;
}
}
//end if
/*
Detect function return values and assign them
a special token, because PHP doesn't.
*/
for ($x = $tokenAfterReturnTypeHint - 1; $x > $i; $x--) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
if (in_array($tokens[$x]['code'], array(T_STRING, T_ARRAY, T_CALLABLE, T_SELF, T_PARENT), true) === true) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$x]['line'];
$type = $tokens[$x]['type'];
echo "\t* token {$x} on line {$line} changed from {$type} to T_RETURN_TYPE" . PHP_EOL;
}
$tokens[$x]['code'] = T_RETURN_TYPE;
$tokens[$x]['type'] = 'T_RETURN_TYPE';
}
break;
}
}
continue;
} else {
if ($tokens[$i]['code'] === T_CLASS && isset($tokens[$i]['scope_opener']) === true) {
/*
Detect anonymous classes and assign them a different token.
*/
for ($x = $i + 1; $x < $numTokens; $x++) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
break;
}
}
if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS || $tokens[$x]['code'] === T_OPEN_CURLY_BRACKET || $tokens[$x]['code'] === T_EXTENDS || $tokens[$x]['code'] === T_IMPLEMENTS) {
$tokens[$i]['code'] = T_ANON_CLASS;
$tokens[$i]['type'] = 'T_ANON_CLASS';
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$i]['line'];
echo "\t* token {$i} on line {$line} changed from T_CLASS to T_ANON_CLASS" . PHP_EOL;
}
for ($x = $tokens[$i]['scope_opener'] + 1; $x < $tokens[$i]['scope_closer']; $x++) {
if (isset($tokens[$x]['conditions'][$i]) === false) {
continue;
}
$tokens[$x]['conditions'][$i] = T_ANON_CLASS;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$type = $tokens[$x]['type'];
echo "\t\t* cleaned {$x} ({$type}) *" . PHP_EOL;
}
}
}
continue;
} else {
if ($tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) {
// Unless there is a variable or a bracket before this token,
// it is the start of an array being defined using the short syntax.
for ($x = $i - 1; $x > 0; $x--) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
break;
}
}
$allowed = array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET, T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET, T_CLOSE_PARENTHESIS => T_CLOSE_PARENTHESIS, T_VARIABLE => T_VARIABLE, T_STRING => T_STRING);
if (isset($allowed[$tokens[$x]['code']]) === false && isset($tokens[$i]['bracket_closer']) === true) {
$tokens[$i]['code'] = T_OPEN_SHORT_ARRAY;
$tokens[$i]['type'] = 'T_OPEN_SHORT_ARRAY';
$closer = $tokens[$i]['bracket_closer'];
$tokens[$closer]['code'] = T_CLOSE_SHORT_ARRAY;
$tokens[$closer]['type'] = 'T_CLOSE_SHORT_ARRAY';
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$i]['line'];
echo "\t* token {$i} on line {$line} changed from T_OPEN_SQUARE_BRACKET to T_OPEN_SHORT_ARRAY" . PHP_EOL;
$line = $tokens[$closer]['line'];
echo "\t* token {$closer} on line {$line} changed from T_CLOSE_SQUARE_BRACKET to T_CLOSE_SHORT_ARRAY" . PHP_EOL;
}
}
continue;
} else {
if ($tokens[$i]['code'] === T_STATIC) {
for ($x = $i - 1; $x > 0; $x--) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
break;
}
}
if ($tokens[$x]['code'] === T_INSTANCEOF) {
$tokens[$i]['code'] = T_STRING;
$tokens[$i]['type'] = 'T_STRING';
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$i]['line'];
echo "\t* token {$i} on line {$line} changed from T_STATIC to T_STRING" . PHP_EOL;
}
}
continue;
} else {
if ($tokens[$i]['code'] === T_ECHO && $tokens[$i]['content'] === '<?=') {
// HHVM tokenizes <?= as T_ECHO but it should be T_OPEN_TAG_WITH_ECHO.
$tokens[$i]['code'] = T_OPEN_TAG_WITH_ECHO;
$tokens[$i]['type'] = 'T_OPEN_TAG_WITH_ECHO';
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$i]['line'];
echo "\t* token {$i} on line {$line} changed from T_ECHO to T_OPEN_TAG_WITH_ECHO" . PHP_EOL;
}
} else {
if ($tokens[$i]['code'] === T_TRUE || $tokens[$i]['code'] === T_FALSE || $tokens[$i]['code'] === T_NULL) {
for ($x = $i + 1; $i < $numTokens; $x++) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
// Non-whitespace content.
break;
}
}
$context = array(T_OBJECT_OPERATOR => true, T_NS_SEPARATOR => true, T_PAAMAYIM_NEKUDOTAYIM => true);
if (isset($context[$tokens[$x]['code']]) === true) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$i]['line'];
$type = $tokens[$i]['type'];
echo "\t* token {$i} on line {$line} changed from {$type} to T_STRING" . PHP_EOL;
}
$tokens[$i]['code'] = T_STRING;
$tokens[$i]['type'] = 'T_STRING';
}
} else {
if ($tokens[$i]['code'] === T_CONST) {
// Context sensitive keywords support.
for ($x = $i + 1; $i < $numTokens; $x++) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
// Non-whitespace content.
break;
}
}
if ($tokens[$x]['code'] !== T_STRING) {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$x]['line'];
$type = $tokens[$x]['type'];
echo "\t* token {$x} on line {$line} changed from {$type} to T_STRING" . PHP_EOL;
}
$tokens[$x]['code'] = T_STRING;
$tokens[$x]['type'] = 'T_STRING';
}
}
}
}
}
}
}
}
//end if
if ($tokens[$i]['code'] !== T_CASE && $tokens[$i]['code'] !== T_DEFAULT || isset($tokens[$i]['scope_opener']) === false) {
// Only interested in CASE and DEFAULT statements from here on in.
continue;
}
$scopeOpener = $tokens[$i]['scope_opener'];
$scopeCloser = $tokens[$i]['scope_closer'];
// If the first char after the opener is a curly brace
// and that brace has been ignored, it is actually
// opening this case statement and the opener and closer are
// probably set incorrectly.
for ($x = $scopeOpener + 1; $x < $numTokens; $x++) {
if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
// Non-whitespace content.
break;
}
}
if ($tokens[$x]['code'] === T_CASE || $tokens[$x]['code'] === T_DEFAULT) {
// Special case for multiple CASE statements that share the same
// closer. Because we are going backwards through the file, this next
// CASE/DEFAULT statement is already fixed, so just use its closer
// and don't worry about fixing anything.
$newCloser = $tokens[$x]['scope_closer'];
$tokens[$i]['scope_closer'] = $newCloser;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$oldType = $tokens[$scopeCloser]['type'];
$newType = $tokens[$newCloser]['type'];
$line = $tokens[$i]['line'];
echo "\t* token {$i} (T_CASE) on line {$line} closer changed from {$scopeCloser} ({$oldType}) to {$newCloser} ({$newType})" . PHP_EOL;
}
continue;
}
if ($tokens[$x]['code'] !== T_OPEN_CURLY_BRACKET || isset($tokens[$x]['scope_condition']) === true) {
// Not a CASE/DEFAULT with a curly brace opener.
continue;
}
// The closer for this CASE/DEFAULT should be the closing curly brace and
// not whatever it already is. The opener needs to be the opening curly
// brace so everything matches up.
$newCloser = $tokens[$x]['bracket_closer'];
foreach (array($i, $x, $newCloser) as $index) {
$tokens[$index]['scope_condition'] = $i;
$tokens[$index]['scope_opener'] = $x;
$tokens[$index]['scope_closer'] = $newCloser;
}
unset($tokens[$scopeOpener]['scope_condition']);
unset($tokens[$scopeOpener]['scope_opener']);
unset($tokens[$scopeOpener]['scope_closer']);
unset($tokens[$scopeCloser]['scope_condition']);
unset($tokens[$scopeCloser]['scope_opener']);
unset($tokens[$scopeCloser]['scope_closer']);
unset($tokens[$x]['bracket_opener']);
unset($tokens[$x]['bracket_closer']);
unset($tokens[$newCloser]['bracket_opener']);
unset($tokens[$newCloser]['bracket_closer']);
$tokens[$scopeCloser]['conditions'][] = $i;
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$line = $tokens[$i]['line'];
$tokenType = $tokens[$i]['type'];
$oldType = $tokens[$scopeOpener]['type'];
$newType = $tokens[$x]['type'];
echo "\t* token {$i} ({$tokenType}) on line {$line} opener changed from {$scopeOpener} ({$oldType}) to {$x} ({$newType})" . PHP_EOL;
$oldType = $tokens[$scopeCloser]['type'];
$newType = $tokens[$newCloser]['type'];
echo "\t* token {$i} ({$tokenType}) on line {$line} closer changed from {$scopeCloser} ({$oldType}) to {$newCloser} ({$newType})" . PHP_EOL;
}
// Now fix up all the tokens that think they are
// inside the CASE/DEFAULT statement when they are really outside.
for ($x = $newCloser; $x < $scopeCloser; $x++) {
foreach ($tokens[$x]['conditions'] as $num => $oldCond) {
if ($oldCond === $tokens[$i]['code']) {
$oldConditions = $tokens[$x]['conditions'];
unset($tokens[$x]['conditions'][$num]);
if (PHP_CODESNIFFER_VERBOSITY > 1) {
$type = $tokens[$x]['type'];
$oldConds = '';
foreach ($oldConditions as $condition) {
$oldConds .= token_name($condition) . ',';
}
$oldConds = rtrim($oldConds, ',');
$newConds = '';
foreach ($tokens[$x]['conditions'] as $condition) {
$newConds .= token_name($condition) . ',';
}
$newConds = rtrim($newConds, ',');
echo "\t\t* cleaned {$x} ({$type}) *" . PHP_EOL;
echo "\t\t\t=> conditions changed from {$oldConds} to {$newConds}" . PHP_EOL;
}
break;
}
//end if
}
//end foreach
}
//end for
}
//end for
if (PHP_CODESNIFFER_VERBOSITY > 1) {
echo "\t*** END ADDITIONAL PHP PROCESSING ***" . PHP_EOL;
}
}