*/ public function register() { return [\T_USE]; } /** * Processes this test, when one of its tokens is encountered. * * @since 1.0.0 * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { if (UseStatements::isImportUse($phpcsFile, $stackPtr) === false) { // Trait or closure use statement. return; } $endOfStatement = $phpcsFile->findNext([\T_SEMICOLON, \T_CLOSE_TAG, \T_OPEN_USE_GROUP], ($stackPtr + 1)); if ($endOfStatement === false) { // Live coding or parse error. return; } $tokens = $phpcsFile->getTokens(); $current = $stackPtr; do { $continue = $this->processImport($phpcsFile, $current, $endOfStatement); if ($continue === false) { break; } // Move the stackPtr forward to the next part of the use statement, if any. $current = $phpcsFile->findNext(\T_COMMA, ($current + 1), $endOfStatement); } while ($current !== false); if ($tokens[$endOfStatement]['code'] !== \T_OPEN_USE_GROUP) { // Finished the statement. return; } $current = $endOfStatement; // Group open brace. $endOfStatement = $phpcsFile->findNext([\T_CLOSE_USE_GROUP], ($endOfStatement + 1)); if ($endOfStatement === false) { // Live coding or parse error. return; } do { $continue = $this->processImport($phpcsFile, $current, $endOfStatement, true); if ($continue === false) { break; } // Move the stackPtr forward to the next part of the use statement, if any. $current = $phpcsFile->findNext(\T_COMMA, ($current + 1), $endOfStatement); } while ($current !== false); } /** * Examine an individual import statement. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token. * @param int $endOfStatement End token for the current import statement. * @param bool $groupUse Whether the current statement is a partial one * within a group use statement. * * @return bool Whether or not to continue examining this import use statement. */ private function processImport(File $phpcsFile, $stackPtr, $endOfStatement, $groupUse = false) { $tokens = $phpcsFile->getTokens(); $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), $endOfStatement, true); if ($nextNonEmpty === false) { // Reached the end of the statement. return false; } // Skip past 'function'/'const' keyword. $contentLC = \strtolower($tokens[$nextNonEmpty]['content']); if ($tokens[$nextNonEmpty]['code'] === \T_STRING && ($contentLC === 'function' || $contentLC === 'const') ) { $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($nextNonEmpty + 1), $endOfStatement, true); if ($nextNonEmpty === false) { // Reached the end of the statement. return false; } } if ($tokens[$nextNonEmpty]['code'] === \T_NS_SEPARATOR) { $phpcsFile->recordMetric($nextNonEmpty, self::METRIC_NAME, 'yes'); $error = 'An import use statement should never start with a leading backslash'; $code = 'LeadingBackslashFound'; if ($groupUse === true) { $error = 'Parse error: partial import use statement in a use group starting with a leading backslash'; $code = 'LeadingBackslashFoundInGroup'; } $fix = $phpcsFile->addFixableError($error, $nextNonEmpty, $code); if ($fix === true) { if ($tokens[$nextNonEmpty - 1]['code'] !== \T_WHITESPACE) { $phpcsFile->fixer->replaceToken($nextNonEmpty, ' '); } else { $phpcsFile->fixer->replaceToken($nextNonEmpty, ''); } } } else { $phpcsFile->recordMetric($nextNonEmpty, self::METRIC_NAME, 'no'); } return true; } }