mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 04:45:20 +01:00
Merge pull request #8585 from gphargreaves/#8315/concat-non-empty-strings
Add additional checks for concat of non-empty strings to return non-falsy
This commit is contained in:
commit
dbb8815813
@ -199,6 +199,14 @@ class ConcatAnalyzer
|
||||
$numeric_type
|
||||
);
|
||||
|
||||
$right_is_numeric = UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
$right_type,
|
||||
$numeric_type
|
||||
);
|
||||
|
||||
$has_numeric_type = $left_is_numeric || $right_is_numeric;
|
||||
|
||||
if ($left_is_numeric) {
|
||||
$right_uint = Type::getPositiveInt();
|
||||
$right_uint->addType(new TLiteralInt(0));
|
||||
@ -230,16 +238,23 @@ class ConcatAnalyzer
|
||||
$non_empty_string = clone $numeric_type;
|
||||
$non_empty_string->addType(new TNonEmptyString());
|
||||
|
||||
$has_non_empty = UnionTypeComparator::isContainedBy(
|
||||
$left_non_empty = UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
$left_type,
|
||||
$non_empty_string
|
||||
) || UnionTypeComparator::isContainedBy(
|
||||
);
|
||||
|
||||
$right_non_empty = UnionTypeComparator::isContainedBy(
|
||||
$codebase,
|
||||
$right_type,
|
||||
$non_empty_string
|
||||
);
|
||||
|
||||
$has_non_empty = $left_non_empty || $right_non_empty;
|
||||
$all_non_empty = $left_non_empty && $right_non_empty;
|
||||
|
||||
$has_numeric_and_non_empty = $has_numeric_type && $has_non_empty;
|
||||
|
||||
$all_literals = $left_type->allLiterals() && $right_type->allLiterals();
|
||||
|
||||
if ($has_non_empty) {
|
||||
@ -248,7 +263,8 @@ class ConcatAnalyzer
|
||||
} elseif ($all_lowercase) {
|
||||
$result_type = Type::getNonEmptyLowercaseString();
|
||||
} else {
|
||||
$result_type = Type::getNonEmptyString();
|
||||
$result_type = $all_non_empty || $has_numeric_and_non_empty ?
|
||||
Type::getNonFalsyString() : Type::getNonEmptyString();
|
||||
}
|
||||
} else {
|
||||
if ($all_literals) {
|
||||
|
@ -34,6 +34,7 @@ use Psalm\Type\Atomic\TNever;
|
||||
use Psalm\Type\Atomic\TNonEmptyList;
|
||||
use Psalm\Type\Atomic\TNonEmptyLowercaseString;
|
||||
use Psalm\Type\Atomic\TNonEmptyString;
|
||||
use Psalm\Type\Atomic\TNonFalsyString;
|
||||
use Psalm\Type\Atomic\TNull;
|
||||
use Psalm\Type\Atomic\TNumeric;
|
||||
use Psalm\Type\Atomic\TNumericString;
|
||||
@ -219,6 +220,13 @@ abstract class Type
|
||||
return new Union([$type]);
|
||||
}
|
||||
|
||||
public static function getNonFalsyString(): Union
|
||||
{
|
||||
$type = new TNonFalsyString();
|
||||
|
||||
return new Union([$type]);
|
||||
}
|
||||
|
||||
public static function getNumeric(): Union
|
||||
{
|
||||
$type = new TNumeric;
|
||||
|
@ -830,6 +830,32 @@ class BinaryOperationTest extends TestCase
|
||||
return ($foo instanceof FooInterface ? $foo->toString() : null) ?? "Not a stringable foo";
|
||||
}',
|
||||
],
|
||||
'concatNonEmptyReturnNonFalsyString' => [
|
||||
'<?php
|
||||
/** @var non-empty-string $s1 */
|
||||
$s1 = "0";
|
||||
/** @var non-empty-string $s1 */
|
||||
$s2 = "0";
|
||||
|
||||
$a = $s1.$s2;',
|
||||
'assertions' => [
|
||||
'$a===' => 'non-falsy-string',
|
||||
],
|
||||
],
|
||||
'concatNumericWithNonEmptyReturnNonFalsyString' => [
|
||||
'<?php
|
||||
/** @var numeric-string $s1 */
|
||||
$s1 = "1";
|
||||
/** @var non-empty-string $s2 */
|
||||
$s2 = "0";
|
||||
|
||||
$a = $s1.$s2;
|
||||
$b = $s2.$s1;',
|
||||
'assertions' => [
|
||||
'$a===' => 'non-falsy-string',
|
||||
'$b===' => 'non-falsy-string',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user