Skip to content

Commit

Permalink
While loop - condition always false
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Sep 21, 2021
1 parent f11480b commit 217fac3
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
7 changes: 7 additions & 0 deletions conf/config.level4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ services:
tags:
- phpstan.rules.rule

-
class: PHPStan\Rules\Comparison\WhileLoopAlwaysFalseConditionRule
arguments:
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
tags:
- phpstan.rules.rule

-
class: PHPStan\Rules\TooWideTypehints\TooWideMethodReturnTypehintRule
arguments:
Expand Down
62 changes: 62 additions & 0 deletions src/Rules/Comparison/WhileLoopAlwaysFalseConditionRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Comparison;

use PhpParser\Node\Stmt\While_;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\Constant\ConstantBooleanType;

/**
* @implements \PHPStan\Rules\Rule<While_>
*/
class WhileLoopAlwaysFalseConditionRule implements \PHPStan\Rules\Rule
{

private ConstantConditionRuleHelper $helper;

private bool $treatPhpDocTypesAsCertain;

public function __construct(
ConstantConditionRuleHelper $helper,
bool $treatPhpDocTypesAsCertain
)
{
$this->helper = $helper;
$this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain;
}

public function getNodeType(): string
{
return While_::class;
}

public function processNode(
\PhpParser\Node $node,
\PHPStan\Analyser\Scope $scope
): array
{
$exprType = $this->helper->getBooleanType($scope, $node->cond);
if ($exprType instanceof ConstantBooleanType && !$exprType->getValue()) {
$addTip = function (RuleErrorBuilder $ruleErrorBuilder) use ($scope, $node): RuleErrorBuilder {
if (!$this->treatPhpDocTypesAsCertain) {
return $ruleErrorBuilder;
}

$booleanNativeType = $this->helper->getNativeBooleanType($scope, $node->cond);
if ($booleanNativeType instanceof ConstantBooleanType) {
return $ruleErrorBuilder;
}

return $ruleErrorBuilder->tip('Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.');
};

return [
$addTip(RuleErrorBuilder::message('While loop condition is always false.'))->line($node->cond->getLine())
->build(),
];
}

return [];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Comparison;

/**
* @extends \PHPStan\Testing\RuleTestCase<WhileLoopAlwaysFalseConditionRule>
*/
class WhileLoopAlwaysFalseConditionRuleTest extends \PHPStan\Testing\RuleTestCase
{

/** @var bool */
private $treatPhpDocTypesAsCertain = true;

protected function getRule(): \PHPStan\Rules\Rule
{
return new WhileLoopAlwaysFalseConditionRule(
new ConstantConditionRuleHelper(
new ImpossibleCheckTypeHelper(
$this->createReflectionProvider(),
$this->getTypeSpecifier(),
[],
$this->treatPhpDocTypesAsCertain
),
$this->treatPhpDocTypesAsCertain
),
$this->treatPhpDocTypesAsCertain
);
}

protected function shouldTreatPhpDocTypesAsCertain(): bool
{
return $this->treatPhpDocTypesAsCertain;
}

public function testRule(): void
{
$this->analyse([__DIR__ . '/data/while-loop-false.php'], [
[
'While loop condition is always false.',
10,
],
[
'While loop condition is always false.',
20,
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
],
]);
}

}
35 changes: 35 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/while-loop-false.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace WhileLoopFalse;

class Foo
{

public function doFoo(): void
{
while (false) {

}
}

/**
* @param 0 $s
*/
public function doBar($s): void
{
while ($s) {

}
}

/**
* @param string $s
*/
public function doBar2($s): void
{
while ($s === null) { // reported by StrictComparisonOfDifferentTypesRule

}
}

}

0 comments on commit 217fac3

Please sign in to comment.