Chris@0: _debug = false; Chris@0: } Chris@0: Chris@0: return array(T_OPEN_TAG); Chris@0: Chris@0: }//end register() Chris@0: Chris@0: Chris@0: /** Chris@0: * Processes this test, when one of its tokens is encountered. Chris@0: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile All the tokens found in the document. Chris@17: * @param int $stackPtr The position of the current token Chris@17: * in the stack passed in $tokens. Chris@0: * Chris@0: * @return void Chris@0: */ Chris@17: public function process(File $phpcsFile, $stackPtr) Chris@0: { Chris@17: $debug = Config::getConfigData('scope_indent_debug'); Chris@0: if ($debug !== null) { Chris@0: $this->_debug = (bool) $debug; Chris@0: } Chris@0: Chris@0: if ($this->_tabWidth === null) { Chris@17: $config = $phpcsFile->config; Chris@17: if (isset($config->tabWidth) === false || $config->tabWidth === 0) { Chris@0: // We have no idea how wide tabs are, so assume 4 spaces for fixing. Chris@0: // It shouldn't really matter because indent checks elsewhere in the Chris@0: // standard should fix things up. Chris@0: $this->_tabWidth = 4; Chris@0: } else { Chris@17: $this->_tabWidth = $config->tabWidth; Chris@0: } Chris@0: } Chris@0: Chris@0: $currentIndent = 0; Chris@0: $lastOpenTag = $stackPtr; Chris@0: $lastCloseTag = null; Chris@0: $openScopes = array(); Chris@0: $adjustments = array(); Chris@0: $setIndents = array(); Chris@0: Chris@0: $tokens = $phpcsFile->getTokens(); Chris@0: $first = $phpcsFile->findFirstOnLine(T_INLINE_HTML, $stackPtr); Chris@0: $trimmed = ltrim($tokens[$first]['content']); Chris@0: if ($trimmed === '') { Chris@0: $currentIndent = ($tokens[$stackPtr]['column'] - 1); Chris@0: } else { Chris@0: $currentIndent = (strlen($tokens[$first]['content']) - strlen($trimmed)); Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$stackPtr]['line']; Chris@0: echo "Start with token $stackPtr on line $line with indent $currentIndent".PHP_EOL; Chris@0: } Chris@0: Chris@0: if (empty($this->_ignoreIndentationTokens) === true) { Chris@0: $this->_ignoreIndentationTokens = array(T_INLINE_HTML => true); Chris@0: foreach ($this->ignoreIndentationTokens as $token) { Chris@0: if (is_int($token) === false) { Chris@0: if (defined($token) === false) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $token = constant($token); Chris@0: } Chris@0: Chris@0: $this->_ignoreIndentationTokens[$token] = true; Chris@0: } Chris@0: }//end if Chris@0: Chris@0: $this->exact = (bool) $this->exact; Chris@0: $this->tabIndent = (bool) $this->tabIndent; Chris@0: Chris@0: for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { Chris@0: if ($i === false) { Chris@0: // Something has gone very wrong; maybe a parse error. Chris@0: break; Chris@0: } Chris@0: Chris@0: $checkToken = null; Chris@0: $checkIndent = null; Chris@0: Chris@0: $exact = (bool) $this->exact; Chris@0: if ($exact === true && isset($tokens[$i]['nested_parenthesis']) === true) { Chris@0: // Don't check indents exactly between parenthesis as they Chris@0: // tend to have custom rules, such as with multi-line function calls Chris@0: // and control structure conditions. Chris@0: $exact = false; Chris@0: } Chris@0: Chris@0: // Detect line changes and figure out where the indent is. Chris@0: if ($tokens[$i]['column'] === 1) { Chris@0: $trimmed = ltrim($tokens[$i]['content']); Chris@0: if ($trimmed === '') { Chris@0: if (isset($tokens[($i + 1)]) === true Chris@0: && $tokens[$i]['line'] === $tokens[($i + 1)]['line'] Chris@0: ) { Chris@0: $checkToken = ($i + 1); Chris@0: $tokenIndent = ($tokens[($i + 1)]['column'] - 1); Chris@0: } Chris@0: } else { Chris@0: $checkToken = $i; Chris@0: $tokenIndent = (strlen($tokens[$i]['content']) - strlen($trimmed)); Chris@0: } Chris@0: } Chris@0: Chris@0: // Closing parenthesis should just be indented to at least Chris@0: // the same level as where they were opened (but can be more). Chris@0: if (($checkToken !== null Chris@0: && $tokens[$checkToken]['code'] === T_CLOSE_PARENTHESIS Chris@0: && isset($tokens[$checkToken]['parenthesis_opener']) === true) Chris@0: || ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS Chris@0: && isset($tokens[$i]['parenthesis_opener']) === true) Chris@0: ) { Chris@0: if ($checkToken !== null) { Chris@0: $parenCloser = $checkToken; Chris@0: } else { Chris@0: $parenCloser = $i; Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Closing parenthesis found on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $parenOpener = $tokens[$parenCloser]['parenthesis_opener']; Chris@0: if ($tokens[$parenCloser]['line'] !== $tokens[$parenOpener]['line']) { Chris@0: $parens = 0; Chris@0: if (isset($tokens[$parenCloser]['nested_parenthesis']) === true Chris@0: && empty($tokens[$parenCloser]['nested_parenthesis']) === false Chris@0: ) { Chris@0: end($tokens[$parenCloser]['nested_parenthesis']); Chris@0: $parens = key($tokens[$parenCloser]['nested_parenthesis']); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$parens]['line']; Chris@0: echo "\t* token has nested parenthesis $parens on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: $condition = 0; Chris@0: if (isset($tokens[$parenCloser]['conditions']) === true Chris@0: && empty($tokens[$parenCloser]['conditions']) === false Chris@0: ) { Chris@0: end($tokens[$parenCloser]['conditions']); Chris@0: $condition = key($tokens[$parenCloser]['conditions']); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$condition]['line']; Chris@0: $type = $tokens[$condition]['type']; Chris@0: echo "\t* token is inside condition $condition ($type) on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($parens > $condition) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* using parenthesis *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $parenOpener = $parens; Chris@0: $condition = 0; Chris@0: } else if ($condition > 0) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* using condition *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $parenOpener = $condition; Chris@0: $parens = 0; Chris@0: } Chris@0: Chris@0: $exact = false; Chris@0: Chris@0: $lastOpenTagConditions = array_keys($tokens[$lastOpenTag]['conditions']); Chris@0: $lastOpenTagCondition = array_pop($lastOpenTagConditions); Chris@0: Chris@0: if ($condition > 0 && $lastOpenTagCondition === $condition) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* open tag is inside condition; using open tag *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $checkIndent = ($tokens[$lastOpenTag]['column'] - 1); Chris@0: if (isset($adjustments[$condition]) === true) { Chris@0: $checkIndent += $adjustments[$condition]; Chris@0: } Chris@0: Chris@0: $currentIndent = $checkIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$lastOpenTag]['type']; Chris@0: echo "\t=> checking indent of $checkIndent; main indent set to $currentIndent by token $lastOpenTag ($type)".PHP_EOL; Chris@0: } Chris@0: } else if ($condition > 0 Chris@0: && isset($tokens[$condition]['scope_opener']) === true Chris@0: && isset($setIndents[$tokens[$condition]['scope_opener']]) === true Chris@0: ) { Chris@0: $checkIndent = $setIndents[$tokens[$condition]['scope_opener']]; Chris@0: if (isset($adjustments[$condition]) === true) { Chris@0: $checkIndent += $adjustments[$condition]; Chris@0: } Chris@0: Chris@0: $currentIndent = $checkIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$condition]['type']; Chris@0: echo "\t=> checking indent of $checkIndent; main indent set to $currentIndent by token $condition ($type)".PHP_EOL; Chris@0: } Chris@0: } else { Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $parenOpener, true); Chris@0: Chris@0: $checkIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $checkIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$first]['line']; Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t* first token on line $line is $first ($type) *".PHP_EOL; Chris@0: } Chris@0: Chris@0: if ($first === $tokens[$parenCloser]['parenthesis_opener']) { Chris@0: // This is unlikely to be the start of the statement, so look Chris@0: // back further to find it. Chris@0: $first--; Chris@0: } Chris@0: Chris@0: $prev = $phpcsFile->findStartOfStatement($first, T_COMMA); Chris@0: if ($prev !== $first) { Chris@0: // This is not the start of the statement. Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$prev]['line']; Chris@0: $type = $tokens[$prev]['type']; Chris@0: echo "\t* previous is $type on line $line *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true); Chris@0: $prev = $phpcsFile->findStartOfStatement($first, T_COMMA); Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$first]['line']; Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t* amended first token is $first ($type) on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: if (isset($tokens[$first]['scope_closer']) === true Chris@0: && $tokens[$first]['scope_closer'] === $first Chris@0: ) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* first token is a scope closer *".PHP_EOL; Chris@0: } Chris@0: Chris@0: if (isset($tokens[$first]['scope_condition']) === true) { Chris@0: $scopeCloser = $first; Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true); Chris@0: Chris@0: $currentIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $currentIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) { Chris@0: $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent); Chris@0: } Chris@0: Chris@0: $setIndents[$first] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $first ($type)".PHP_EOL; Chris@0: } Chris@0: }//end if Chris@0: } else { Chris@0: // Don't force current indent to divisible because there could be custom Chris@0: // rules in place between parenthesis, such as with arrays. Chris@0: $currentIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $currentIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: $setIndents[$first] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t=> checking indent of $checkIndent; main indent set to $currentIndent by token $first ($type)".PHP_EOL; Chris@0: } Chris@0: }//end if Chris@0: }//end if Chris@0: } else if ($this->_debug === true) { Chris@0: echo "\t * ignoring single-line definition *".PHP_EOL; Chris@0: }//end if Chris@0: }//end if Chris@0: Chris@0: // Closing short array bracket should just be indented to at least Chris@0: // the same level as where it was opened (but can be more). Chris@0: if ($tokens[$i]['code'] === T_CLOSE_SHORT_ARRAY Chris@0: || ($checkToken !== null Chris@0: && $tokens[$checkToken]['code'] === T_CLOSE_SHORT_ARRAY) Chris@0: ) { Chris@0: if ($checkToken !== null) { Chris@0: $arrayCloser = $checkToken; Chris@0: } else { Chris@0: $arrayCloser = $i; Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$arrayCloser]['line']; Chris@0: echo "Closing short array bracket found on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $arrayOpener = $tokens[$arrayCloser]['bracket_opener']; Chris@0: if ($tokens[$arrayCloser]['line'] !== $tokens[$arrayOpener]['line']) { Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $arrayOpener, true); Chris@0: $checkIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $checkIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: $exact = false; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$first]['line']; Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t* first token on line $line is $first ($type) *".PHP_EOL; Chris@0: } Chris@0: Chris@0: if ($first === $tokens[$arrayCloser]['bracket_opener']) { Chris@0: // This is unlikely to be the start of the statement, so look Chris@0: // back further to find it. Chris@0: $first--; Chris@0: } Chris@0: Chris@0: $prev = $phpcsFile->findStartOfStatement($first, T_COMMA); Chris@0: if ($prev !== $first) { Chris@0: // This is not the start of the statement. Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$prev]['line']; Chris@0: $type = $tokens[$prev]['type']; Chris@0: echo "\t* previous is $type on line $line *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true); Chris@0: $prev = $phpcsFile->findStartOfStatement($first, T_COMMA); Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$first]['line']; Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t* amended first token is $first ($type) on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: if (isset($tokens[$first]['scope_closer']) === true Chris@0: && $tokens[$first]['scope_closer'] === $first Chris@0: ) { Chris@0: // The first token is a scope closer and would have already Chris@0: // been processed and set the indent level correctly, so Chris@0: // don't adjust it again. Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* first token is a scope closer; ignoring closing short array bracket *".PHP_EOL; Chris@0: } Chris@0: Chris@0: if (isset($setIndents[$first]) === true) { Chris@0: $currentIndent = $setIndents[$first]; Chris@0: if ($this->_debug === true) { Chris@0: echo "\t=> indent reset to $currentIndent".PHP_EOL; Chris@0: } Chris@0: } Chris@0: } else { Chris@0: // Don't force current indent to be divisible because there could be custom Chris@0: // rules in place for arrays. Chris@0: $currentIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $currentIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: $setIndents[$first] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t=> checking indent of $checkIndent; main indent set to $currentIndent by token $first ($type)".PHP_EOL; Chris@0: } Chris@0: }//end if Chris@0: } else if ($this->_debug === true) { Chris@0: echo "\t * ignoring single-line definition *".PHP_EOL; Chris@0: }//end if Chris@0: }//end if Chris@0: Chris@0: // Adjust lines within scopes while auto-fixing. Chris@0: if ($checkToken !== null Chris@0: && $exact === false Chris@0: && (empty($tokens[$checkToken]['conditions']) === false Chris@0: || (isset($tokens[$checkToken]['scope_opener']) === true Chris@0: && $tokens[$checkToken]['scope_opener'] === $checkToken)) Chris@0: ) { Chris@0: if (empty($tokens[$checkToken]['conditions']) === false) { Chris@0: end($tokens[$checkToken]['conditions']); Chris@0: $condition = key($tokens[$checkToken]['conditions']); Chris@0: } else { Chris@0: $condition = $tokens[$checkToken]['scope_condition']; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $condition, true); Chris@0: Chris@0: if (isset($adjustments[$first]) === true Chris@0: && (($adjustments[$first] < 0 && $tokenIndent > $currentIndent) Chris@0: || ($adjustments[$first] > 0 && $tokenIndent < $currentIndent)) Chris@0: ) { Chris@0: $padding = ($tokenIndent + $adjustments[$first]); Chris@0: if ($padding > 0) { Chris@0: if ($this->tabIndent === true) { Chris@0: $numTabs = floor($padding / $this->_tabWidth); Chris@0: $numSpaces = ($padding - ($numTabs * $this->_tabWidth)); Chris@0: $padding = str_repeat("\t", $numTabs).str_repeat(' ', $numSpaces); Chris@0: } else { Chris@0: $padding = str_repeat(' ', $padding); Chris@0: } Chris@0: } else { Chris@0: $padding = ''; Chris@0: } Chris@0: Chris@0: if ($checkToken === $i) { Chris@0: $phpcsFile->fixer->replaceToken($checkToken, $padding.$trimmed); Chris@0: } else { Chris@0: // Easier to just replace the entire indent. Chris@0: $phpcsFile->fixer->replaceToken(($checkToken - 1), $padding); Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $length = strlen($padding); Chris@0: $line = $tokens[$checkToken]['line']; Chris@0: $type = $tokens[$checkToken]['type']; Chris@0: echo "Indent adjusted to $length for $type on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $adjustments[$checkToken] = $adjustments[$first]; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$checkToken]['line']; Chris@0: $type = $tokens[$checkToken]['type']; Chris@0: echo "\t=> Add adjustment of ".$adjustments[$checkToken]." for token $checkToken ($type) on line $line".PHP_EOL; Chris@0: } Chris@0: }//end if Chris@0: }//end if Chris@0: Chris@0: // Scope closers reset the required indent to the same level as the opening condition. Chris@0: if (($checkToken !== null Chris@0: && isset($openScopes[$checkToken]) === true Chris@0: || (isset($tokens[$checkToken]['scope_condition']) === true Chris@0: && isset($tokens[$checkToken]['scope_closer']) === true Chris@0: && $tokens[$checkToken]['scope_closer'] === $checkToken Chris@0: && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line'])) Chris@0: || ($checkToken === null Chris@0: && isset($openScopes[$i]) === true Chris@0: || (isset($tokens[$i]['scope_condition']) === true Chris@0: && isset($tokens[$i]['scope_closer']) === true Chris@0: && $tokens[$i]['scope_closer'] === $i Chris@0: && $tokens[$i]['line'] !== $tokens[$tokens[$i]['scope_opener']]['line'])) Chris@0: ) { Chris@0: if ($this->_debug === true) { Chris@0: if ($checkToken === null) { Chris@0: $type = $tokens[$tokens[$i]['scope_condition']]['type']; Chris@0: $line = $tokens[$i]['line']; Chris@0: } else { Chris@0: $type = $tokens[$tokens[$checkToken]['scope_condition']]['type']; Chris@0: $line = $tokens[$checkToken]['line']; Chris@0: } Chris@0: Chris@0: echo "Close scope ($type) on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $scopeCloser = $checkToken; Chris@0: if ($scopeCloser === null) { Chris@0: $scopeCloser = $i; Chris@0: } else { Chris@0: array_pop($openScopes); Chris@0: } Chris@0: Chris@0: if (isset($tokens[$scopeCloser]['scope_condition']) === true) { Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true); Chris@0: Chris@0: $currentIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $currentIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) { Chris@0: $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent); Chris@0: } Chris@0: Chris@0: $setIndents[$scopeCloser] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$scopeCloser]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $scopeCloser ($type)".PHP_EOL; Chris@0: } Chris@0: Chris@0: // We only check the indent of scope closers if they are Chris@0: // curly braces because other constructs tend to have different rules. Chris@0: if ($tokens[$scopeCloser]['code'] === T_CLOSE_CURLY_BRACKET) { Chris@0: $exact = true; Chris@0: } else { Chris@0: $checkToken = null; Chris@0: } Chris@0: }//end if Chris@0: }//end if Chris@0: Chris@0: // Handle scope for JS object notation. Chris@0: if ($phpcsFile->tokenizerType === 'JS' Chris@0: && (($checkToken !== null Chris@0: && $tokens[$checkToken]['code'] === T_CLOSE_OBJECT Chris@0: && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['bracket_opener']]['line']) Chris@0: || ($checkToken === null Chris@0: && $tokens[$i]['code'] === T_CLOSE_OBJECT Chris@0: && $tokens[$i]['line'] !== $tokens[$tokens[$i]['bracket_opener']]['line'])) Chris@0: ) { Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Close JS object on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $scopeCloser = $checkToken; Chris@0: if ($scopeCloser === null) { Chris@0: $scopeCloser = $i; Chris@0: } else { Chris@0: array_pop($openScopes); Chris@0: } Chris@0: Chris@0: $parens = 0; Chris@0: if (isset($tokens[$scopeCloser]['nested_parenthesis']) === true Chris@0: && empty($tokens[$scopeCloser]['nested_parenthesis']) === false Chris@0: ) { Chris@0: end($tokens[$scopeCloser]['nested_parenthesis']); Chris@0: $parens = key($tokens[$scopeCloser]['nested_parenthesis']); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$parens]['line']; Chris@0: echo "\t* token has nested parenthesis $parens on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: $condition = 0; Chris@0: if (isset($tokens[$scopeCloser]['conditions']) === true Chris@0: && empty($tokens[$scopeCloser]['conditions']) === false Chris@0: ) { Chris@0: end($tokens[$scopeCloser]['conditions']); Chris@0: $condition = key($tokens[$scopeCloser]['conditions']); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$condition]['line']; Chris@0: $type = $tokens[$condition]['type']; Chris@0: echo "\t* token is inside condition $condition ($type) on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($parens > $condition) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* using parenthesis *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $parens, true); Chris@0: $condition = 0; Chris@0: } else if ($condition > 0) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* using condition *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $condition, true); Chris@0: $parens = 0; Chris@0: } else { Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$tokens[$scopeCloser]['bracket_opener']]['line']; Chris@0: echo "\t* token is not in parenthesis or condition; using opener on line $line *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['bracket_opener'], true); Chris@0: }//end if Chris@0: Chris@0: $currentIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $currentIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: if ($parens > 0 || $condition > 0) { Chris@0: $checkIndent = ($tokens[$first]['column'] - 1); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $checkIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: if ($condition > 0) { Chris@0: $checkIndent += $this->indent; Chris@0: $currentIndent += $this->indent; Chris@0: $exact = true; Chris@0: } Chris@0: } else { Chris@0: $checkIndent = $currentIndent; Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent); Chris@0: $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent); Chris@0: $setIndents[$first] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t=> checking indent of $checkIndent; main indent set to $currentIndent by token $first ($type)".PHP_EOL; Chris@0: } Chris@0: }//end if Chris@0: Chris@0: if ($checkToken !== null Chris@17: && isset(Tokens::$scopeOpeners[$tokens[$checkToken]['code']]) === true Chris@0: && in_array($tokens[$checkToken]['code'], $this->nonIndentingScopes) === false Chris@0: && isset($tokens[$checkToken]['scope_opener']) === true Chris@0: ) { Chris@0: $exact = true; Chris@0: Chris@0: $lastOpener = null; Chris@0: if (empty($openScopes) === false) { Chris@0: end($openScopes); Chris@0: $lastOpener = current($openScopes); Chris@0: } Chris@0: Chris@0: // A scope opener that shares a closer with another token (like multiple Chris@0: // CASEs using the same BREAK) needs to reduce the indent level so its Chris@0: // indent is checked correctly. It will then increase the indent again Chris@0: // (as all openers do) after being checked. Chris@0: if ($lastOpener !== null Chris@0: && isset($tokens[$lastOpener]['scope_closer']) === true Chris@0: && $tokens[$lastOpener]['level'] === $tokens[$checkToken]['level'] Chris@0: && $tokens[$lastOpener]['scope_closer'] === $tokens[$checkToken]['scope_closer'] Chris@0: ) { Chris@0: $currentIndent -= $this->indent; Chris@0: $setIndents[$lastOpener] = $currentIndent; Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: $type = $tokens[$lastOpener]['type']; Chris@0: echo "Shared closer found on line $line".PHP_EOL; Chris@0: echo "\t=> indent set to $currentIndent by token $lastOpener ($type)".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($tokens[$checkToken]['code'] === T_CLOSURE Chris@0: && $tokenIndent > $currentIndent Chris@0: ) { Chris@0: // The opener is indented more than needed, which is fine. Chris@0: // But just check that it is divisible by our expected indent. Chris@0: $checkIndent = (int) (ceil($tokenIndent / $this->indent) * $this->indent); Chris@0: $exact = false; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Closure found on line $line".PHP_EOL; Chris@0: echo "\t=> checking indent of $checkIndent; main indent remains at $currentIndent".PHP_EOL; Chris@0: } Chris@0: } Chris@0: }//end if Chris@0: Chris@0: // Method prefix indentation has to be exact or else if will break Chris@0: // the rest of the function declaration, and potentially future ones. Chris@0: if ($checkToken !== null Chris@17: && isset(Tokens::$methodPrefixes[$tokens[$checkToken]['code']]) === true Chris@0: && $tokens[($checkToken + 1)]['code'] !== T_DOUBLE_COLON Chris@0: ) { Chris@0: $exact = true; Chris@0: } Chris@0: Chris@0: // JS property indentation has to be exact or else if will break Chris@0: // things like function and object indentation. Chris@0: if ($checkToken !== null && $tokens[$checkToken]['code'] === T_PROPERTY) { Chris@0: $exact = true; Chris@0: } Chris@0: Chris@0: // PHP tags needs to be indented to exact column positions Chris@0: // so they don't cause problems with indent checks for the code Chris@0: // within them, but they don't need to line up with the current indent. Chris@0: if ($checkToken !== null Chris@0: && ($tokens[$checkToken]['code'] === T_OPEN_TAG Chris@0: || $tokens[$checkToken]['code'] === T_OPEN_TAG_WITH_ECHO Chris@0: || $tokens[$checkToken]['code'] === T_CLOSE_TAG) Chris@0: ) { Chris@0: $exact = true; Chris@0: $checkIndent = ($tokens[$checkToken]['column'] - 1); Chris@0: $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent); Chris@0: } Chris@0: Chris@0: // Check the line indent. Chris@0: if ($checkIndent === null) { Chris@0: $checkIndent = $currentIndent; Chris@0: } Chris@0: Chris@0: // If the line starts with "->" we assume this is an indented chained Chris@0: // method invocation, so we add one level of indentation. Chris@0: if ($checkToken !== null && $tokens[$checkToken]['code'] === T_OBJECT_OPERATOR) { Chris@0: $checkIndent += $this->indent; Chris@0: } Chris@0: Chris@0: // Comments starting with a star have an extra whitespace. Chris@0: if ($checkToken !== null && $tokens[$checkToken]['code'] === T_COMMENT) { Chris@0: $content = trim($tokens[$checkToken]['content']); Chris@0: if ($content{0} === '*') { Chris@0: $checkIndent += 1; Chris@0: } Chris@0: } Chris@0: Chris@0: $adjusted = false; Chris@0: if ($checkToken !== null Chris@0: && isset($this->_ignoreIndentationTokens[$tokens[$checkToken]['code']]) === false Chris@0: && (($tokenIndent !== $checkIndent && $exact === true) Chris@0: || ($tokenIndent < $checkIndent && $exact === false)) Chris@0: ) { Chris@0: if ($tokenIndent > $checkIndent) { Chris@0: // Ignore multi line statements. Chris@17: $before = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($checkToken - 1), null, true); Chris@0: if ($before !== false && in_array( Chris@0: $tokens[$before]['code'], Chris@0: array( Chris@0: T_SEMICOLON, Chris@0: T_CLOSE_CURLY_BRACKET, Chris@0: T_OPEN_CURLY_BRACKET, Chris@0: T_COLON, Chris@0: ) Chris@0: ) === false Chris@0: ) { Chris@0: continue; Chris@0: } Chris@0: } Chris@0: Chris@0: // Skip array closing indentation errors, this is handled by the Chris@0: // ArraySniff. Chris@0: if (($tokens[$checkToken]['code'] === T_CLOSE_PARENTHESIS Chris@0: && isset($tokens[$checkToken]['parenthesis_owner']) === true Chris@0: && $tokens[$tokens[$checkToken]['parenthesis_owner']]['code'] === T_ARRAY) Chris@0: || $tokens[$checkToken]['code'] === T_CLOSE_SHORT_ARRAY Chris@0: ) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $type = 'IncorrectExact'; Chris@0: $error = 'Line indented incorrectly; expected '; Chris@0: if ($exact === false) { Chris@0: $error .= 'at least '; Chris@0: $type = 'Incorrect'; Chris@0: } Chris@0: Chris@0: if ($this->tabIndent === true) { Chris@0: $error .= '%s tabs, found %s'; Chris@0: $data = array( Chris@0: floor($checkIndent / $this->_tabWidth), Chris@0: floor($tokenIndent / $this->_tabWidth), Chris@0: ); Chris@0: } else { Chris@0: $error .= '%s spaces, found %s'; Chris@0: $data = array( Chris@0: $checkIndent, Chris@0: $tokenIndent, Chris@0: ); Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$checkToken]['line']; Chris@0: $message = vsprintf($error, $data); Chris@0: echo "[Line $line] $message".PHP_EOL; Chris@0: } Chris@0: Chris@0: $fix = $phpcsFile->addFixableError($error, $checkToken, $type, $data); Chris@0: if ($fix === true || $this->_debug === true) { Chris@0: $padding = ''; Chris@0: if ($this->tabIndent === true) { Chris@0: $numTabs = floor($checkIndent / $this->_tabWidth); Chris@0: if ($numTabs > 0) { Chris@0: $numSpaces = ($checkIndent - ($numTabs * $this->_tabWidth)); Chris@0: $padding = str_repeat("\t", $numTabs).str_repeat(' ', $numSpaces); Chris@0: } Chris@0: } else if ($checkIndent > 0) { Chris@0: $padding = str_repeat(' ', $checkIndent); Chris@0: } Chris@0: Chris@0: if ($checkToken === $i) { Chris@0: $accepted = $phpcsFile->fixer->replaceToken($checkToken, $padding.$trimmed); Chris@0: } else { Chris@0: // Easier to just replace the entire indent. Chris@0: $accepted = $phpcsFile->fixer->replaceToken(($checkToken - 1), $padding); Chris@0: } Chris@0: Chris@0: if ($accepted === true) { Chris@0: $adjustments[$checkToken] = ($checkIndent - $tokenIndent); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$checkToken]['line']; Chris@0: $type = $tokens[$checkToken]['type']; Chris@0: echo "\t=> Add adjustment of ".$adjustments[$checkToken]." for token $checkToken ($type) on line $line".PHP_EOL; Chris@0: } Chris@0: } Chris@0: } else { Chris@0: // Assume the change would be applied and continue Chris@0: // checking indents under this assumption. This gives more Chris@0: // technically accurate error messages. Chris@0: $adjustments[$checkToken] = ($checkIndent - $tokenIndent); Chris@0: }//end if Chris@0: }//end if Chris@0: Chris@0: if ($checkToken !== null) { Chris@0: $i = $checkToken; Chris@0: } Chris@0: Chris@0: // Completely skip here/now docs as the indent is a part of the Chris@0: // content itself. Chris@0: if ($tokens[$i]['code'] === T_START_HEREDOC Chris@0: || $tokens[$i]['code'] === T_START_NOWDOC Chris@0: ) { Chris@0: $i = $phpcsFile->findNext(array(T_END_HEREDOC, T_END_NOWDOC), ($i + 1)); Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Completely skip multi-line strings as the indent is a part of the Chris@0: // content itself. Chris@0: if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING Chris@0: || $tokens[$i]['code'] === T_DOUBLE_QUOTED_STRING Chris@0: ) { Chris@0: $i = $phpcsFile->findNext($tokens[$i]['code'], ($i + 1), null, true); Chris@0: $i--; Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Completely skip doc comments as they tend to have complex Chris@0: // indentation rules. Chris@0: if ($tokens[$i]['code'] === T_DOC_COMMENT_OPEN_TAG) { Chris@0: $i = $tokens[$i]['comment_closer']; Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Open tags reset the indent level. Chris@0: if ($tokens[$i]['code'] === T_OPEN_TAG Chris@0: || $tokens[$i]['code'] === T_OPEN_TAG_WITH_ECHO Chris@0: ) { Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Open PHP tag found on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: if ($checkToken === null) { Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true); Chris@0: $currentIndent = (strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']))); Chris@0: } else { Chris@0: $currentIndent = ($tokens[$i]['column'] - 1); Chris@0: } Chris@0: Chris@0: $lastOpenTag = $i; Chris@0: Chris@0: if (isset($adjustments[$i]) === true) { Chris@0: $currentIndent += $adjustments[$i]; Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent); Chris@0: $setIndents[$i] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$i]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $i ($type)".PHP_EOL; Chris@0: } Chris@0: Chris@0: continue; Chris@0: }//end if Chris@0: Chris@0: // Close tags reset the indent level, unless they are closing a tag Chris@0: // opened on the same line. Chris@0: if ($tokens[$i]['code'] === T_CLOSE_TAG) { Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Close PHP tag found on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: if ($tokens[$lastOpenTag]['line'] !== $tokens[$i]['line']) { Chris@0: $currentIndent = ($tokens[$i]['column'] - 1); Chris@0: $lastCloseTag = $i; Chris@0: } else { Chris@0: if ($lastCloseTag === null) { Chris@0: $currentIndent = 0; Chris@0: } else { Chris@0: $currentIndent = ($tokens[$lastCloseTag]['column'] - 1); Chris@0: } Chris@0: } Chris@0: Chris@0: if (isset($adjustments[$i]) === true) { Chris@0: $currentIndent += $adjustments[$i]; Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent); Chris@0: $setIndents[$i] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$i]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $i ($type)".PHP_EOL; Chris@0: } Chris@0: Chris@0: continue; Chris@0: }//end if Chris@0: Chris@0: // Anon classes and functions set the indent based on their own indent level. Chris@0: if ($tokens[$i]['code'] === T_CLOSURE || $tokens[$i]['code'] === T_ANON_CLASS) { Chris@0: $closer = $tokens[$i]['scope_closer']; Chris@0: if ($tokens[$i]['line'] === $tokens[$closer]['line']) { Chris@0: if ($this->_debug === true) { Chris@0: $type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2))); Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "* ignoring single-line $type on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $i = $closer; Chris@0: continue; Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2))); Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Open $type on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true); Chris@0: $currentIndent = (($tokens[$first]['column'] - 1) + $this->indent); Chris@0: Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $currentIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: $currentIndent = (int) (floor($currentIndent / $this->indent) * $this->indent); Chris@0: $i = $tokens[$i]['scope_opener']; Chris@0: $setIndents[$i] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$i]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $i ($type)".PHP_EOL; Chris@0: } Chris@0: Chris@0: continue; Chris@0: }//end if Chris@0: Chris@0: // Scope openers increase the indent level. Chris@0: if (isset($tokens[$i]['scope_condition']) === true Chris@0: && isset($tokens[$i]['scope_opener']) === true Chris@0: && $tokens[$i]['scope_opener'] === $i Chris@0: ) { Chris@0: $closer = $tokens[$i]['scope_closer']; Chris@0: if ($tokens[$i]['line'] === $tokens[$closer]['line']) { Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: $type = $tokens[$i]['type']; Chris@0: echo "* ignoring single-line $type on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $i = $closer; Chris@0: continue; Chris@0: } Chris@0: Chris@0: $condition = $tokens[$tokens[$i]['scope_condition']]['code']; Chris@17: if (isset(Tokens::$scopeOpeners[$condition]) === true Chris@0: && in_array($condition, $this->nonIndentingScopes) === false Chris@0: ) { Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: $type = $tokens[$tokens[$i]['scope_condition']]['type']; Chris@0: echo "Open scope ($type) on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $currentIndent += $this->indent; Chris@0: $setIndents[$i] = $currentIndent; Chris@0: $openScopes[$tokens[$i]['scope_closer']] = $tokens[$i]['scope_condition']; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$i]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $i ($type)".PHP_EOL; Chris@0: } Chris@0: Chris@0: continue; Chris@0: } Chris@0: }//end if Chris@0: Chris@0: // JS objects set the indent level. Chris@0: if ($phpcsFile->tokenizerType === 'JS' Chris@0: && $tokens[$i]['code'] === T_OBJECT Chris@0: ) { Chris@0: $closer = $tokens[$i]['bracket_closer']; Chris@0: if ($tokens[$i]['line'] === $tokens[$closer]['line']) { Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "* ignoring single-line JS object on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $i = $closer; Chris@0: continue; Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Open JS object on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true); Chris@0: $currentIndent = (($tokens[$first]['column'] - 1) + $this->indent); Chris@0: if (isset($adjustments[$first]) === true) { Chris@0: $currentIndent += $adjustments[$first]; Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent); Chris@0: $setIndents[$first] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $first ($type)".PHP_EOL; Chris@0: } Chris@0: Chris@0: continue; Chris@0: }//end if Chris@0: Chris@0: // Closing an anon class or function. Chris@0: if (isset($tokens[$i]['scope_condition']) === true Chris@0: && $tokens[$i]['scope_closer'] === $i Chris@0: && ($tokens[$tokens[$i]['scope_condition']]['code'] === T_CLOSURE Chris@0: || $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS) Chris@0: ) { Chris@0: if ($this->_debug === true) { Chris@0: $type = str_replace('_', ' ', strtolower(substr($tokens[$tokens[$i]['scope_condition']]['type'], 2))); Chris@0: $line = $tokens[$i]['line']; Chris@0: echo "Close $type on line $line".PHP_EOL; Chris@0: } Chris@0: Chris@0: $prev = false; Chris@0: Chris@0: $object = 0; Chris@0: if ($phpcsFile->tokenizerType === 'JS') { Chris@0: $conditions = $tokens[$i]['conditions']; Chris@0: krsort($conditions, SORT_NUMERIC); Chris@0: foreach ($conditions as $token => $condition) { Chris@0: if ($condition === T_OBJECT) { Chris@0: $object = $token; Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($this->_debug === true && $object !== 0) { Chris@0: $line = $tokens[$object]['line']; Chris@0: echo "\t* token is inside JS object $object on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: $parens = 0; Chris@0: if (isset($tokens[$i]['nested_parenthesis']) === true Chris@0: && empty($tokens[$i]['nested_parenthesis']) === false Chris@0: ) { Chris@0: end($tokens[$i]['nested_parenthesis']); Chris@0: $parens = key($tokens[$i]['nested_parenthesis']); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$parens]['line']; Chris@0: echo "\t* token has nested parenthesis $parens on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: $condition = 0; Chris@0: if (isset($tokens[$i]['conditions']) === true Chris@0: && empty($tokens[$i]['conditions']) === false Chris@0: ) { Chris@0: end($tokens[$i]['conditions']); Chris@0: $condition = key($tokens[$i]['conditions']); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$condition]['line']; Chris@0: $type = $tokens[$condition]['type']; Chris@0: echo "\t* token is inside condition $condition ($type) on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($parens > $object && $parens > $condition) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* using parenthesis *".PHP_EOL; Chris@0: } Chris@0: Chris@17: $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($parens - 1), null, true); Chris@0: $object = 0; Chris@0: $condition = 0; Chris@0: } else if ($object > 0 && $object >= $condition) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* using object *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $prev = $object; Chris@0: $parens = 0; Chris@0: $condition = 0; Chris@0: } else if ($condition > 0) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* using condition *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $prev = $condition; Chris@0: $object = 0; Chris@0: $parens = 0; Chris@0: }//end if Chris@0: Chris@0: if ($prev === false) { Chris@0: $prev = $phpcsFile->findPrevious(array(T_EQUAL, T_RETURN), ($tokens[$i]['scope_condition'] - 1), null, false, null, true); Chris@0: if ($prev === false) { Chris@0: $prev = $i; Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* could not find a previous T_EQUAL or T_RETURN token; will use current token *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$prev]['line']; Chris@0: $type = $tokens[$prev]['type']; Chris@0: echo "\t* previous token is $type on line $line *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$first]['line']; Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t* first token on line $line is $first ($type) *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $prev = $phpcsFile->findStartOfStatement($first); Chris@0: if ($prev !== $first) { Chris@0: // This is not the start of the statement. Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$prev]['line']; Chris@0: $type = $tokens[$prev]['type']; Chris@0: echo "\t* amended previous is $type on line $line *".PHP_EOL; Chris@0: } Chris@0: Chris@0: $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true); Chris@0: if ($this->_debug === true) { Chris@0: $line = $tokens[$first]['line']; Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t* amended first token is $first ($type) on line $line *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: $currentIndent = ($tokens[$first]['column'] - 1); Chris@0: if ($object > 0 || $condition > 0) { Chris@0: $currentIndent += $this->indent; Chris@0: } Chris@0: Chris@0: if (isset($tokens[$first]['scope_closer']) === true Chris@0: && $tokens[$first]['scope_closer'] === $first Chris@0: ) { Chris@0: if ($this->_debug === true) { Chris@0: echo "\t* first token is a scope closer *".PHP_EOL; Chris@0: } Chris@0: Chris@0: if ($condition === 0 || $tokens[$condition]['scope_opener'] < $first) { Chris@0: $currentIndent = $setIndents[$first]; Chris@0: } else if ($this->_debug === true) { Chris@0: echo "\t* ignoring scope closer *".PHP_EOL; Chris@0: } Chris@0: } Chris@0: Chris@0: // Make sure it is divisible by our expected indent. Chris@0: $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent); Chris@0: $setIndents[$first] = $currentIndent; Chris@0: Chris@0: if ($this->_debug === true) { Chris@0: $type = $tokens[$first]['type']; Chris@0: echo "\t=> indent set to $currentIndent by token $first ($type)".PHP_EOL; Chris@0: } Chris@0: }//end if Chris@0: }//end for Chris@0: Chris@0: // Don't process the rest of the file. Chris@0: return $phpcsFile->numTokens; Chris@0: Chris@0: }//end process() Chris@0: Chris@0: Chris@0: }//end class