You are here

public function ScopeIndentSniff::process in Coder 8.3

Same name and namespace in other branches
  1. 8.2 coder_sniffer/Drupal/Sniffs/WhiteSpace/ScopeIndentSniff.php \Drupal\Sniffs\WhiteSpace\ScopeIndentSniff::process()
  2. 8.3.x coder_sniffer/Drupal/Sniffs/WhiteSpace/ScopeIndentSniff.php \Drupal\Sniffs\WhiteSpace\ScopeIndentSniff::process()

Processes this test, when one of its tokens is encountered.

Parameters

\PHP_CodeSniffer\Files\File $phpcsFile All the tokens found in the document.:

int $stackPtr The position of the current token: in the stack passed in $tokens.

Return value

void|int

File

coder_sniffer/Drupal/Sniffs/WhiteSpace/ScopeIndentSniff.php, line 131

Class

ScopeIndentSniff
Largely copied from \PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff, modified to make the exact mode working with comments and multi line statements.

Namespace

Drupal\Sniffs\WhiteSpace

Code

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;
    }
  }
  $lastOpenTag = $stackPtr;
  $lastCloseTag = null;
  $openScopes = [];
  $adjustments = [];
  $setIndents = [];
  $disableExactEnd = 0;
  $tokenIndent = 0;
  $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 = [
      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;
  $checkAnnotations = $phpcsFile->config->annotations;
  for ($i = $stackPtr + 1; $i < $phpcsFile->numTokens; $i++) {
    if ($checkAnnotations === true && $tokens[$i]['code'] === T_PHPCS_SET && isset($tokens[$i]['sniffCode']) === true && $tokens[$i]['sniffCode'] === 'Generic.WhiteSpace.ScopeIndent' && $tokens[$i]['sniffProperty'] === 'exact') {
      $value = $tokens[$i]['sniffPropertyValue'];
      if ($value === 'true') {
        $value = true;
      }
      else {
        if ($value === 'false') {
          $value = false;
        }
        else {
          $value = (bool) $value;
        }
      }
      $this->exact = $value;
      if ($this->debug === true) {
        $line = $tokens[$i]['line'];
        if ($this->exact === true) {
          $value = 'true';
        }
        else {
          $value = 'false';
        }
        echo "* token {$i} on line {$line} set exact flag to {$value} *" . PHP_EOL;
      }
    }

    //end if
    $checkToken = null;
    $checkIndent = null;

    /*
        Don't check indents exactly between parenthesis or arrays as they
        tend to have custom rules, such as with multi-line function calls
        and control structure conditions.
    */
    $exact = $this->exact;
    if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS && isset($tokens[$i]['parenthesis_closer']) === true) {
      $disableExactEnd = max($disableExactEnd, $tokens[$i]['parenthesis_closer']);
      if ($this->debug === true) {
        $line = $tokens[$i]['line'];
        $type = $tokens[$disableExactEnd]['type'];
        echo "Opening parenthesis found on line {$line}" . PHP_EOL;
        echo "\t=> disabling exact indent checking until {$disableExactEnd} ({$type})" . PHP_EOL;
      }
    }
    if ($exact === true && $i < $disableExactEnd) {
      $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) {
      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) {
          $parens = $tokens[$parenCloser]['nested_parenthesis'];
          end($parens);
          $parens = key($parens);
          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 && (isset($tokens[$parenCloser]['parenthesis_owner']) === false || $parens > 0)) {
          $condition = $tokens[$parenCloser]['conditions'];
          end($condition);
          $condition = key($condition);
          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;
        $lastOpenTagConditions = array_keys($tokens[$lastOpenTag]['conditions']);
        $lastOpenTagCondition = array_pop($lastOpenTagConditions);
        if ($condition > 0 && $lastOpenTagCondition === $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'] && $tokens[$first - 1]['line'] === $tokens[$first]['line']) {

              // This is unlikely to be the start of the statement, so look
              // back further to find it.
              $first--;
              if ($this->debug === true) {
                $line = $tokens[$first]['line'];
                $type = $tokens[$first]['type'];
                echo "\t* first token is the parenthesis opener *" . PHP_EOL;
                echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
              }
            }
            $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,
                T_INLINE_HTML,
              ], $prev, true);
              if ($first !== false) {
                $prev = $phpcsFile
                  ->findStartOfStatement($first, T_COMMA);
                $first = $phpcsFile
                  ->findFirstOnLine([
                  T_WHITESPACE,
                  T_INLINE_HTML,
                ], $prev, true);
              }
              else {
                $first = $prev;
              }
              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;
              }
            }

            //end if
            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 be 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,
          T_DOUBLE_ARROW,
        ]);
        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,
            T_DOUBLE_ARROW,
          ]);
          $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;
          }
        }
        else {
          if ($tokens[$first]['code'] === T_WHITESPACE) {
            $first = $phpcsFile
              ->findNext(T_WHITESPACE, $first + 1, null, true);
          }
        }
        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) {
        $condition = $tokens[$checkToken]['conditions'];
        end($condition);
        $condition = key($condition);
      }
      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)) {
        $length = $tokenIndent + $adjustments[$first];

        // When fixing, we're going to adjust the indent of this line
        // here automatically, so use this new padding value when
        // comparing the expected padding to the actual padding.
        if ($phpcsFile->fixer->enabled === true) {
          $tokenIndent = $length;
          $this
            ->adjustIndent($phpcsFile, $checkToken, $length, $adjustments[$first]);
        }
        if ($this->debug === true) {
          $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) {
      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;
      }
      $conditionToken = array_pop($openScopes);
      if ($this->debug === true) {
        $line = $tokens[$conditionToken]['line'];
        $type = $tokens[$conditionToken]['type'];
        echo "\t=> removed open scope {$conditionToken} ({$type}) on line {$line}" . PHP_EOL;
      }
      if (isset($tokens[$scopeCloser]['scope_condition']) === true) {
        $first = $phpcsFile
          ->findFirstOnLine([
          T_WHITESPACE,
          T_INLINE_HTML,
        ], $tokens[$scopeCloser]['scope_condition'], true);
        if ($this->debug === true) {
          $line = $tokens[$first]['line'];
          $type = $tokens[$first]['type'];
          echo "\t* first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
        }
        while ($tokens[$first]['code'] === T_CONSTANT_ENCAPSED_STRING && $tokens[$first - 1]['code'] === T_CONSTANT_ENCAPSED_STRING) {
          $first = $phpcsFile
            ->findFirstOnLine(T_WHITESPACE, $first - 1, true);
          if ($this->debug === true) {
            $line = $tokens[$first]['line'];
            $type = $tokens[$first]['type'];
            echo "\t* found multi-line string; amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
          }
        }
        $currentIndent = $tokens[$first]['column'] - 1;
        if (isset($adjustments[$first]) === true) {
          $currentIndent += $adjustments[$first];
        }
        $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 {
        $conditionToken = array_pop($openScopes);
        if ($this->debug === true) {
          $line = $tokens[$conditionToken]['line'];
          $type = $tokens[$conditionToken]['type'];
          echo "\t=> removed open scope {$conditionToken} ({$type}) on line {$line}" . PHP_EOL;
        }
      }
      $parens = 0;
      if (isset($tokens[$scopeCloser]['nested_parenthesis']) === true && empty($tokens[$scopeCloser]['nested_parenthesis']) === false) {
        $parens = $tokens[$scopeCloser]['nested_parenthesis'];
        end($parens);
        $parens = key($parens);
        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) {
        $condition = $tokens[$scopeCloser]['conditions'];
        end($condition);
        $condition = key($condition);
        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, true) === 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 it 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) {
      $next = $phpcsFile
        ->findNext(Tokens::$emptyTokens, $checkToken + 1, null, true);
      if ($next === false || $tokens[$next]['code'] !== T_CLOSURE) {
        if ($this->debug === true) {
          $line = $tokens[$checkToken]['line'];
          $type = $tokens[$checkToken]['type'];
          echo "\t* method prefix ({$type}) found on line {$line}; indent set to exact *" . PHP_EOL;
        }
        $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;
    }

    // Open 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
    // in most cases.
    if ($checkToken !== null && ($tokens[$checkToken]['code'] === T_OPEN_TAG || $tokens[$checkToken]['code'] === T_OPEN_TAG_WITH_ECHO)) {
      $checkIndent = $tokens[$checkToken]['column'] - 1;

      // If we are re-opening a block that was closed in the same
      // scope as us, then reset the indent back to what the scope opener
      // set instead of using whatever indent this open tag has set.
      if (empty($tokens[$checkToken]['conditions']) === false) {
        $close = $phpcsFile
          ->findPrevious(T_CLOSE_TAG, $checkToken - 1);
        if ($close !== false && $tokens[$checkToken]['conditions'] === $tokens[$close]['conditions']) {
          $conditions = array_keys($tokens[$checkToken]['conditions']);
          $lastCondition = array_pop($conditions);
          $lastOpener = $tokens[$lastCondition]['scope_opener'];
          $lastCloser = $tokens[$lastCondition]['scope_closer'];
          if ($tokens[$lastCloser]['line'] !== $tokens[$checkToken]['line'] && isset($setIndents[$lastOpener]) === true) {
            $checkIndent = $setIndents[$lastOpener];
          }
        }
      }
      $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
    }

    //end if

    // Close tags needs to be indented to exact column positions.
    if ($checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_TAG) {
      $exact = true;
      $checkIndent = $currentIndent;
      $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
    }

    // Special case for ELSE statements that are not on the same
    // line as the previous IF statements closing brace. They still need
    // to have the same indent or it will break code after the block.
    if ($checkToken !== null && $tokens[$checkToken]['code'] === T_ELSE) {
      $exact = true;
    }

    // Don't perform strict checking on chained method calls since they
    // are often covered by custom rules.
    if ($checkToken !== null && $tokens[$checkToken]['code'] === T_OBJECT_OPERATOR && $exact === true) {
      $exact = false;
    }
    if ($checkIndent === null) {
      $checkIndent = $currentIndent;
    }

    // If the line starts with "->" we assume this is an indented chained
    // method invocation, so we add one level of indentation.
    if ($checkToken !== null && $tokens[$checkToken]['code'] === T_OBJECT_OPERATOR) {
      $exact = true;
      $checkIndent += $this->indent;
    }

    // Comments starting with a star have an extra whitespace.
    if ($checkToken !== null && $tokens[$checkToken]['code'] === T_COMMENT) {
      $content = trim($tokens[$checkToken]['content']);
      if ($content[0] === '*') {
        $checkIndent += 1;
      }
    }

    /*
        The indent of the line is checked by the following IF block.

        Up until now, we've just been figuring out what the indent
        of this line should be.

        After this IF block, we adjust the indent again for
        the checking of future lines
    */
    if ($checkToken !== null && isset($this->ignoreIndentation[$tokens[$checkToken]['code']]) === false && ($tokenIndent !== $checkIndent && $exact === true || $tokenIndent < $checkIndent && $exact === false)) {
      if ($tokenIndent > $checkIndent) {

        // Ignore multi line statements.
        $before = $phpcsFile
          ->findPrevious(Tokens::$emptyTokens, $checkToken - 1, null, true);
        if ($before !== false && in_array($tokens[$before]['code'], [
          T_SEMICOLON,
          T_CLOSE_CURLY_BRACKET,
          T_OPEN_CURLY_BRACKET,
          T_COLON,
          T_OPEN_TAG,
        ]) === false) {
          continue;
        }
      }

      // Skip array closing indentation errors, this is handled by the
      // ArraySniff.
      if ($tokens[$checkToken]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$checkToken]['parenthesis_owner']) === true && $tokens[$tokens[$checkToken]['parenthesis_owner']]['code'] === T_ARRAY || $tokens[$checkToken]['code'] === T_CLOSE_SHORT_ARRAY) {
        continue;
      }
      $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 = [
          floor($checkIndent / $this->tabWidth),
          floor($tokenIndent / $this->tabWidth),
        ];
      }
      else {
        $error .= '%s spaces, found %s';
        $data = [
          $checkIndent,
          $tokenIndent,
        ];
      }
      if ($this->debug === true) {
        $line = $tokens[$checkToken]['line'];
        $message = vsprintf($error, $data);
        echo "[Line {$line}] {$message}" . PHP_EOL;
      }

      // Assume the change would be applied and continue
      // checking indents under this assumption. This gives more
      // technically accurate error messages.
      $adjustments[$checkToken] = $checkIndent - $tokenIndent;
      $fix = $phpcsFile
        ->addFixableError($error, $checkToken, $type, $data);
      if ($fix === true || $this->debug === true) {
        $accepted = $this
          ->adjustIndent($phpcsFile, $checkToken, $checkIndent, $checkIndent - $tokenIndent);
        if ($accepted === true && $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
    if ($checkToken !== null) {
      $i = $checkToken;
    }

    // Don't check indents exactly between arrays as they tend to have custom rules.
    if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) {
      $disableExactEnd = max($disableExactEnd, $tokens[$i]['bracket_closer']);
      if ($this->debug === true) {
        $line = $tokens[$i]['line'];
        $type = $tokens[$disableExactEnd]['type'];
        echo "Opening short array bracket found on line {$line}" . PHP_EOL;
        if ($disableExactEnd === $tokens[$i]['bracket_closer']) {
          echo "\t=> disabling exact indent checking until {$disableExactEnd} ({$type})" . PHP_EOL;
        }
        else {
          echo "\t=> continuing to disable exact indent checking until {$disableExactEnd} ({$type})" . PHP_EOL;
        }
      }
    }

    // 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) {
      if ($this->debug === true) {
        $line = $tokens[$i]['line'];
        $type = $tokens[$disableExactEnd]['type'];
        echo "Here/nowdoc found on line {$line}" . PHP_EOL;
      }
      $i = $phpcsFile
        ->findNext([
        T_END_HEREDOC,
        T_END_NOWDOC,
      ], $i + 1);
      $next = $phpcsFile
        ->findNext(Tokens::$emptyTokens, $i + 1, null, true);
      if ($tokens[$next]['code'] === T_COMMA) {
        $i = $next;
      }
      if ($this->debug === true) {
        $line = $tokens[$i]['line'];
        $type = $tokens[$i]['type'];
        echo "\t* skipping to token {$i} ({$type}) on line {$line} *" . PHP_EOL;
      }
      continue;
    }

    //end if

    // 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);
      if ($this->debug === true) {
        $line = $tokens[$first]['line'];
        $type = $tokens[$first]['type'];
        echo "\t* first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
      }
      while ($tokens[$first]['code'] === T_CONSTANT_ENCAPSED_STRING && $tokens[$first - 1]['code'] === T_CONSTANT_ENCAPSED_STRING) {
        $first = $phpcsFile
          ->findFirstOnLine(T_WHITESPACE, $first - 1, true);
        if ($this->debug === true) {
          $line = $tokens[$first]['line'];
          $type = $tokens[$first]['type'];
          echo "\t* found multi-line string; amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
        }
      }
      $currentIndent = $tokens[$first]['column'] - 1 + $this->indent;
      $openScopes[$tokens[$i]['scope_closer']] = $tokens[$i]['scope_condition'];
      if ($this->debug === true) {
        $closerToken = $tokens[$i]['scope_closer'];
        $closerLine = $tokens[$closerToken]['line'];
        $closerType = $tokens[$closerToken]['type'];
        $conditionToken = $tokens[$i]['scope_condition'];
        $conditionLine = $tokens[$conditionToken]['line'];
        $conditionType = $tokens[$conditionToken]['type'];
        echo "\t=> added open scope {$closerToken} ({$closerType}) on line {$closerLine}, pointing to condition {$conditionToken} ({$conditionType}) on line {$conditionLine}" . PHP_EOL;
      }
      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, true) === 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) {
          $closerToken = $tokens[$i]['scope_closer'];
          $closerLine = $tokens[$closerToken]['line'];
          $closerType = $tokens[$closerToken]['type'];
          $conditionToken = $tokens[$i]['scope_condition'];
          $conditionLine = $tokens[$conditionToken]['line'];
          $conditionType = $tokens[$conditionToken]['type'];
          echo "\t=> added open scope {$closerToken} ({$closerType}) on line {$closerLine}, pointing to condition {$conditionToken} ({$conditionType}) on line {$conditionLine}" . PHP_EOL;
        }
        if ($this->debug === true) {
          $type = $tokens[$i]['type'];
          echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
        }
        continue;
      }

      //end if
    }

    //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) {
        $parens = $tokens[$i]['nested_parenthesis'];
        end($parens);
        $parens = key($parens);
        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) {
        $condition = $tokens[$i]['conditions'];
        end($condition);
        $condition = key($condition);
        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([
          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;
}