Skip to content

Commit

Permalink
Merge pull request #10722 from kkmuffme/fix-uppercase-non-empty-lower…
Browse files Browse the repository at this point in the history
…case-and-falsy-in-loop
  • Loading branch information
weirdan committed Feb 20, 2024
2 parents 6129891 + 4ac1872 commit 503ccd8
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 6 deletions.
52 changes: 47 additions & 5 deletions src/Psalm/Internal/Type/TypeCombiner.php
Expand Up @@ -1047,12 +1047,19 @@ private static function scrapeStringProperties(
&& strtolower($type->value) === $type->value
) {
// do nothing
} elseif (isset($combination->value_types['string'])
&& $combination->value_types['string'] instanceof TNonFalsyString
&& $type->value
) {
// do nothing
} elseif (isset($combination->value_types['string'])
&& $combination->value_types['string'] instanceof TNonFalsyString
&& $type->value === '0'
) {
$combination->value_types['string'] = new TNonEmptyString();
} elseif (isset($combination->value_types['string'])
&& $combination->value_types['string'] instanceof TNonEmptyString
&& ($combination->value_types['string'] instanceof TNonFalsyString
? $type->value
: $type->value !== ''
)
&& $type->value !== ''
) {
// do nothing
} else {
Expand Down Expand Up @@ -1103,18 +1110,53 @@ private static function scrapeStringProperties(
} else {
$combination->value_types['string'] = $type;
}
} elseif ($type instanceof TNonFalsyString) {
$has_empty_string = false;
$has_falsy_string = false;

foreach ($combination->strings as $string_type) {
if ($string_type->value === '') {
$has_empty_string = true;
$has_falsy_string = true;
break;
}

if ($string_type->value === '0') {
$has_falsy_string = true;
}
}

if ($has_empty_string) {
$combination->value_types['string'] = new TString();
} elseif ($has_falsy_string) {
$combination->value_types['string'] = new TNonEmptyString();
} else {
$combination->value_types['string'] = $type;
}
} elseif ($type instanceof TNonEmptyString) {
$has_empty_string = false;

foreach ($combination->strings as $string_type) {
if (!$string_type->value) {
if ($string_type->value === '') {
$has_empty_string = true;
break;
}
}

$has_non_lowercase_string = false;
if ($type instanceof TNonEmptyLowercaseString) {
foreach ($combination->strings as $string_type) {
if (strtolower($string_type->value) !== $string_type->value) {
$has_non_lowercase_string = true;
break;
}
}
}

if ($has_empty_string) {
$combination->value_types['string'] = new TString();
} elseif ($has_non_lowercase_string && get_class($type) !== TNonEmptyString::class) {
$combination->value_types['string'] = new TNonEmptyString();
} else {
$combination->value_types['string'] = $type;
}
Expand Down
36 changes: 35 additions & 1 deletion tests/TypeCombinationTest.php
Expand Up @@ -127,6 +127,40 @@ function takesLiteralString($arg) {}
'$x===' => 'non-falsy-string',
],
],
'loopNonFalsyWithZeroShouldBeNonEmpty' => [
'code' => '<?php
/**
* @psalm-suppress InvalidReturnType
* @return string[]
*/
function getStringArray() {}
$x = array();
foreach (getStringArray() as $id) {
$x[] = "0";
$x[] = "some_" . $id;
}',
'assertions' => [
'$x===' => 'list<non-empty-string>',
],
],
'loopNonLowercaseLiteralWithNonEmptyLowercaseShouldBeNonEmptyAndNotLowercase' => [
'code' => '<?php
/**
* @psalm-suppress InvalidReturnType
* @return int[]
*/
function getIntArray() {}
$x = array();
foreach (getIntArray() as $id) {
$x[] = "TEXT";
$x[] = "some_" . $id;
}',
'assertions' => [
'$x===' => 'list<non-empty-string>',
],
],
];
}

Expand Down Expand Up @@ -900,7 +934,7 @@ public function providerTestValidTypeCombination(): array
],
],
'nonFalsyStringAndFalsyLiteral' => [
'string',
'non-empty-string',
[
'non-falsy-string',
'"0"',
Expand Down

0 comments on commit 503ccd8

Please sign in to comment.