From 26358e086cde7d201c13ef0d3c5a279e0e6dc6de Mon Sep 17 00:00:00 2001 From: Marian <42134098+IanDelMar@users.noreply.github.com> Date: Fri, 28 Jun 2024 20:16:55 +0200 Subject: [PATCH 1/3] fix/update extension for wp_parse_url --- ...eUrlFunctionDynamicReturnTypeExtension.php | 83 +++++++++++-------- tests/data/wp_parse_url.php | 6 +- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/WpParseUrlFunctionDynamicReturnTypeExtension.php b/src/WpParseUrlFunctionDynamicReturnTypeExtension.php index 05214b18..86269499 100644 --- a/src/WpParseUrlFunctionDynamicReturnTypeExtension.php +++ b/src/WpParseUrlFunctionDynamicReturnTypeExtension.php @@ -19,7 +19,7 @@ use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; -use PHPStan\Type\IntegerType; +use PHPStan\Type\IntegerRangeType; use PHPStan\Type\NullType; use PHPStan\Type\StringType; use PHPStan\Type\Type; @@ -66,32 +66,42 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $this->cacheReturnTypes(); - $componentType = new ConstantIntegerType(-1); if (count($functionCall->getArgs()) > 1) { $componentType = $scope->getType($functionCall->getArgs()[1]->value); + if (! $componentType->isConstantValue()->yes()) { + return $this->createAllComponentsReturnType(); + } + + $componentType = $componentType->toInteger(); + if (! $componentType instanceof ConstantIntegerType) { return $this->createAllComponentsReturnType(); } + } else { + $componentType = new ConstantIntegerType(-1); } $urlType = $scope->getType($functionCall->getArgs()[0]->value); - if (count($urlType->getConstantStrings()) !== 0) { - $returnTypes = []; + if (count($urlType->getConstantStrings()) > 0) { + $types = []; foreach ($urlType->getConstantStrings() as $constantString) { try { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged $result = @parse_url($constantString->getValue(), $componentType->getValue()); - $returnTypes[] = $scope->getTypeFromValue($result); } catch (\ValueError $e) { - $returnTypes[] = new ConstantBooleanType(false); + $types[] = new ConstantBooleanType(false); + continue; } + + $types[] = $scope->getTypeFromValue($result); } - return TypeCombinator::union(...$returnTypes); + + return TypeCombinator::union(...$types); } if ($componentType->getValue() === -1) { - return $this->createAllComponentsReturnType(); + return TypeCombinator::union($this->createComponentsArray(), new ConstantBooleanType(false)); } return $this->componentTypesPairedConstants[$componentType->getValue()] ?? new ConstantBooleanType(false); @@ -102,24 +112,31 @@ private function createAllComponentsReturnType(): Type if ($this->allComponentsTogetherType === null) { $returnTypes = [ new ConstantBooleanType(false), + new NullType(), + IntegerRangeType::fromInterval(0, 65535), + new StringType(), + $this->createComponentsArray(), ]; - $builder = ConstantArrayTypeBuilder::createEmpty(); + $this->allComponentsTogetherType = TypeCombinator::union(...$returnTypes); + } - if ($this->componentTypesPairedStrings === null) { - throw new \PHPStan\ShouldNotHappenException(); - } + return $this->allComponentsTogetherType; + } - foreach ($this->componentTypesPairedStrings as $componentName => $componentValueType) { - $builder->setOffsetValueType(new ConstantStringType($componentName), $componentValueType, true); - } + private function createComponentsArray(): Type + { + $builder = ConstantArrayTypeBuilder::createEmpty(); - $returnTypes[] = $builder->getArray(); + if ($this->componentTypesPairedStrings === null) { + throw new \PHPStan\ShouldNotHappenException(); + } - $this->allComponentsTogetherType = TypeCombinator::union(...$returnTypes); + foreach ($this->componentTypesPairedStrings as $componentName => $componentValueType) { + $builder->setOffsetValueType(new ConstantStringType($componentName), $componentValueType, true); } - return $this->allComponentsTogetherType; + return $builder->getArray(); } private function cacheReturnTypes(): void @@ -128,18 +145,18 @@ private function cacheReturnTypes(): void return; } - $stringType = new StringType(); - $integerType = new IntegerType(); - $falseType = new ConstantBooleanType(false); - $nullType = new NullType(); + $string = new StringType(); + $port = IntegerRangeType::fromInterval(0, 65535); + $false = new ConstantBooleanType(false); + $null = new NullType(); - $stringOrFalseOrNull = TypeCombinator::union($stringType, $falseType, $nullType); - $integerOrFalseOrNull = TypeCombinator::union($integerType, $falseType, $nullType); + $stringOrFalseOrNull = TypeCombinator::union($string, $false, $null); + $portOrFalseOrNull = TypeCombinator::union($port, $false, $null); $this->componentTypesPairedConstants = [ PHP_URL_SCHEME => $stringOrFalseOrNull, PHP_URL_HOST => $stringOrFalseOrNull, - PHP_URL_PORT => $integerOrFalseOrNull, + PHP_URL_PORT => $portOrFalseOrNull, PHP_URL_USER => $stringOrFalseOrNull, PHP_URL_PASS => $stringOrFalseOrNull, PHP_URL_PATH => $stringOrFalseOrNull, @@ -148,14 +165,14 @@ private function cacheReturnTypes(): void ]; $this->componentTypesPairedStrings = [ - 'scheme' => $stringType, - 'host' => $stringType, - 'port' => $integerType, - 'user' => $stringType, - 'pass' => $stringType, - 'path' => $stringType, - 'query' => $stringType, - 'fragment' => $stringType, + 'scheme' => $string, + 'host' => $string, + 'port' => $port, + 'user' => $string, + 'pass' => $string, + 'path' => $string, + 'query' => $string, + 'fragment' => $string, ]; } } diff --git a/tests/data/wp_parse_url.php b/tests/data/wp_parse_url.php index 4ad14909..c05df9e9 100644 --- a/tests/data/wp_parse_url.php +++ b/tests/data/wp_parse_url.php @@ -30,7 +30,7 @@ assertType("array{scheme: 'http', host: 'def.abc'}", $value); $value = wp_parse_url('http://def.abc', $integer); -assertType('array{scheme?: string, host?: string, port?: int, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|false', $value); +assertType('array{scheme?: string, host?: string, port?: int<0, 65535>, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|int<0, 65535>|string|false|null', $value); $value = wp_parse_url('http://def.abc', PHP_URL_FRAGMENT); assertType('null', $value); @@ -45,10 +45,10 @@ assertType('false', $value); $value = wp_parse_url($string, PHP_URL_PORT); -assertType('int|false|null', $value); +assertType('int<0, 65535>|false|null', $value); $value = wp_parse_url($string); -assertType('array{scheme?: string, host?: string, port?: int, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|false', $value); +assertType('array{scheme?: string, host?: string, port?: int<0, 65535>, user?: string, pass?: string, path?: string, query?: string, fragment?: string}|false', $value); /** @var 'http://def.abc'|'https://example.com' $union */ $union = $union; From 1c3d429f332aa6d840f4f87e66eb234934e39735 Mon Sep 17 00:00:00 2001 From: Marian <42134098+IanDelMar@users.noreply.github.com> Date: Fri, 28 Jun 2024 20:38:53 +0200 Subject: [PATCH 2/3] rename variables with reserved names --- ...eUrlFunctionDynamicReturnTypeExtension.php | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/WpParseUrlFunctionDynamicReturnTypeExtension.php b/src/WpParseUrlFunctionDynamicReturnTypeExtension.php index 86269499..3ca82a2c 100644 --- a/src/WpParseUrlFunctionDynamicReturnTypeExtension.php +++ b/src/WpParseUrlFunctionDynamicReturnTypeExtension.php @@ -145,13 +145,13 @@ private function cacheReturnTypes(): void return; } - $string = new StringType(); + $stringType = new StringType(); $port = IntegerRangeType::fromInterval(0, 65535); - $false = new ConstantBooleanType(false); - $null = new NullType(); + $falseType = new ConstantBooleanType(false); + $nullType = new NullType(); - $stringOrFalseOrNull = TypeCombinator::union($string, $false, $null); - $portOrFalseOrNull = TypeCombinator::union($port, $false, $null); + $stringOrFalseOrNull = TypeCombinator::union($stringType, $falseType, $nullType); + $portOrFalseOrNull = TypeCombinator::union($port, $falseType, $nullType); $this->componentTypesPairedConstants = [ PHP_URL_SCHEME => $stringOrFalseOrNull, @@ -165,14 +165,14 @@ private function cacheReturnTypes(): void ]; $this->componentTypesPairedStrings = [ - 'scheme' => $string, - 'host' => $string, + 'scheme' => $stringType, + 'host' => $stringType, 'port' => $port, - 'user' => $string, - 'pass' => $string, - 'path' => $string, - 'query' => $string, - 'fragment' => $string, + 'user' => $stringType, + 'pass' => $stringType, + 'path' => $stringType, + 'query' => $stringType, + 'fragment' => $stringType, ]; } } From 2a284d842e378efcd3c90433c0a5eba47e4e3c08 Mon Sep 17 00:00:00 2001 From: Marian <42134098+IanDelMar@users.noreply.github.com> Date: Fri, 28 Jun 2024 20:55:03 +0200 Subject: [PATCH 3/3] remove else statement --- src/WpParseUrlFunctionDynamicReturnTypeExtension.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WpParseUrlFunctionDynamicReturnTypeExtension.php b/src/WpParseUrlFunctionDynamicReturnTypeExtension.php index 3ca82a2c..b998b9a4 100644 --- a/src/WpParseUrlFunctionDynamicReturnTypeExtension.php +++ b/src/WpParseUrlFunctionDynamicReturnTypeExtension.php @@ -66,6 +66,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $this->cacheReturnTypes(); + $componentType = new ConstantIntegerType(-1); + if (count($functionCall->getArgs()) > 1) { $componentType = $scope->getType($functionCall->getArgs()[1]->value); @@ -78,8 +80,6 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if (! $componentType instanceof ConstantIntegerType) { return $this->createAllComponentsReturnType(); } - } else { - $componentType = new ConstantIntegerType(-1); } $urlType = $scope->getType($functionCall->getArgs()[0]->value);