Example #1
0
 /**
  * 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(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     // If this is an inline condition (ie. there is no scope opener), then
     // return, as this is not a new scope.
     if (isset($tokens[$stackPtr]['scope_closer']) === false) {
         return;
     }
     // We need to actually find the first piece of content on this line,
     // as if this is a method with tokens before it (public, static etc)
     // or an if with an else before it, then we need to start the scope
     // checking from there, rather than the current token.
     $lineStart = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true);
     $startColumn = $tokens[$lineStart]['column'];
     $scopeStart = $tokens[$stackPtr]['scope_opener'];
     $scopeEnd = $tokens[$stackPtr]['scope_closer'];
     // Check that the closing brace is on it's own line.
     $lastContent = $phpcsFile->findPrevious(array(T_INLINE_HTML, T_WHITESPACE, T_OPEN_TAG), $scopeEnd - 1, $scopeStart, true);
     if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) {
         $error = 'Closing brace must be on a line by itself';
         $fix = $phpcsFile->addFixableError($error, $scopeEnd, 'ContentBefore');
         if ($fix === true) {
             $phpcsFile->fixer->addNewlineBefore($scopeEnd);
         }
         return;
     }
     // Check now that the closing brace is lined up correctly.
     $lineStart = $phpcsFile->findFirstOnLine(T_WHITESPACE, $scopeEnd, true);
     $braceIndent = $tokens[$lineStart]['column'];
     if ($tokens[$stackPtr]['code'] !== T_DEFAULT && $tokens[$stackPtr]['code'] !== T_CASE && $braceIndent !== $startColumn) {
         $error = 'Closing brace indented incorrectly; expected %s spaces, found %s';
         $data = array($startColumn - 1, $braceIndent - 1);
         $fix = $phpcsFile->addFixableError($error, $scopeEnd, 'Indent', $data);
         if ($fix === true) {
             $diff = $startColumn - $braceIndent;
             if ($diff > 0) {
                 $phpcsFile->fixer->addContentBefore($scopeEnd, str_repeat(' ', $diff));
             } else {
                 $phpcsFile->fixer->substrToken($scopeEnd - 1, 0, $diff);
             }
         }
     }
     //end if
 }
Example #2
0
 /**
  * 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(File $phpcsFile, $stackPtr)
 {
     $debug = Config::getConfigData('scope_indent_debug');
     if ($debug !== null) {
         $this->debug = (bool) $debug;
     }
     if ($this->tabWidth === null) {
         if (isset($phpcsFile->config->tabWidth) === false || $phpcsFile->config->tabWidth === 0) {
             // We have no idea how wide tabs are, so assume 4 spaces for fixing.
             // It shouldn't really matter because indent checks elsewhere in the
             // standard should fix things up.
             $this->tabWidth = 4;
         } else {
             $this->tabWidth = $phpcsFile->config->tabWidth;
         }
     }
     $currentIndent = 0;
     $lastOpenTag = $stackPtr;
     $lastCloseTag = null;
     $openScopes = array();
     $adjustments = array();
     $setIndents = array();
     $tokens = $phpcsFile->getTokens();
     $first = $phpcsFile->findFirstOnLine(T_INLINE_HTML, $stackPtr);
     $trimmed = ltrim($tokens[$first]['content']);
     if ($trimmed === '') {
         $currentIndent = $tokens[$stackPtr]['column'] - 1;
     } else {
         $currentIndent = strlen($tokens[$first]['content']) - strlen($trimmed);
     }
     if ($this->debug === true) {
         $line = $tokens[$stackPtr]['line'];
         echo "Start with token {$stackPtr} on line {$line} with indent {$currentIndent}" . PHP_EOL;
     }
     if (empty($this->ignoreIndentation) === true) {
         $this->ignoreIndentation = array(T_INLINE_HTML => true);
         foreach ($this->ignoreIndentationTokens as $token) {
             if (is_int($token) === false) {
                 if (defined($token) === false) {
                     continue;
                 }
                 $token = constant($token);
             }
             $this->ignoreIndentation[$token] = true;
         }
     }
     //end if
     $this->exact = (bool) $this->exact;
     $this->tabIndent = (bool) $this->tabIndent;
     for ($i = $stackPtr + 1; $i < $phpcsFile->numTokens; $i++) {
         if ($i === false) {
             // Something has gone very wrong; maybe a parse error.
             break;
         }
         $checkToken = null;
         $checkIndent = null;
         $exact = (bool) $this->exact;
         if ($exact === true && isset($tokens[$i]['nested_parenthesis']) === true) {
             // Don't check indents exactly between parenthesis as they
             // tend to have custom rules, such as with multi-line function calls
             // and control structure conditions.
             $exact = false;
         }
         // Detect line changes and figure out where the indent is.
         if ($tokens[$i]['column'] === 1) {
             $trimmed = ltrim($tokens[$i]['content']);
             if ($trimmed === '') {
                 if (isset($tokens[$i + 1]) === true && $tokens[$i]['line'] === $tokens[$i + 1]['line']) {
                     $checkToken = $i + 1;
                     $tokenIndent = $tokens[$i + 1]['column'] - 1;
                 }
             } else {
                 $checkToken = $i;
                 $tokenIndent = strlen($tokens[$i]['content']) - strlen($trimmed);
             }
         }
         // Closing parenthesis should just be indented to at least
         // the same level as where they were opened (but can be more).
         if ($checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$checkToken]['parenthesis_opener']) === true || $tokens[$i]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$i]['parenthesis_opener']) === true && isset($tokens[$i]['parenthesis_owner']) === true && $tokens[$tokens[$i]['parenthesis_owner']]['code'] === T_ARRAY) {
             if ($checkToken !== null) {
                 $parenCloser = $checkToken;
             } else {
                 $parenCloser = $i;
             }
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Closing parenthesis found on line {$line}" . PHP_EOL;
             }
             $parenOpener = $tokens[$parenCloser]['parenthesis_opener'];
             if ($tokens[$parenCloser]['line'] !== $tokens[$parenOpener]['line']) {
                 $parens = 0;
                 if (isset($tokens[$parenCloser]['nested_parenthesis']) === true && empty($tokens[$parenCloser]['nested_parenthesis']) === false) {
                     end($tokens[$parenCloser]['nested_parenthesis']);
                     $parens = key($tokens[$parenCloser]['nested_parenthesis']);
                     if ($this->debug === true) {
                         $line = $tokens[$parens]['line'];
                         echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
                     }
                 }
                 $condition = 0;
                 if (isset($tokens[$parenCloser]['conditions']) === true && empty($tokens[$parenCloser]['conditions']) === false) {
                     end($tokens[$parenCloser]['conditions']);
                     $condition = key($tokens[$parenCloser]['conditions']);
                     if ($this->debug === true) {
                         $line = $tokens[$condition]['line'];
                         $type = $tokens[$condition]['type'];
                         echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
                     }
                 }
                 if ($parens > $condition) {
                     if ($this->debug === true) {
                         echo "\t* using parenthesis *" . PHP_EOL;
                     }
                     $parenOpener = $parens;
                     $condition = 0;
                 } else {
                     if ($condition > 0) {
                         if ($this->debug === true) {
                             echo "\t* using condition *" . PHP_EOL;
                         }
                         $parenOpener = $condition;
                         $parens = 0;
                     }
                 }
                 $exact = false;
                 if ($condition > 0 && $lastOpenTag > $condition) {
                     if ($this->debug === true) {
                         echo "\t* open tag is inside condition; using open tag *" . PHP_EOL;
                     }
                     $checkIndent = $tokens[$lastOpenTag]['column'] - 1;
                     if (isset($adjustments[$condition]) === true) {
                         $checkIndent += $adjustments[$condition];
                     }
                     $currentIndent = $checkIndent;
                     if ($this->debug === true) {
                         $type = $tokens[$lastOpenTag]['type'];
                         echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$lastOpenTag} ({$type})" . PHP_EOL;
                     }
                 } else {
                     if ($condition > 0 && isset($tokens[$condition]['scope_opener']) === true && isset($setIndents[$tokens[$condition]['scope_opener']]) === true) {
                         $checkIndent = $setIndents[$tokens[$condition]['scope_opener']];
                         if (isset($adjustments[$condition]) === true) {
                             $checkIndent += $adjustments[$condition];
                         }
                         $currentIndent = $checkIndent;
                         if ($this->debug === true) {
                             $type = $tokens[$condition]['type'];
                             echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$condition} ({$type})" . PHP_EOL;
                         }
                     } else {
                         $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $parenOpener, true);
                         $checkIndent = $tokens[$first]['column'] - 1;
                         if (isset($adjustments[$first]) === true) {
                             $checkIndent += $adjustments[$first];
                         }
                         if ($this->debug === true) {
                             $line = $tokens[$first]['line'];
                             $type = $tokens[$first]['type'];
                             echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
                         }
                         if ($first === $tokens[$parenCloser]['parenthesis_opener']) {
                             // This is unlikely to be the start of the statement, so look
                             // back further to find it.
                             $first--;
                         }
                         $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                         if ($prev !== $first) {
                             // This is not the start of the statement.
                             if ($this->debug === true) {
                                 $line = $tokens[$prev]['line'];
                                 $type = $tokens[$prev]['type'];
                                 echo "\t* previous is {$type} on line {$line} *" . PHP_EOL;
                             }
                             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                             $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                             if ($this->debug === true) {
                                 $line = $tokens[$first]['line'];
                                 $type = $tokens[$first]['type'];
                                 echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
                             }
                         }
                         if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
                             if ($this->debug === true) {
                                 echo "\t* first token is a scope closer *" . PHP_EOL;
                             }
                             if (isset($tokens[$first]['scope_condition']) === true) {
                                 $scopeCloser = $first;
                                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true);
                                 $currentIndent = $tokens[$first]['column'] - 1;
                                 if (isset($adjustments[$first]) === true) {
                                     $currentIndent += $adjustments[$first];
                                 }
                                 // Make sure it is divisible by our expected indent.
                                 if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) {
                                     $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
                                 }
                                 $setIndents[$first] = $currentIndent;
                                 if ($this->debug === true) {
                                     $type = $tokens[$first]['type'];
                                     echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
                                 }
                             }
                             //end if
                         } else {
                             // Don't force current indent to divisible because there could be custom
                             // rules in place between parenthesis, such as with arrays.
                             $currentIndent = $tokens[$first]['column'] - 1;
                             if (isset($adjustments[$first]) === true) {
                                 $currentIndent += $adjustments[$first];
                             }
                             $setIndents[$first] = $currentIndent;
                             if ($this->debug === true) {
                                 $type = $tokens[$first]['type'];
                                 echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
                             }
                         }
                         //end if
                     }
                 }
                 //end if
             } else {
                 if ($this->debug === true) {
                     echo "\t * ignoring single-line definition *" . PHP_EOL;
                 }
             }
             //end if
         }
         //end if
         // Closing short array bracket should just be indented to at least
         // the same level as where it was opened (but can be more).
         if ($tokens[$i]['code'] === T_CLOSE_SHORT_ARRAY || $checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_SHORT_ARRAY) {
             if ($checkToken !== null) {
                 $arrayCloser = $checkToken;
             } else {
                 $arrayCloser = $i;
             }
             if ($this->debug === true) {
                 $line = $tokens[$arrayCloser]['line'];
                 echo "Closing short array bracket found on line {$line}" . PHP_EOL;
             }
             $arrayOpener = $tokens[$arrayCloser]['bracket_opener'];
             if ($tokens[$arrayCloser]['line'] !== $tokens[$arrayOpener]['line']) {
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $arrayOpener, true);
                 $checkIndent = $tokens[$first]['column'] - 1;
                 if (isset($adjustments[$first]) === true) {
                     $checkIndent += $adjustments[$first];
                 }
                 $exact = false;
                 if ($this->debug === true) {
                     $line = $tokens[$first]['line'];
                     $type = $tokens[$first]['type'];
                     echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
                 }
                 if ($first === $tokens[$arrayCloser]['bracket_opener']) {
                     // This is unlikely to be the start of the statement, so look
                     // back further to find it.
                     $first--;
                 }
                 $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                 if ($prev !== $first) {
                     // This is not the start of the statement.
                     if ($this->debug === true) {
                         $line = $tokens[$prev]['line'];
                         $type = $tokens[$prev]['type'];
                         echo "\t* previous is {$type} on line {$line} *" . PHP_EOL;
                     }
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                     $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                     if ($this->debug === true) {
                         $line = $tokens[$first]['line'];
                         $type = $tokens[$first]['type'];
                         echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
                     }
                 }
                 if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
                     // The first token is a scope closer and would have already
                     // been processed and set the indent level correctly, so
                     // don't adjust it again.
                     if ($this->debug === true) {
                         echo "\t* first token is a scope closer; ignoring closing short array bracket *" . PHP_EOL;
                     }
                     if (isset($setIndents[$first]) === true) {
                         $currentIndent = $setIndents[$first];
                         if ($this->debug === true) {
                             echo "\t=> indent reset to {$currentIndent}" . PHP_EOL;
                         }
                     }
                 } else {
                     // Don't force current indent to be divisible because there could be custom
                     // rules in place for arrays.
                     $currentIndent = $tokens[$first]['column'] - 1;
                     if (isset($adjustments[$first]) === true) {
                         $currentIndent += $adjustments[$first];
                     }
                     $setIndents[$first] = $currentIndent;
                     if ($this->debug === true) {
                         $type = $tokens[$first]['type'];
                         echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
                     }
                 }
                 //end if
             } else {
                 if ($this->debug === true) {
                     echo "\t * ignoring single-line definition *" . PHP_EOL;
                 }
             }
             //end if
         }
         //end if
         // Adjust lines within scopes while auto-fixing.
         if ($checkToken !== null && $exact === false && (empty($tokens[$checkToken]['conditions']) === false || isset($tokens[$checkToken]['scope_opener']) === true && $tokens[$checkToken]['scope_opener'] === $checkToken)) {
             if (empty($tokens[$checkToken]['conditions']) === false) {
                 end($tokens[$checkToken]['conditions']);
                 $condition = key($tokens[$checkToken]['conditions']);
             } else {
                 $condition = $tokens[$checkToken]['scope_condition'];
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $condition, true);
             if (isset($adjustments[$first]) === true && ($adjustments[$first] < 0 && $tokenIndent > $currentIndent || $adjustments[$first] > 0 && $tokenIndent < $currentIndent)) {
                 $padding = $tokenIndent + $adjustments[$first];
                 if ($padding > 0) {
                     if ($this->tabIndent === true) {
                         $numTabs = floor($padding / $this->tabWidth);
                         $numSpaces = $padding - $numTabs * $this->tabWidth;
                         $padding = str_repeat("\t", $numTabs) . str_repeat(' ', $numSpaces);
                     } else {
                         $padding = str_repeat(' ', $padding);
                     }
                 } else {
                     $padding = '';
                 }
                 if ($checkToken === $i) {
                     $phpcsFile->fixer->replaceToken($checkToken, $padding . $trimmed);
                 } else {
                     // Easier to just replace the entire indent.
                     $phpcsFile->fixer->replaceToken($checkToken - 1, $padding);
                 }
                 if ($this->debug === true) {
                     $length = strlen($padding);
                     $line = $tokens[$checkToken]['line'];
                     $type = $tokens[$checkToken]['type'];
                     echo "Indent adjusted to {$length} for {$type} on line {$line}" . PHP_EOL;
                 }
                 $adjustments[$checkToken] = $adjustments[$first];
                 if ($this->debug === true) {
                     $line = $tokens[$checkToken]['line'];
                     $type = $tokens[$checkToken]['type'];
                     echo "\t=> Add adjustment of " . $adjustments[$checkToken] . " for token {$checkToken} ({$type}) on line {$line}" . PHP_EOL;
                 }
             }
             //end if
         }
         //end if
         // Scope closers reset the required indent to the same level as the opening condition.
         if ($checkToken !== null && isset($openScopes[$checkToken]) === true || isset($tokens[$checkToken]['scope_condition']) === true && isset($tokens[$checkToken]['scope_closer']) === true && $tokens[$checkToken]['scope_closer'] === $checkToken && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line'] || ($checkToken === null && isset($openScopes[$i]) === true || isset($tokens[$i]['scope_condition']) === true && isset($tokens[$i]['scope_closer']) === true && $tokens[$i]['scope_closer'] === $i && $tokens[$i]['line'] !== $tokens[$tokens[$i]['scope_opener']]['line'])) {
             if ($this->debug === true) {
                 if ($checkToken === null) {
                     $type = $tokens[$tokens[$i]['scope_condition']]['type'];
                     $line = $tokens[$i]['line'];
                 } else {
                     $type = $tokens[$tokens[$checkToken]['scope_condition']]['type'];
                     $line = $tokens[$checkToken]['line'];
                 }
                 echo "Close scope ({$type}) on line {$line}" . PHP_EOL;
             }
             $scopeCloser = $checkToken;
             if ($scopeCloser === null) {
                 $scopeCloser = $i;
             } else {
                 array_pop($openScopes);
             }
             if (isset($tokens[$scopeCloser]['scope_condition']) === true) {
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true);
                 $currentIndent = $tokens[$first]['column'] - 1;
                 if (isset($adjustments[$first]) === true) {
                     $currentIndent += $adjustments[$first];
                 }
                 // Make sure it is divisible by our expected indent.
                 if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) {
                     $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
                 }
                 $setIndents[$scopeCloser] = $currentIndent;
                 if ($this->debug === true) {
                     $type = $tokens[$scopeCloser]['type'];
                     echo "\t=> indent set to {$currentIndent} by token {$scopeCloser} ({$type})" . PHP_EOL;
                 }
                 // We only check the indent of scope closers if they are
                 // curly braces because other constructs tend to have different rules.
                 if ($tokens[$scopeCloser]['code'] === T_CLOSE_CURLY_BRACKET) {
                     $exact = true;
                 } else {
                     $checkToken = null;
                 }
             }
             //end if
         }
         //end if
         // Handle scope for JS object notation.
         if ($phpcsFile->tokenizerType === 'JS' && ($checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_OBJECT && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['bracket_opener']]['line'] || $checkToken === null && $tokens[$i]['code'] === T_CLOSE_OBJECT && $tokens[$i]['line'] !== $tokens[$tokens[$i]['bracket_opener']]['line'])) {
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Close JS object on line {$line}" . PHP_EOL;
             }
             $scopeCloser = $checkToken;
             if ($scopeCloser === null) {
                 $scopeCloser = $i;
             } else {
                 array_pop($openScopes);
             }
             $parens = 0;
             if (isset($tokens[$scopeCloser]['nested_parenthesis']) === true && empty($tokens[$scopeCloser]['nested_parenthesis']) === false) {
                 end($tokens[$scopeCloser]['nested_parenthesis']);
                 $parens = key($tokens[$scopeCloser]['nested_parenthesis']);
                 if ($this->debug === true) {
                     $line = $tokens[$parens]['line'];
                     echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
                 }
             }
             $condition = 0;
             if (isset($tokens[$scopeCloser]['conditions']) === true && empty($tokens[$scopeCloser]['conditions']) === false) {
                 end($tokens[$scopeCloser]['conditions']);
                 $condition = key($tokens[$scopeCloser]['conditions']);
                 if ($this->debug === true) {
                     $line = $tokens[$condition]['line'];
                     $type = $tokens[$condition]['type'];
                     echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
                 }
             }
             if ($parens > $condition) {
                 if ($this->debug === true) {
                     echo "\t* using parenthesis *" . PHP_EOL;
                 }
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $parens, true);
                 $condition = 0;
             } else {
                 if ($condition > 0) {
                     if ($this->debug === true) {
                         echo "\t* using condition *" . PHP_EOL;
                     }
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $condition, true);
                     $parens = 0;
                 } else {
                     if ($this->debug === true) {
                         $line = $tokens[$tokens[$scopeCloser]['bracket_opener']]['line'];
                         echo "\t* token is not in parenthesis or condition; using opener on line {$line} *" . PHP_EOL;
                     }
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['bracket_opener'], true);
                 }
             }
             //end if
             $currentIndent = $tokens[$first]['column'] - 1;
             if (isset($adjustments[$first]) === true) {
                 $currentIndent += $adjustments[$first];
             }
             if ($parens > 0 || $condition > 0) {
                 $checkIndent = $tokens[$first]['column'] - 1;
                 if (isset($adjustments[$first]) === true) {
                     $checkIndent += $adjustments[$first];
                 }
                 if ($condition > 0) {
                     $checkIndent += $this->indent;
                     $currentIndent += $this->indent;
                     $exact = true;
                 }
             } else {
                 $checkIndent = $currentIndent;
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
             $setIndents[$first] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$first]['type'];
                 echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
             }
         }
         //end if
         if ($checkToken !== null && isset(Tokens::$scopeOpeners[$tokens[$checkToken]['code']]) === true && in_array($tokens[$checkToken]['code'], $this->nonIndentingScopes) === false && isset($tokens[$checkToken]['scope_opener']) === true) {
             $exact = true;
             $lastOpener = null;
             if (empty($openScopes) === false) {
                 end($openScopes);
                 $lastOpener = current($openScopes);
             }
             // A scope opener that shares a closer with another token (like multiple
             // CASEs using the same BREAK) needs to reduce the indent level so its
             // indent is checked correctly. It will then increase the indent again
             // (as all openers do) after being checked.
             if ($lastOpener !== null && isset($tokens[$lastOpener]['scope_closer']) === true && $tokens[$lastOpener]['level'] === $tokens[$checkToken]['level'] && $tokens[$lastOpener]['scope_closer'] === $tokens[$checkToken]['scope_closer']) {
                 $currentIndent -= $this->indent;
                 $setIndents[$lastOpener] = $currentIndent;
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     $type = $tokens[$lastOpener]['type'];
                     echo "Shared closer found on line {$line}" . PHP_EOL;
                     echo "\t=> indent set to {$currentIndent} by token {$lastOpener} ({$type})" . PHP_EOL;
                 }
             }
             if ($tokens[$checkToken]['code'] === T_CLOSURE && $tokenIndent > $currentIndent) {
                 // The opener is indented more than needed, which is fine.
                 // But just check that it is divisible by our expected indent.
                 $checkIndent = (int) (ceil($tokenIndent / $this->indent) * $this->indent);
                 $exact = false;
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     echo "Closure found on line {$line}" . PHP_EOL;
                     echo "\t=> checking indent of {$checkIndent}; main indent remains at {$currentIndent}" . PHP_EOL;
                 }
             }
         }
         //end if
         // Method prefix indentation has to be exact or else if will break
         // the rest of the function declaration, and potentially future ones.
         if ($checkToken !== null && isset(Tokens::$methodPrefixes[$tokens[$checkToken]['code']]) === true && $tokens[$checkToken + 1]['code'] !== T_DOUBLE_COLON) {
             $exact = true;
         }
         // JS property indentation has to be exact or else if will break
         // things like function and object indentation.
         if ($checkToken !== null && $tokens[$checkToken]['code'] === T_PROPERTY) {
             $exact = true;
         }
         // PHP tags needs to be indented to exact column positions
         // so they don't cause problems with indent checks for the code
         // within them, but they don't need to line up with the current indent.
         if ($checkToken !== null && ($tokens[$checkToken]['code'] === T_OPEN_TAG || $tokens[$checkToken]['code'] === T_OPEN_TAG_WITH_ECHO || $tokens[$checkToken]['code'] === T_CLOSE_TAG)) {
             $exact = true;
             $checkIndent = $tokens[$checkToken]['column'] - 1;
             $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
         }
         // Check the line indent.
         if ($checkIndent === null) {
             $checkIndent = $currentIndent;
         }
         $adjusted = false;
         if ($checkToken !== null && isset($this->ignoreIndentation[$tokens[$checkToken]['code']]) === false && ($tokenIndent !== $checkIndent && $exact === true || $tokenIndent < $checkIndent && $exact === false)) {
             $type = 'IncorrectExact';
             $error = 'Line indented incorrectly; expected ';
             if ($exact === false) {
                 $error .= 'at least ';
                 $type = 'Incorrect';
             }
             if ($this->tabIndent === true) {
                 $error .= '%s tabs, found %s';
                 $data = array(floor($checkIndent / $this->tabWidth), floor($tokenIndent / $this->tabWidth));
             } else {
                 $error .= '%s spaces, found %s';
                 $data = array($checkIndent, $tokenIndent);
             }
             if ($this->debug === true) {
                 $line = $tokens[$checkToken]['line'];
                 $message = vsprintf($error, $data);
                 echo "[Line {$line}] {$message}" . PHP_EOL;
             }
             $fix = $phpcsFile->addFixableError($error, $checkToken, $type, $data);
             if ($fix === true || $this->debug === true) {
                 $padding = '';
                 if ($this->tabIndent === true) {
                     $numTabs = floor($checkIndent / $this->tabWidth);
                     if ($numTabs > 0) {
                         $numSpaces = $checkIndent - $numTabs * $this->tabWidth;
                         $padding = str_repeat("\t", $numTabs) . str_repeat(' ', $numSpaces);
                     }
                 } else {
                     if ($checkIndent > 0) {
                         $padding = str_repeat(' ', $checkIndent);
                     }
                 }
                 if ($checkToken === $i) {
                     $accepted = $phpcsFile->fixer->replaceToken($checkToken, $padding . $trimmed);
                 } else {
                     // Easier to just replace the entire indent.
                     $accepted = $phpcsFile->fixer->replaceToken($checkToken - 1, $padding);
                 }
                 if ($accepted === true) {
                     $adjustments[$checkToken] = $checkIndent - $tokenIndent;
                     if ($this->debug === true) {
                         $line = $tokens[$checkToken]['line'];
                         $type = $tokens[$checkToken]['type'];
                         echo "\t=> Add adjustment of " . $adjustments[$checkToken] . " for token {$checkToken} ({$type}) on line {$line}" . PHP_EOL;
                     }
                 }
             } else {
                 // Assume the change would be applied and continue
                 // checking indents under this assumption. This gives more
                 // technically accurate error messages.
                 $adjustments[$checkToken] = $checkIndent - $tokenIndent;
             }
             //end if
         }
         //end if
         if ($checkToken !== null) {
             $i = $checkToken;
         }
         // Completely skip here/now docs as the indent is a part of the
         // content itself.
         if ($tokens[$i]['code'] === T_START_HEREDOC || $tokens[$i]['code'] === T_START_NOWDOC) {
             $i = $phpcsFile->findNext(array(T_END_HEREDOC, T_END_NOWDOC), $i + 1);
             continue;
         }
         // Completely skip multi-line strings as the indent is a part of the
         // content itself.
         if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING || $tokens[$i]['code'] === T_DOUBLE_QUOTED_STRING) {
             $i = $phpcsFile->findNext($tokens[$i]['code'], $i + 1, null, true);
             $i--;
             continue;
         }
         // Completely skip doc comments as they tend to have complex
         // indentation rules.
         if ($tokens[$i]['code'] === T_DOC_COMMENT_OPEN_TAG) {
             $i = $tokens[$i]['comment_closer'];
             continue;
         }
         // Open tags reset the indent level.
         if ($tokens[$i]['code'] === T_OPEN_TAG || $tokens[$i]['code'] === T_OPEN_TAG_WITH_ECHO) {
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Open PHP tag found on line {$line}" . PHP_EOL;
             }
             if ($checkToken === null) {
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true);
                 $currentIndent = strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']));
             } else {
                 $currentIndent = $tokens[$i]['column'] - 1;
             }
             $lastOpenTag = $i;
             if (isset($adjustments[$i]) === true) {
                 $currentIndent += $adjustments[$i];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$i] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$i]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Close tags reset the indent level, unless they are closing a tag
         // opened on the same line.
         if ($tokens[$i]['code'] === T_CLOSE_TAG) {
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Close PHP tag found on line {$line}" . PHP_EOL;
             }
             if ($tokens[$lastOpenTag]['line'] !== $tokens[$i]['line']) {
                 $currentIndent = $tokens[$i]['column'] - 1;
                 $lastCloseTag = $i;
             } else {
                 if ($lastCloseTag === null) {
                     $currentIndent = 0;
                 } else {
                     $currentIndent = $tokens[$lastCloseTag]['column'] - 1;
                 }
             }
             if (isset($adjustments[$i]) === true) {
                 $currentIndent += $adjustments[$i];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$i] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$i]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Anon classes and functions set the indent based on their own indent level.
         if ($tokens[$i]['code'] === T_CLOSURE || $tokens[$i]['code'] === T_ANON_CLASS) {
             $closer = $tokens[$i]['scope_closer'];
             if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
                 if ($this->debug === true) {
                     $type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2)));
                     $line = $tokens[$i]['line'];
                     echo "* ignoring single-line {$type} on line {$line}" . PHP_EOL;
                 }
                 $i = $closer;
                 continue;
             }
             if ($this->debug === true) {
                 $type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2)));
                 $line = $tokens[$i]['line'];
                 echo "Open {$type} on line {$line}" . PHP_EOL;
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true);
             $currentIndent = $tokens[$first]['column'] - 1 + $this->indent;
             if (isset($adjustments[$first]) === true) {
                 $currentIndent += $adjustments[$first];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (floor($currentIndent / $this->indent) * $this->indent);
             $i = $tokens[$i]['scope_opener'];
             $setIndents[$i] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$i]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Scope openers increase the indent level.
         if (isset($tokens[$i]['scope_condition']) === true && isset($tokens[$i]['scope_opener']) === true && $tokens[$i]['scope_opener'] === $i) {
             $closer = $tokens[$i]['scope_closer'];
             if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     $type = $tokens[$i]['type'];
                     echo "* ignoring single-line {$type} on line {$line}" . PHP_EOL;
                 }
                 $i = $closer;
                 continue;
             }
             $condition = $tokens[$tokens[$i]['scope_condition']]['code'];
             if (isset(Tokens::$scopeOpeners[$condition]) === true && in_array($condition, $this->nonIndentingScopes) === false) {
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     $type = $tokens[$tokens[$i]['scope_condition']]['type'];
                     echo "Open scope ({$type}) on line {$line}" . PHP_EOL;
                 }
                 $currentIndent += $this->indent;
                 $setIndents[$i] = $currentIndent;
                 $openScopes[$tokens[$i]['scope_closer']] = $tokens[$i]['scope_condition'];
                 if ($this->debug === true) {
                     $type = $tokens[$i]['type'];
                     echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
                 }
                 continue;
             }
         }
         //end if
         // JS objects set the indent level.
         if ($phpcsFile->tokenizerType === 'JS' && $tokens[$i]['code'] === T_OBJECT) {
             $closer = $tokens[$i]['bracket_closer'];
             if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     echo "* ignoring single-line JS object on line {$line}" . PHP_EOL;
                 }
                 $i = $closer;
                 continue;
             }
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Open JS object on line {$line}" . PHP_EOL;
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true);
             $currentIndent = $tokens[$first]['column'] - 1 + $this->indent;
             if (isset($adjustments[$first]) === true) {
                 $currentIndent += $adjustments[$first];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$first] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$first]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Closing an anon class or function.
         if (isset($tokens[$i]['scope_condition']) === true && $tokens[$i]['scope_closer'] === $i && ($tokens[$tokens[$i]['scope_condition']]['code'] === T_CLOSURE || $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS)) {
             if ($this->debug === true) {
                 $type = str_replace('_', ' ', strtolower(substr($tokens[$tokens[$i]['scope_condition']]['type'], 2)));
                 $line = $tokens[$i]['line'];
                 echo "Close {$type} on line {$line}" . PHP_EOL;
             }
             $prev = false;
             $object = 0;
             if ($phpcsFile->tokenizerType === 'JS') {
                 $conditions = $tokens[$i]['conditions'];
                 krsort($conditions, SORT_NUMERIC);
                 foreach ($conditions as $token => $condition) {
                     if ($condition === T_OBJECT) {
                         $object = $token;
                         break;
                     }
                 }
                 if ($this->debug === true && $object !== 0) {
                     $line = $tokens[$object]['line'];
                     echo "\t* token is inside JS object {$object} on line {$line} *" . PHP_EOL;
                 }
             }
             $parens = 0;
             if (isset($tokens[$i]['nested_parenthesis']) === true && empty($tokens[$i]['nested_parenthesis']) === false) {
                 end($tokens[$i]['nested_parenthesis']);
                 $parens = key($tokens[$i]['nested_parenthesis']);
                 if ($this->debug === true) {
                     $line = $tokens[$parens]['line'];
                     echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
                 }
             }
             $condition = 0;
             if (isset($tokens[$i]['conditions']) === true && empty($tokens[$i]['conditions']) === false) {
                 end($tokens[$i]['conditions']);
                 $condition = key($tokens[$i]['conditions']);
                 if ($this->debug === true) {
                     $line = $tokens[$condition]['line'];
                     $type = $tokens[$condition]['type'];
                     echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
                 }
             }
             if ($parens > $object && $parens > $condition) {
                 if ($this->debug === true) {
                     echo "\t* using parenthesis *" . PHP_EOL;
                 }
                 $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $parens - 1, null, true);
                 $object = 0;
                 $condition = 0;
             } else {
                 if ($object > 0 && $object >= $condition) {
                     if ($this->debug === true) {
                         echo "\t* using object *" . PHP_EOL;
                     }
                     $prev = $object;
                     $parens = 0;
                     $condition = 0;
                 } else {
                     if ($condition > 0) {
                         if ($this->debug === true) {
                             echo "\t* using condition *" . PHP_EOL;
                         }
                         $prev = $condition;
                         $object = 0;
                         $parens = 0;
                     }
                 }
             }
             //end if
             if ($prev === false) {
                 $prev = $phpcsFile->findPrevious(array(T_EQUAL, T_RETURN), $tokens[$i]['scope_condition'] - 1, null, false, null, true);
                 if ($prev === false) {
                     $prev = $i;
                     if ($this->debug === true) {
                         echo "\t* could not find a previous T_EQUAL or T_RETURN token; will use current token *" . PHP_EOL;
                     }
                 }
             }
             if ($this->debug === true) {
                 $line = $tokens[$prev]['line'];
                 $type = $tokens[$prev]['type'];
                 echo "\t* previous token is {$type} on line {$line} *" . PHP_EOL;
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
             if ($this->debug === true) {
                 $line = $tokens[$first]['line'];
                 $type = $tokens[$first]['type'];
                 echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
             }
             $prev = $phpcsFile->findStartOfStatement($first);
             if ($prev !== $first) {
                 // This is not the start of the statement.
                 if ($this->debug === true) {
                     $line = $tokens[$prev]['line'];
                     $type = $tokens[$prev]['type'];
                     echo "\t* amended previous is {$type} on line {$line} *" . PHP_EOL;
                 }
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                 if ($this->debug === true) {
                     $line = $tokens[$first]['line'];
                     $type = $tokens[$first]['type'];
                     echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
                 }
             }
             $currentIndent = $tokens[$first]['column'] - 1;
             if ($object > 0 || $condition > 0) {
                 $currentIndent += $this->indent;
             }
             if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
                 if ($this->debug === true) {
                     echo "\t* first token is a scope closer *" . PHP_EOL;
                 }
                 if ($condition === 0 || $tokens[$condition]['scope_opener'] < $first) {
                     $currentIndent = $setIndents[$first];
                 } else {
                     if ($this->debug === true) {
                         echo "\t* ignoring scope closer *" . PHP_EOL;
                     }
                 }
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$first] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$first]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
             }
         }
         //end if
     }
     //end for
     // Don't process the rest of the file.
     return $phpcsFile->numTokens;
 }
 /**
  * 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(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     if (isset($tokens[$stackPtr]['scope_opener']) === false) {
         return;
     }
     if ($tokens[$stackPtr]['code'] === T_FUNCTION && (bool) $this->checkFunctions === false || $tokens[$stackPtr]['code'] === T_CLOSURE && (bool) $this->checkClosures === false) {
         return;
     }
     $openingBrace = $tokens[$stackPtr]['scope_opener'];
     $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
     if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
         $use = $phpcsFile->findNext(T_USE, $closeBracket + 1, $tokens[$stackPtr]['scope_opener']);
         if ($use !== false) {
             $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $use + 1);
             $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
         }
     }
     $functionLine = $tokens[$closeBracket]['line'];
     $braceLine = $tokens[$openingBrace]['line'];
     $lineDifference = $braceLine - $functionLine;
     if ($lineDifference === 0) {
         $error = 'Opening brace should be on a new line';
         $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceOnSameLine');
         if ($fix === true) {
             $phpcsFile->fixer->beginChangeset();
             $indent = $phpcsFile->findFirstOnLine(array(), $openingBrace);
             if ($tokens[$indent]['code'] === T_WHITESPACE) {
                 $phpcsFile->fixer->addContentBefore($openingBrace, $tokens[$indent]['content']);
             }
             $phpcsFile->fixer->addNewlineBefore($openingBrace);
             $phpcsFile->fixer->endChangeset();
         }
         $phpcsFile->recordMetric($stackPtr, 'Function opening brace placement', 'same line');
     } else {
         if ($lineDifference > 1) {
             $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)';
             $data = array($lineDifference - 1);
             $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceSpacing', $data);
             if ($fix === true) {
                 for ($i = $tokens[$stackPtr]['parenthesis_closer'] + 1; $i < $openingBrace; $i++) {
                     if ($tokens[$i]['line'] === $braceLine) {
                         $phpcsFile->fixer->addNewLineBefore($i);
                         break;
                     }
                     $phpcsFile->fixer->replaceToken($i, '');
                 }
             }
         }
     }
     //end if
     $next = $phpcsFile->findNext(T_WHITESPACE, $openingBrace + 1, null, true);
     if ($tokens[$next]['line'] === $tokens[$openingBrace]['line']) {
         if ($next === $tokens[$stackPtr]['scope_closer']) {
             // Ignore empty functions.
             return;
         }
         $error = 'Opening brace must be the last content on the line';
         $fix = $phpcsFile->addFixableError($error, $openingBrace, 'ContentAfterBrace');
         if ($fix === true) {
             $phpcsFile->fixer->addNewline($openingBrace);
         }
     }
     // Only continue checking if the opening brace looks good.
     if ($lineDifference !== 1) {
         return;
     }
     // We need to actually find the first piece of content on this line,
     // as if this is a method with tokens before it (public, static etc)
     // or an if with an else before it, then we need to start the scope
     // checking from there, rather than the current token.
     $lineStart = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true);
     // The opening brace is on the correct line, now it needs to be
     // checked to be correctly indented.
     $startColumn = $tokens[$lineStart]['column'];
     $braceIndent = $tokens[$openingBrace]['column'];
     if ($braceIndent !== $startColumn) {
         $expected = $startColumn - 1;
         $found = $braceIndent - 1;
         $error = 'Opening brace indented incorrectly; expected %s spaces, found %s';
         $data = array($expected, $found);
         $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceIndent', $data);
         if ($fix === true) {
             $indent = str_repeat(' ', $expected);
             if ($found === 0) {
                 $phpcsFile->fixer->addContentBefore($openingBrace, $indent);
             } else {
                 $phpcsFile->fixer->replaceToken($openingBrace - 1, $indent);
             }
         }
     }
     //end if
     $phpcsFile->recordMetric($stackPtr, 'Function opening brace placement', 'new line');
 }
Example #4
0
 /**
  * Processes the closing section of a class 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.
  *
  * @return void
  */
 public function processClose(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     if (isset($tokens[$stackPtr]['scope_closer']) === false) {
         return;
     }
     $closeBrace = $tokens[$stackPtr]['scope_closer'];
     // Check that the closing brace has one blank line after it.
     for ($nextContent = $closeBrace + 1; $nextContent < $phpcsFile->numTokens; $nextContent++) {
         // Ignore comments on the same lines as the brace.
         if ($tokens[$nextContent]['line'] === $tokens[$closeBrace]['line'] && ($tokens[$nextContent]['code'] === T_WHITESPACE || $tokens[$nextContent]['code'] === T_COMMENT)) {
             continue;
         }
         if ($tokens[$nextContent]['code'] !== T_WHITESPACE) {
             break;
         }
     }
     if ($nextContent === $phpcsFile->numTokens) {
         // Ignore the line check as this is the very end of the file.
         $difference = 1;
     } else {
         $difference = $tokens[$nextContent]['line'] - $tokens[$closeBrace]['line'] - 1;
     }
     $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, $closeBrace - 1, $stackPtr, true);
     if ($difference === -1 || $tokens[$lastContent]['line'] === $tokens[$closeBrace]['line']) {
         $error = 'Closing %s brace must be on a line by itself';
         $data = array($tokens[$stackPtr]['content']);
         $fix = $phpcsFile->addFixableError($error, $closeBrace, 'CloseBraceSameLine', $data);
         if ($fix === true) {
             if ($difference === -1) {
                 $phpcsFile->fixer->addNewlineBefore($nextContent);
             }
             if ($tokens[$lastContent]['line'] === $tokens[$closeBrace]['line']) {
                 $phpcsFile->fixer->addNewlineBefore($closeBrace);
             }
         }
     } else {
         if ($tokens[$closeBrace - 1]['code'] === T_WHITESPACE) {
             $prevContent = $tokens[$closeBrace - 1]['content'];
             if ($prevContent !== $phpcsFile->eolChar) {
                 $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar));
                 $spaces = strlen($blankSpace);
                 if ($spaces !== 0) {
                     if ($tokens[$closeBrace - 1]['line'] !== $tokens[$closeBrace]['line']) {
                         $error = 'Expected 0 spaces before closing brace; newline found';
                         $phpcsFile->addError($error, $closeBrace, 'NewLineBeforeCloseBrace');
                     } else {
                         $error = 'Expected 0 spaces before closing brace; %s found';
                         $data = array($spaces);
                         $fix = $phpcsFile->addFixableError($error, $closeBrace, 'SpaceBeforeCloseBrace', $data);
                         if ($fix === true) {
                             $phpcsFile->fixer->replaceToken($closeBrace - 1, '');
                         }
                     }
                 }
             }
         }
     }
     //end if
     if ($difference !== -1 && $difference !== 1) {
         $error = 'Closing brace of a %s must be followed by a single blank line; found %s';
         $data = array($tokens[$stackPtr]['content'], $difference);
         $fix = $phpcsFile->addFixableError($error, $closeBrace, 'NewlinesAfterCloseBrace', $data);
         if ($fix === true) {
             if ($difference === 0) {
                 $first = $phpcsFile->findFirstOnLine(array(), $nextContent, true);
                 $phpcsFile->fixer->addNewlineBefore($first);
             } else {
                 $phpcsFile->fixer->beginChangeset();
                 for ($i = $closeBrace + 1; $i < $nextContent; $i++) {
                     if ($tokens[$i]['line'] <= $tokens[$closeBrace]['line'] + 1) {
                         continue;
                     } else {
                         if ($tokens[$i]['line'] === $tokens[$nextContent]['line']) {
                             break;
                         }
                     }
                     $phpcsFile->fixer->replaceToken($i, '');
                 }
                 $phpcsFile->fixer->endChangeset();
             }
         }
     }
     //end if
 }
