mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 13:51:54 +01:00
Fix RiskyTruthyFalsyComparison reporting irrelevant errors when there is no explicit truthy/falsy type
This commit is contained in:
parent
503ccd8235
commit
9d8080096c
@ -1,6 +1,6 @@
|
||||
# RiskyTruthyFalsyComparison
|
||||
|
||||
Emitted when comparing a value with multiple types that can both contain truthy and falsy values.
|
||||
Emitted when comparing a value with multiple types, where at least one type can be only truthy or falsy and other types can contain both truthy and falsy values.
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -22,7 +22,7 @@ function foo($arg) {
|
||||
|
||||
## Why this is bad
|
||||
|
||||
The truthy/falsy type of one variable is often forgotten and not handled explicitly causing hard to track down errors.
|
||||
The truthy/falsy type of a variable is often forgotten and not handled explicitly causing hard to track down errors.
|
||||
|
||||
## How to fix
|
||||
|
||||
|
@ -372,16 +372,18 @@ final class IfConditionalAnalyzer
|
||||
&& !($stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical)
|
||||
&& !($stmt instanceof PhpParser\Node\Expr\BooleanNot)) {
|
||||
if (count($type->getAtomicTypes()) > 1) {
|
||||
$has_truthy_or_falsy_exclusive_type = false;
|
||||
$both_types = $type->getBuilder();
|
||||
foreach ($both_types->getAtomicTypes() as $key => $atomic_type) {
|
||||
if ($atomic_type->isTruthy()
|
||||
|| $atomic_type->isFalsy()
|
||||
|| $atomic_type instanceof TBool) {
|
||||
$both_types->removeType($key);
|
||||
$has_truthy_or_falsy_exclusive_type = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($both_types->getAtomicTypes()) > 0) {
|
||||
if (count($both_types->getAtomicTypes()) > 0 && $has_truthy_or_falsy_exclusive_type) {
|
||||
$both_types = $both_types->freeze();
|
||||
IssueBuffer::maybeAdd(
|
||||
new RiskyTruthyFalsyComparison(
|
||||
|
@ -46,16 +46,18 @@ final class BooleanNotAnalyzer
|
||||
$stmt_type = new TTrue($expr_type->from_docblock);
|
||||
} else {
|
||||
if (count($expr_type->getAtomicTypes()) > 1) {
|
||||
$has_truthy_or_falsy_exclusive_type = false;
|
||||
$both_types = $expr_type->getBuilder();
|
||||
foreach ($both_types->getAtomicTypes() as $key => $atomic_type) {
|
||||
if ($atomic_type->isTruthy()
|
||||
|| $atomic_type->isFalsy()
|
||||
|| $atomic_type instanceof TBool) {
|
||||
$both_types->removeType($key);
|
||||
$has_truthy_or_falsy_exclusive_type = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($both_types->getAtomicTypes()) > 0) {
|
||||
if (count($both_types->getAtomicTypes()) > 0 && $has_truthy_or_falsy_exclusive_type) {
|
||||
$both_types = $both_types->freeze();
|
||||
IssueBuffer::maybeAdd(
|
||||
new RiskyTruthyFalsyComparison(
|
||||
|
@ -65,16 +65,18 @@ final class EmptyAnalyzer
|
||||
$stmt_type = new TTrue($expr_type->from_docblock);
|
||||
} else {
|
||||
if (count($expr_type->getAtomicTypes()) > 1) {
|
||||
$has_truthy_or_falsy_exclusive_type = false;
|
||||
$both_types = $expr_type->getBuilder();
|
||||
foreach ($both_types->getAtomicTypes() as $key => $atomic_type) {
|
||||
if ($atomic_type->isTruthy()
|
||||
|| $atomic_type->isFalsy()
|
||||
|| $atomic_type instanceof TBool) {
|
||||
$both_types->removeType($key);
|
||||
$has_truthy_or_falsy_exclusive_type = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($both_types->getAtomicTypes()) > 0) {
|
||||
if (count($both_types->getAtomicTypes()) > 0 && $has_truthy_or_falsy_exclusive_type) {
|
||||
$both_types = $both_types->freeze();
|
||||
IssueBuffer::maybeAdd(
|
||||
new RiskyTruthyFalsyComparison(
|
||||
|
@ -3153,6 +3153,25 @@ class ConditionalTest extends TestCase
|
||||
'$existing' => 'null|stdClass',
|
||||
],
|
||||
],
|
||||
'nonStrictConditionWithoutExclusiveTruthyFalsyFuncCallNegated' => [
|
||||
'code' => '<?php
|
||||
/**
|
||||
* @param array|null $arg
|
||||
* @return void
|
||||
*/
|
||||
function foo($arg) {
|
||||
if (!bar($arg)) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $arg
|
||||
* @return float|int
|
||||
*/
|
||||
function bar($arg) {}',
|
||||
'assertions' => [],
|
||||
'ignored_issues' => ['InvalidReturnType'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user