You are here

public function UseGlobalClassSniff::process in Coder 8.3

Same name and namespace in other branches
  1. 8.3.x coder_sniffer/Drupal/Sniffs/Classes/UseGlobalClassSniff.php \Drupal\Sniffs\Classes\UseGlobalClassSniff::process()

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

Parameters

\PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where the: token was found.

int $stackPtr The position in the PHP_CodeSniffer: file's token stack where the token was found.

Return value

void|int Optionally returns a stack pointer. The sniff will not be called again on the current file until the returned stack pointer is reached. Return $phpcsFile->numTokens + 1 to skip the rest of the file.

File

coder_sniffer/Drupal/Sniffs/Classes/UseGlobalClassSniff.php, line 52

Class

UseGlobalClassSniff
Checks non-namespaced classes are referenced by FQN, not imported.

Namespace

Drupal\Sniffs\Classes

Code

public function process(File $phpcsFile, $stackPtr) {
  $tokens = $phpcsFile
    ->getTokens();

  // Find the first declaration, marking the end of the use statements.
  $bodyStart = $phpcsFile
    ->findNext([
    T_CLASS,
    T_INTERFACE,
    T_TRAIT,
    T_FUNCTION,
  ], 0);

  // Ensure we are in the global scope, to exclude trait use statements.
  if (empty($tokens[$stackPtr]['conditions']) === false) {
    return;
  }

  // End of the full statement.
  $stmtEnd = $phpcsFile
    ->findNext(T_SEMICOLON, $stackPtr);
  $lineStart = $stackPtr;

  // Iterate through a potential multiline use statement.
  while (false !== ($lineEnd = $phpcsFile
    ->findNext([
    T_SEMICOLON,
    T_COMMA,
  ], $lineStart + 1, $stmtEnd + 1))) {

    // We are only interested in imports that contain no backslash,
    // which means this is a class without a namespace.
    // Also skip function imports.
    if ($phpcsFile
      ->findNext(T_NS_SEPARATOR, $lineStart, $lineEnd) !== false || $phpcsFile
      ->findNext(T_STRING, $lineStart, $lineEnd, false, 'function') !== false) {
      $lineStart = $lineEnd;
      continue;
    }

    // The first string token is the class name.
    $class = $phpcsFile
      ->findNext(T_STRING, $lineStart, $lineEnd);
    $className = $tokens[$class]['content'];

    // If there is more than one string token, the last one is the alias.
    $alias = $phpcsFile
      ->findPrevious(T_STRING, $lineEnd, $stackPtr);
    $aliasName = $tokens[$alias]['content'];
    $error = 'Non-namespaced classes/interfaces/traits should not be referenced with use statements';
    $fix = $phpcsFile
      ->addFixableError($error, $class, 'RedundantUseStatement');
    if ($fix === true) {
      $phpcsFile->fixer
        ->beginChangeset();

      // Remove the entire line by default.
      $start = $lineStart;
      $end = $lineEnd;
      $next = $phpcsFile
        ->findNext(T_WHITESPACE, $end + 1, null, true);
      if ($tokens[$lineStart]['code'] === T_COMMA) {

        // If there are lines before this one,
        // then leave the ending delimiter in place.
        $end = $lineEnd - 1;
      }
      else {
        if ($tokens[$lineEnd]['code'] === T_COMMA) {

          // If there are lines after, but not before,
          // then leave the use keyword.
          $start = $class;
        }
        else {
          if ($tokens[$next]['code'] === T_USE) {

            // If the whole statement is removed, and there is one after it,
            // then also remove the linebreaks.
            $end = $next - 1;
          }
        }
      }
      for ($i = $start; $i <= $end; $i++) {
        $phpcsFile->fixer
          ->replaceToken($i, '');
      }

      // Find all usages of the class, and add a leading backslash.
      // Only start looking after the end of the use statement block.
      $i = $bodyStart;
      while (false !== ($i = $phpcsFile
        ->findNext(T_STRING, $i + 1, null, false, $aliasName))) {
        if ($tokens[$i - 1]['code'] !== T_NS_SEPARATOR) {
          $phpcsFile->fixer
            ->replaceToken($i, '\\' . $className);
        }
      }
      $phpcsFile->fixer
        ->endChangeset();
    }

    //end if
    $lineStart = $lineEnd;
  }

  //end while
}