From a2bf5cb0546661bd8b058132b738a8798fc68959 Mon Sep 17 00:00:00 2001 From: kkmuffme <11071985+kkmuffme@users.noreply.github.com> Date: Sun, 17 Dec 2023 20:31:32 +0100 Subject: [PATCH 1/4] Fix empty literal string becomes non-empty-string when max literal string length is 0, which means literal strings are disabled --- src/Psalm/Type.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Psalm/Type.php b/src/Psalm/Type.php index 1215799f785..d05a9b9d5c3 100644 --- a/src/Psalm/Type.php +++ b/src/Psalm/Type.php @@ -287,7 +287,7 @@ public static function getAtomicStringFromLiteral(string $value, bool $from_docb $type = $config->eventDispatcher->dispatchStringInterpreter($event); if (!$type) { - if (strlen($value) < $config->max_string_length) { + if ($value === '' || strlen($value) < $config->max_string_length) { $type = new TLiteralString($value, $from_docblock); } else { $type = new TNonEmptyString($from_docblock); From 40926182604e32a97e0fd342c2ff6704b5c7dac8 Mon Sep 17 00:00:00 2001 From: kkmuffme <11071985+kkmuffme@users.noreply.github.com> Date: Wed, 20 Dec 2023 09:11:59 +0100 Subject: [PATCH 2/4] should be non-falsy-string instead of non-empty-string in most cases --- src/Psalm/Type.php | 6 ++++-- tests/TypeCombinationTest.php | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Psalm/Type.php b/src/Psalm/Type.php index d05a9b9d5c3..cc5de1f8b03 100644 --- a/src/Psalm/Type.php +++ b/src/Psalm/Type.php @@ -277,7 +277,7 @@ public static function getString(?string $value = null): Union return new Union([$value === null ? new TString() : self::getAtomicStringFromLiteral($value)]); } - /** @return TLiteralString|TNonEmptyString */ + /** @return TLiteralString|TNonEmptyString|TNonFalsyString */ public static function getAtomicStringFromLiteral(string $value, bool $from_docblock = false): TString { $config = Config::getInstance(); @@ -289,8 +289,10 @@ public static function getAtomicStringFromLiteral(string $value, bool $from_docb if (!$type) { if ($value === '' || strlen($value) < $config->max_string_length) { $type = new TLiteralString($value, $from_docblock); - } else { + } elseif ($value === '0') { $type = new TNonEmptyString($from_docblock); + } else { + $type = new TNonFalsyString($from_docblock); } } diff --git a/tests/TypeCombinationTest.php b/tests/TypeCombinationTest.php index b891e84dcc2..f041453d9d5 100644 --- a/tests/TypeCombinationTest.php +++ b/tests/TypeCombinationTest.php @@ -120,6 +120,13 @@ function takesLiteralString($arg) {} takesLiteralString($c); }', ], + 'tooLongLiteralShouldBeNonFalsyString' => [ + 'code' => ' [ + '$x===' => 'non-falsy-string', + ] + ], ]; } From 7f0f0bc36173909a333324cd1a4ce0f63e81ab75 Mon Sep 17 00:00:00 2001 From: kkmuffme <11071985+kkmuffme@users.noreply.github.com> Date: Wed, 20 Dec 2023 09:22:49 +0100 Subject: [PATCH 3/4] ensure concat https://psalm.dev/r/323e33ae8a will be a non-falsy-string --- .../Expression/BinaryOp/ConcatAnalyzer.php | 18 ++++++++++++++++-- tests/BinaryOperationTest.php | 9 +++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php index fd7ab531f3e..6a59185b55f 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ConcatAnalyzer.php @@ -258,6 +258,19 @@ public static function analyze( $has_numeric_and_non_empty = $has_numeric_type && $has_non_empty; + $non_falsy_string = $numeric_type->getBuilder()->addType(new TNonFalsyString())->freeze(); + $left_non_falsy = UnionTypeComparator::isContainedBy( + $codebase, + $left_type, + $non_falsy_string, + ); + + $right_non_falsy = UnionTypeComparator::isContainedBy( + $codebase, + $right_type, + $non_falsy_string, + ); + $all_literals = $left_type->allLiterals() && $right_type->allLiterals(); if ($has_non_empty) { @@ -265,9 +278,10 @@ public static function analyze( $result_type = new Union([new TNonEmptyNonspecificLiteralString]); } elseif ($all_lowercase) { $result_type = Type::getNonEmptyLowercaseString(); + } elseif ($all_non_empty || $has_numeric_and_non_empty || $left_non_falsy || $right_non_falsy) { + $result_type = Type::getNonFalsyString(); } else { - $result_type = $all_non_empty || $has_numeric_and_non_empty ? - Type::getNonFalsyString() : Type::getNonEmptyString(); + $result_type = Type::getNonEmptyString(); } } else { if ($all_literals) { diff --git a/tests/BinaryOperationTest.php b/tests/BinaryOperationTest.php index f0fe0c9e3ae..e2dafc18724 100644 --- a/tests/BinaryOperationTest.php +++ b/tests/BinaryOperationTest.php @@ -357,6 +357,15 @@ public function providerValidCodeParse(): iterable 'code' => ' [ + 'code' => ' [ + '$a===' => 'non-falsy-string', + ], + 'ignored_issues' => ['InvalidReturnType'], + ], 'concatenationWithNumberInWeakMode' => [ 'code' => ' Date: Sat, 13 Jan 2024 17:12:41 +0100 Subject: [PATCH 4/4] code style --- tests/TypeCombinationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TypeCombinationTest.php b/tests/TypeCombinationTest.php index f041453d9d5..56af82a69ed 100644 --- a/tests/TypeCombinationTest.php +++ b/tests/TypeCombinationTest.php @@ -125,7 +125,7 @@ function takesLiteralString($arg) {} $x = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";', 'assertions' => [ '$x===' => 'non-falsy-string', - ] + ], ], ]; }