Example #5
0
 /**
  * Processes the function tokens within the class.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found.
  * @param int                  $stackPtr  The position where the token was found.
  *
  * @return void
  */
 protected function processMemberVar(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $ignore = Tokens::$methodPrefixes;
     $ignore[] = T_VAR;
     $ignore[] = T_WHITESPACE;
     $start = $stackPtr;
     $prev = $phpcsFile->findPrevious($ignore, $stackPtr - 1, null, true);
     if (isset(Tokens::$commentTokens[$tokens[$prev]['code']]) === true) {
         // Assume the comment belongs to the member var if it is on a line by itself.
         $prevContent = $phpcsFile->findPrevious(Tokens::$emptyTokens, $prev - 1, null, true);
         if ($tokens[$prevContent]['line'] !== $tokens[$prev]['line']) {
             // Check the spacing, but then skip it.
             $foundLines = $tokens[$stackPtr]['line'] - $tokens[$prev]['line'] - 1;
             if ($foundLines > 0) {
                 $error = 'Expected 0 blank lines after member var comment; %s found';
                 $data = array($foundLines);
                 $fix = $phpcsFile->addFixableError($error, $prev, 'AfterComment', $data);
                 if ($fix === true) {
                     $phpcsFile->fixer->beginChangeset();
                     // Inline comments have the newline included in the content but
                     // docblock do not.
                     if ($tokens[$prev]['code'] === T_COMMENT) {
                         $phpcsFile->fixer->replaceToken($prev, rtrim($tokens[$prev]['content']));
                     }
                     for ($i = $prev + 1; $i <= $stackPtr; $i++) {
                         if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) {
                             break;
                         }
                         $phpcsFile->fixer->replaceToken($i, '');
                     }
                     $phpcsFile->fixer->addNewline($prev);
                     $phpcsFile->fixer->endChangeset();
                 }
             }
             //end if
             $start = $prev;
         }
         //end if
     }
     //end if
     // There needs to be 1 blank line before the var, not counting comments.
     if ($start === $stackPtr) {
         // No comment found.
         $first = $phpcsFile->findFirstOnLine(Tokens::$emptyTokens, $start, true);
         if ($first === false) {
             $first = $start;
         }
     } else {
         if ($tokens[$start]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
             $first = $tokens[$start]['comment_opener'];
         } else {
             $first = $phpcsFile->findPrevious(Tokens::$emptyTokens, $start - 1, null, true);
             $first = $phpcsFile->findNext(Tokens::$commentTokens, $first + 1);
         }
     }
     $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $first - 1, null, true);
     $foundLines = $tokens[$first]['line'] - $tokens[$prev]['line'] - 1;
     if ($foundLines === 1) {
         return;
     }
     $error = 'Expected 1 blank line before member var; %s found';
     $data = array($foundLines);
     $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Incorrect', $data);
     if ($fix === true) {
         $phpcsFile->fixer->beginChangeset();
         for ($i = $prev + 1; $i < $first; $i++) {
             if ($tokens[$i]['line'] === $tokens[$prev]['line']) {
                 continue;
             }
             if ($tokens[$i]['line'] === $tokens[$first]['line']) {
                 $phpcsFile->fixer->addNewline($i - 1);
                 break;
             }
             $phpcsFile->fixer->replaceToken($i, '');
         }
         $phpcsFile->fixer->endChangeset();
     }
     //end if
 }