Skip to content

Commit

Permalink
Support treatPhpDocTypesAsCertain in NumberComparisonOperatorsConstan…
Browse files Browse the repository at this point in the history
…tConditionRule
  • Loading branch information
ondrejmirtes committed Jan 19, 2023
1 parent 01f7309 commit 649eb70
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 5 deletions.
8 changes: 7 additions & 1 deletion conf/config.level4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ includes:

rules:
- PHPStan\Rules\Arrays\DeadForeachRule
- PHPStan\Rules\Comparison\NumberComparisonOperatorsConstantConditionRule
- PHPStan\Rules\DeadCode\NoopRule
- PHPStan\Rules\DeadCode\UnreachableStatementRule
- PHPStan\Rules\DeadCode\UnusedPrivateConstantRule
Expand Down Expand Up @@ -127,6 +126,13 @@ services:
tags:
- phpstan.rules.rule

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

-
class: PHPStan\Rules\Comparison\StrictComparisonOfDifferentTypesRule
arguments:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
class NumberComparisonOperatorsConstantConditionRule implements Rule
{

public function __construct(
private bool $treatPhpDocTypesAsCertain,
)
{
}

public function getNodeType(): string
{
return BinaryOp::class;
Expand All @@ -36,16 +42,29 @@ public function processNode(
return [];
}

$exprType = $scope->getType($node);
$exprType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node) : $scope->getNativeType($node);
if ($exprType instanceof ConstantBooleanType) {
$addTip = function (RuleErrorBuilder $ruleErrorBuilder) use ($scope, $node): RuleErrorBuilder {
if (!$this->treatPhpDocTypesAsCertain) {
return $ruleErrorBuilder;
}

$booleanNativeType = $scope->getNativeType($node);
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 [
RuleErrorBuilder::message(sprintf(
$addTip(RuleErrorBuilder::message(sprintf(
'Comparison operation "%s" between %s and %s is always %s.',
$node->getOperatorSigil(),
$scope->getType($node->left)->describe(VerbosityLevel::value()),
$scope->getType($node->right)->describe(VerbosityLevel::value()),
$exprType->getValue() ? 'true' : 'false',
))->build(),
)))->build(),
];
}

Expand Down
17 changes: 17 additions & 0 deletions tests/PHPStan/Analyser/data/native-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,20 @@ public function doFoo(): void
}

}

class PositiveInt
{

/**
* @param positive-int $i
* @return void
*/
public function doFoo(int $i): void
{
assertType('true', $i > 0);
assertType('false', $i <= 0);
assertNativeType('bool', $i > 0);
assertNativeType('bool', $i <= 0);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
class NumberComparisonOperatorsConstantConditionRuleTest extends RuleTestCase
{

private bool $treatPhpDocTypesAsCertain = true;

protected function getRule(): Rule
{
return new NumberComparisonOperatorsConstantConditionRule();
return new NumberComparisonOperatorsConstantConditionRule($this->treatPhpDocTypesAsCertain);
}

public function testBug8277(): void
Expand Down Expand Up @@ -160,4 +162,37 @@ public function testBug8643(): void
$this->analyse([__DIR__ . '/data/bug-8643.php'], []);
}

public function dataTreatPhpDocTypesAsCertain(): iterable
{
yield [
false,
[],
];
yield [
true,
[
[
'Comparison operation ">=" between int<1, max> and 0 is always true.',
11,
'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%</>.',
],
[
'Comparison operation "<" between int<1, max> and 0 is always false.',
18,
'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%</>.',
],
],
];
}

/**
* @dataProvider dataTreatPhpDocTypesAsCertain
* @param list<array{0: string, 1: int, 2?: string}> $expectedErrors
*/
public function testTreatPhpDocTypesAsCertain(bool $treatPhpDocTypesAsCertain, array $expectedErrors): void
{
$this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain;
$this->analyse([__DIR__ . '/data/number-comparison-treat.php'], $expectedErrors);
}

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

namespace NumberComparisonTreatPhpDocTypesAsCertain;

class Foo
{

/** @param positive-int $i */
public function sayHello(int $i): void
{
if ($i >= 0) {
}
}

/** @param positive-int $i */
public function sayHello2(int $i): void
{
if ($i < 0) {
}
}

}

0 comments on commit 649eb70

Please sign in to comment.