Chris@0: numTokens + 1 to skip Chris@0: * the rest of the file. Chris@0: */ Chris@17: public function process(File $phpcsFile, $stackPtr) Chris@0: { Chris@0: $tokens = $phpcsFile->getTokens(); Chris@0: Chris@0: // Skip this sniff in *api.php files because they want to have fully Chris@0: // qualified names for documentation purposes. Chris@0: if (substr($phpcsFile->getFilename(), -8) === '.api.php') { Chris@0: return ($phpcsFile->numTokens + 1); Chris@0: } Chris@0: Chris@0: // We are only interested in a backslash embedded between strings, which Chris@0: // means this is a class reference with more than once namespace part. Chris@0: if ($tokens[($stackPtr - 1)]['code'] !== T_STRING || $tokens[($stackPtr + 1)]['code'] !== T_STRING) { Chris@0: return; Chris@0: } Chris@0: Chris@0: // Check if this is a use statement and ignore those. Chris@0: $before = $phpcsFile->findPrevious([T_STRING, T_NS_SEPARATOR, T_WHITESPACE], $stackPtr, null, true); Chris@0: if ($tokens[$before]['code'] === T_USE || $tokens[$before]['code'] === T_NAMESPACE) { Chris@0: return $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR], ($stackPtr + 1), null, true); Chris@0: } Chris@0: Chris@0: // If this is a namespaced function call then ignore this because use Chris@0: // statements for functions are not possible in PHP 5.5 and lower. Chris@0: $after = $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR, T_WHITESPACE], $stackPtr, null, true); Chris@0: if ($tokens[$after]['code'] === T_OPEN_PARENTHESIS && $tokens[$before]['code'] !== T_NEW) { Chris@0: return ($after + 1); Chris@0: } Chris@0: Chris@0: $error = 'Namespaced classes/interfaces/traits should be referenced with use statements'; Chris@0: $fix = $phpcsFile->addFixableError($error, $stackPtr, 'UseStatementMissing'); Chris@0: Chris@0: if ($fix === true) { Chris@0: $fullName = $phpcsFile->getTokensAsString(($before + 1), ($after - 1 - $before)); Chris@0: $fullName = trim($fullName, '\ '); Chris@0: Chris@0: $phpcsFile->fixer->beginChangeset(); Chris@0: Chris@0: // Replace the fully qualified name with the local name. Chris@0: for ($i = ($before + 1); $i < $after; $i++) { Chris@0: if ($tokens[$i]['code'] !== T_WHITESPACE) { Chris@0: $phpcsFile->fixer->replaceToken($i, ''); Chris@0: } Chris@0: } Chris@0: Chris@0: $parts = explode('\\', $fullName); Chris@0: $className = end($parts); Chris@0: $phpcsFile->fixer->addContentBefore(($after - 1), $className); Chris@0: Chris@0: // Check if there is a use statement already for this class and Chris@0: // namespace. Chris@0: $alreadyUsed = false; Chris@0: $useStatement = $phpcsFile->findNext(T_USE, 0); Chris@0: while ($useStatement !== false && empty($tokens[$useStatement]['conditions']) === true) { Chris@0: $useEnd = $phpcsFile->findEndOfStatement($useStatement); Chris@0: $classRef = trim($phpcsFile->getTokensAsString(($useStatement + 1), ($useEnd - 1 - $useStatement))); Chris@0: if (strcasecmp($classRef, $fullName) === 0) { Chris@0: $alreadyUsed = true; Chris@0: break; Chris@0: } Chris@0: Chris@0: $useStatement = $phpcsFile->findNext(T_USE, ($useEnd + 1)); Chris@0: } Chris@0: Chris@0: // @todo Check if the name is already in use - then we need to alias it. Chris@0: // Insert use statement at the beginning of the file if it is not there Chris@0: // already. Also check if another sniff (for example Chris@0: // UnusedUseStatementSniff) has already deleted the use statement, then Chris@0: // we need to add it back. Chris@0: if ($alreadyUsed === false Chris@0: || $phpcsFile->fixer->getTokenContent($useStatement) !== $tokens[$useStatement]['content'] Chris@0: ) { Chris@0: // Check if there is a group of use statements and add it there. Chris@0: $useStatement = $phpcsFile->findNext(T_USE, 0); Chris@0: if ($useStatement !== false && empty($tokens[$useStatement]['conditions']) === true) { Chris@0: $phpcsFile->fixer->addContentBefore($useStatement, "use $fullName;\n"); Chris@0: } else { Chris@0: // Check if there is an @file comment. Chris@0: $beginning = 0; Chris@0: $fileComment = $phpcsFile->findNext(T_WHITESPACE, ($beginning + 1), null, true); Chris@0: if ($tokens[$fileComment]['code'] === T_DOC_COMMENT_OPEN_TAG) { Chris@0: $beginning = $tokens[$fileComment]['comment_closer']; Chris@0: } Chris@0: Chris@0: $phpcsFile->fixer->addContent($beginning, "use $fullName;\n"); Chris@0: } Chris@0: } Chris@0: Chris@0: $phpcsFile->fixer->endChangeset(); Chris@0: }//end if Chris@0: Chris@0: // Continue after this class reference so that errors for this are not Chris@0: // flagged multiple times. Chris@0: return $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR], ($stackPtr + 1), null, true); Chris@0: Chris@0: }//end process() Chris@0: Chris@0: Chris@0: }//end class