Skip to content

Commit f77cd97

Browse files
committed
EarlyExitSniff: fixed fixer for complicated logical conditions
1 parent a53b8da commit f77cd97

File tree

4 files changed

+53
-13
lines changed

4 files changed

+53
-13
lines changed

SlevomatCodingStandard/Sniffs/ControlStructures/EarlyExitSniff.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,13 @@ private function processElse(\PHP_CodeSniffer\Files\File $phpcsFile, int $elsePo
124124

125125
$ifCode = $this->getScopeCode($phpcsFile, $ifPointer);
126126
$elseCode = $this->getScopeCode($phpcsFile, $elsePointer);
127-
$negativeIfCondition = $this->getNegativeCondition($phpcsFile, $tokens[$ifPointer]['parenthesis_opener'] + 1, $tokens[$ifPointer]['parenthesis_closer'] - 1);
127+
$negativeIfCondition = $this->getNegativeCondition($phpcsFile, $tokens[$ifPointer]['parenthesis_opener'], $tokens[$ifPointer]['parenthesis_closer']);
128128
$afterIfCode = $this->fixIndentation($ifCode, $phpcsFile->eolChar, $this->getIndentation($phpcsFile, $ifPointer));
129129

130130
$phpcsFile->fixer->addContent(
131131
$ifPointer,
132132
sprintf(
133-
'if (%s) {%s}%s%s',
133+
'if %s {%s}%s%s',
134134
$negativeIfCondition,
135135
$elseCode,
136136
$phpcsFile->eolChar,
@@ -225,7 +225,7 @@ private function processIf(\PHP_CodeSniffer\Files\File $phpcsFile, int $ifPointe
225225
$earlyExitCode = $this->getEarlyExitCode($tokens[$scopePointer]['code']);
226226
$earlyExitCodeIndentation = $this->prepareIndentation($ifIndentation);
227227

228-
$negativeIfCondition = $this->getNegativeCondition($phpcsFile, $tokens[$ifPointer]['parenthesis_opener'] + 1, $tokens[$ifPointer]['parenthesis_closer'] - 1);
228+
$negativeIfCondition = $this->getNegativeCondition($phpcsFile, $tokens[$ifPointer]['parenthesis_opener'], $tokens[$ifPointer]['parenthesis_closer']);
229229

230230
$phpcsFile->fixer->beginChangeset();
231231

@@ -238,7 +238,7 @@ private function processIf(\PHP_CodeSniffer\Files\File $phpcsFile, int $ifPointe
238238
$phpcsFile->fixer->addContent(
239239
$ifPointer,
240240
sprintf(
241-
'if (%s) {%s%s%s;%s%s}%s%s',
241+
'if %s {%s%s%s;%s%s}%s%s',
242242
$negativeIfCondition,
243243
$phpcsFile->eolChar,
244244
$earlyExitCodeIndentation,
@@ -291,7 +291,7 @@ private function getEarlyExitCode($code): string
291291
return 'return';
292292
}
293293

294-
private function getNegativeCondition(\PHP_CodeSniffer\Files\File $phpcsFile, int $conditionBoundaryStartPointer, int $conditionBoundaryEndPointer, bool $nested = false): string
294+
private function getNegativeConditionPart(\PHP_CodeSniffer\Files\File $phpcsFile, int $conditionBoundaryStartPointer, int $conditionBoundaryEndPointer, bool $nested): string
295295
{
296296
$tokens = $phpcsFile->getTokens();
297297

@@ -314,7 +314,7 @@ private function getNegativeCondition(\PHP_CodeSniffer\Files\File $phpcsFile, in
314314
}
315315
}
316316

317-
if (!$nested && count($booleanPointers) > 0) {
317+
if (count($booleanPointers) > 0) {
318318
return $this->getNegativeLogicalCondition($phpcsFile, $conditionBoundaryStartPointer, $conditionBoundaryEndPointer);
319319
}
320320

@@ -405,30 +405,38 @@ private function getNegativeLogicalCondition(\PHP_CodeSniffer\Files\File $phpcsF
405405
continue;
406406
}
407407

408-
$negativeCondition .= $this->getNegativeNestedCondition($phpcsFile, $nestedConditionStartPointer, $actualPointer - 1);
408+
$negativeCondition .= $this->getNegativeCondition($phpcsFile, $nestedConditionStartPointer, $actualPointer - 1, true);
409409
$negativeCondition .= $booleanOperatorReplacements[$tokens[$actualPointer]['code']];
410410

411411
$nestedConditionStartPointer = $actualPointer + 1;
412412
$actualPointer++;
413413

414414
} while (true);
415415

416-
$negativeCondition .= $this->getNegativeNestedCondition($phpcsFile, $nestedConditionStartPointer, $conditionBoundaryEndPointer);
416+
$negativeCondition .= $this->getNegativeCondition($phpcsFile, $nestedConditionStartPointer, $conditionBoundaryEndPointer, true);
417417

418418
return $negativeCondition;
419419
}
420420

421-
private function getNegativeNestedCondition(\PHP_CodeSniffer\Files\File $phpcsFile, int $conditionBoundaryStartPointer, int $conditionBoundaryEndPointer): string
421+
private function getNegativeCondition(\PHP_CodeSniffer\Files\File $phpcsFile, int $conditionBoundaryStartPointer, int $conditionBoundaryEndPointer, bool $nested = false): string
422422
{
423423
/** @var int $conditionStartPointer */
424424
$conditionStartPointer = TokenHelper::findNextEffective($phpcsFile, $conditionBoundaryStartPointer);
425425
/** @var int $conditionEndPointer */
426426
$conditionEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $conditionBoundaryEndPointer);
427427

428+
$tokens = $phpcsFile->getTokens();
429+
if ($tokens[$conditionStartPointer]['code'] === T_OPEN_PARENTHESIS && $tokens[$conditionStartPointer]['parenthesis_closer'] === $conditionEndPointer) {
430+
/** @var int $conditionStartPointer */
431+
$conditionStartPointer = TokenHelper::findNextEffective($phpcsFile, $conditionStartPointer + 1);
432+
/** @var int $conditionEndPointer */
433+
$conditionEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $conditionEndPointer - 1);
434+
}
435+
428436
return sprintf(
429437
'%s%s%s',
430438
$conditionBoundaryStartPointer !== $conditionStartPointer ? TokenHelper::getContent($phpcsFile, $conditionBoundaryStartPointer, $conditionStartPointer - 1) : '',
431-
$this->getNegativeCondition($phpcsFile, $conditionStartPointer, $conditionEndPointer, true),
439+
$this->getNegativeConditionPart($phpcsFile, $conditionStartPointer, $conditionEndPointer, $nested),
432440
$conditionBoundaryEndPointer !== $conditionEndPointer ? TokenHelper::getContent($phpcsFile, $conditionEndPointer + 1, $conditionBoundaryEndPointer) : ''
433441
);
434442
}

tests/Sniffs/ControlStructures/EarlyExitSniffTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ public function testErrors(): void
1616
{
1717
$report = self::checkFile(__DIR__ . '/data/earlyExitErrors.php');
1818

19-
self::assertSame(46, $report->getErrorCount());
19+
self::assertSame(48, $report->getErrorCount());
2020

2121
foreach ([6, 15, 24, 33, 42, 50, 58, 66, 74, 82, 90, 98, 108, 149, 157, 165, 191, 199, 207] as $line) {
2222
self::assertSniffError($report, $line, EarlyExitSniff::CODE_EARLY_EXIT_NOT_USED, 'Use early exit instead of else.');
2323
}
2424

25-
foreach ([115, 122, 129, 135, 141, 213, 222, 229, 235, 241, 247, 256, 262, 271, 287, 305] as $line) {
25+
foreach ([115, 122, 129, 135, 141, 213, 222, 229, 235, 241, 247, 256, 262, 271, 287, 305, 361, 368] as $line) {
2626
self::assertSniffError($report, $line, EarlyExitSniff::CODE_EARLY_EXIT_NOT_USED, 'Use early exit to reduce code nesting.');
2727
}
2828

tests/Sniffs/ControlStructures/data/earlyExitErrors.fixed.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ function inlineCommentAfterIf() {
206206
}
207207

208208
function logicalCombinedCondition() {
209-
if (!(true && true) && !false) {
209+
if ((!true || !true) && !false) {
210210
return;
211211
}
212212

@@ -403,3 +403,21 @@ function ifElseInElse() {
403403

404404
doSomething();
405405
}
406+
407+
function logicalCombinedComplicatedCondition() {
408+
foreach ($records as $record) {
409+
if (!in_array($record['type'], ['A', 'C']) || (strpos($record['name'], 'www.') !== 0 && strpos($record['name'], 'ftp.') !== 0)) {
410+
continue;
411+
}
412+
413+
echo 'You should see this echo twice!'.PHP_EOL;
414+
}
415+
}
416+
417+
function logicalVeryComplicatedCondition() {
418+
if ((!true) || ((!false && !true) && (!false || (!true)))) {
419+
return;
420+
}
421+
422+
doSomething();
423+
}

tests/Sniffs/ControlStructures/data/earlyExitErrors.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,17 @@ function ifElseInElse() {
355355
}
356356
}
357357
}
358+
359+
function logicalCombinedComplicatedCondition() {
360+
foreach ($records as $record) {
361+
if (in_array($record['type'], ['A', 'C']) && (strpos($record['name'], 'www.') === 0 || strpos($record['name'], 'ftp.') === 0)) {
362+
echo 'You should see this echo twice!'.PHP_EOL;
363+
}
364+
}
365+
}
366+
367+
function logicalVeryComplicatedCondition() {
368+
if ((true) && ((false || true) || (false && (true)))) {
369+
doSomething();
370+
}
371+
}

0 commit comments

Comments
 (0)