class RequireNullCoalesceOperatorSniff
Hierarchy
- class \SlevomatCodingStandard\Sniffs\ControlStructures\RequireNullCoalesceOperatorSniff implements \PHP_CodeSniffer\Sniffs\Sniff
Expanded class hierarchy of RequireNullCoalesceOperatorSniff
File
-
vendor/
slevomat/ coding-standard/ SlevomatCodingStandard/ Sniffs/ ControlStructures/ RequireNullCoalesceOperatorSniff.php, line 24
Namespace
SlevomatCodingStandard\Sniffs\ControlStructuresView source
class RequireNullCoalesceOperatorSniff implements Sniff {
public const CODE_NULL_COALESCE_OPERATOR_NOT_USED = 'NullCoalesceOperatorNotUsed';
/**
* @return array<int, (int|string)>
*/
public function register() : array {
return [
T_ISSET,
T_IS_IDENTICAL,
T_IS_NOT_IDENTICAL,
];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer) : void {
$tokens = $phpcsFile->getTokens();
if ($tokens[$pointer]['code'] === T_ISSET) {
$this->checkIsset($phpcsFile, $pointer);
}
else {
$this->checkIdenticalOperator($phpcsFile, $pointer);
}
}
public function checkIsset(File $phpcsFile, int $issetPointer) : void {
$tokens = $phpcsFile->getTokens();
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $issetPointer - 1);
if ($tokens[$previousPointer]['code'] === T_BOOLEAN_NOT) {
return;
}
if (in_array($tokens[$previousPointer]['code'], Tokens::$booleanOperators, true)) {
return;
}
$openParenthesisPointer = TokenHelper::findNextEffective($phpcsFile, $issetPointer + 1);
$closeParenthesisPointer = $tokens[$openParenthesisPointer]['parenthesis_closer'];
/** @var int $inlineThenPointer */
$inlineThenPointer = TokenHelper::findNextEffective($phpcsFile, $closeParenthesisPointer + 1);
if ($tokens[$inlineThenPointer]['code'] !== T_INLINE_THEN) {
return;
}
$commaPointer = TokenHelper::findNext($phpcsFile, T_COMMA, $openParenthesisPointer + 1, $closeParenthesisPointer);
if ($commaPointer !== null) {
return;
}
$inlineElsePointer = TernaryOperatorHelper::getElsePointer($phpcsFile, $inlineThenPointer);
$variableContent = IdentificatorHelper::getContent($phpcsFile, $openParenthesisPointer + 1, $closeParenthesisPointer - 1);
$thenContent = IdentificatorHelper::getContent($phpcsFile, $inlineThenPointer + 1, $inlineElsePointer - 1);
if ($variableContent !== $thenContent) {
return;
}
$fix = $phpcsFile->addFixableError('Use null coalesce operator instead of ternary operator.', $inlineThenPointer, self::CODE_NULL_COALESCE_OPERATOR_NOT_USED);
if (!$fix) {
return;
}
$startPointer = $issetPointer;
if (in_array($tokens[$previousPointer]['code'], Tokens::$castTokens, true)) {
$startPointer = $previousPointer;
}
$phpcsFile->fixer
->beginChangeset();
FixerHelper::change($phpcsFile, $startPointer, $inlineElsePointer, sprintf('%s ??', $variableContent));
$phpcsFile->fixer
->endChangeset();
}
public function checkIdenticalOperator(File $phpcsFile, int $identicalOperator) : void {
$tokens = $phpcsFile->getTokens();
/** @var int $pointerBeforeIdenticalOperator */
$pointerBeforeIdenticalOperator = TokenHelper::findPreviousEffective($phpcsFile, $identicalOperator - 1);
/** @var int $pointerAfterIdenticalOperator */
$pointerAfterIdenticalOperator = TokenHelper::findNextEffective($phpcsFile, $identicalOperator + 1);
if ($tokens[$pointerBeforeIdenticalOperator]['code'] !== T_NULL && $tokens[$pointerAfterIdenticalOperator]['code'] !== T_NULL) {
return;
}
$isYodaCondition = $tokens[$pointerBeforeIdenticalOperator]['code'] === T_NULL;
$variableEndPointer = $isYodaCondition ? $pointerAfterIdenticalOperator : $pointerBeforeIdenticalOperator;
$tmpPointer = $variableEndPointer;
while ($tokens[$tmpPointer]['code'] === T_CLOSE_PARENTHESIS) {
/** @var int $tmpPointer */
$tmpPointer = TokenHelper::findPreviousEffective($phpcsFile, $tokens[$tmpPointer]['parenthesis_opener'] - 1);
}
$variableStartPointer = IdentificatorHelper::findStartPointer($phpcsFile, $tmpPointer);
if ($variableStartPointer === null) {
return;
}
$pointerBeforeCondition = TokenHelper::findPreviousEffective($phpcsFile, ($isYodaCondition ? $pointerBeforeIdenticalOperator : $variableStartPointer) - 1);
if (in_array($tokens[$pointerBeforeCondition]['code'], Tokens::$booleanOperators, true)) {
return;
}
/** @var int $inlineThenPointer */
$inlineThenPointer = TokenHelper::findNextEffective($phpcsFile, ($isYodaCondition ? $variableEndPointer : $pointerAfterIdenticalOperator) + 1);
if ($tokens[$inlineThenPointer]['code'] !== T_INLINE_THEN) {
return;
}
$inlineElsePointer = TernaryOperatorHelper::getElsePointer($phpcsFile, $inlineThenPointer);
$inlineElseEndPointer = TernaryOperatorHelper::getEndPointer($phpcsFile, $inlineThenPointer, $inlineElsePointer);
$pointerAfterInlineElseEnd = TokenHelper::findNextEffective($phpcsFile, $inlineElseEndPointer + 1);
$variableContent = IdentificatorHelper::getContent($phpcsFile, $variableStartPointer, $variableEndPointer);
/** @var int $compareToStartPointer */
$compareToStartPointer = TokenHelper::findNextEffective($phpcsFile, ($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL ? $inlineElsePointer : $inlineThenPointer) + 1);
/** @var int $compareToEndPointer */
$compareToEndPointer = TokenHelper::findPreviousEffective($phpcsFile, ($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL ? $pointerAfterInlineElseEnd : $inlineElsePointer) - 1);
$compareToContent = IdentificatorHelper::getContent($phpcsFile, $compareToStartPointer, $compareToEndPointer);
if ($compareToContent !== $variableContent) {
return;
}
$fix = $phpcsFile->addFixableError('Use null coalesce operator instead of ternary operator.', $inlineThenPointer, self::CODE_NULL_COALESCE_OPERATOR_NOT_USED);
if (!$fix) {
return;
}
/** @var int $conditionStart */
$conditionStart = $isYodaCondition ? $pointerBeforeIdenticalOperator : $variableStartPointer;
$variableContent = trim(TokenHelper::getContent($phpcsFile, $variableStartPointer, $variableEndPointer));
$phpcsFile->fixer
->beginChangeset();
$phpcsFile->fixer
->replaceToken($conditionStart, sprintf('%s ??', $variableContent));
if ($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL) {
FixerHelper::removeBetweenIncluding($phpcsFile, $conditionStart + 1, $inlineThenPointer);
$pointerBeforeInlineElse = TokenHelper::findPreviousEffective($phpcsFile, $inlineElsePointer - 1);
FixerHelper::removeBetweenIncluding($phpcsFile, $pointerBeforeInlineElse + 1, $inlineElseEndPointer);
}
else {
FixerHelper::removeBetweenIncluding($phpcsFile, $conditionStart + 1, $inlineElsePointer);
}
$phpcsFile->fixer
->endChangeset();
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title |
---|---|---|---|---|
RequireNullCoalesceOperatorSniff::checkIdenticalOperator | public | function | ||
RequireNullCoalesceOperatorSniff::checkIsset | public | function | ||
RequireNullCoalesceOperatorSniff::CODE_NULL_COALESCE_OPERATOR_NOT_USED | public | constant | ||
RequireNullCoalesceOperatorSniff::process | public | function | * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint * |
Overrides Sniff::process |
RequireNullCoalesceOperatorSniff::register | public | function | * | Overrides Sniff::register |