From 152c644e1e629f2027010f0bfcfb5627e040824e Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Tue, 1 Feb 2022 09:10:42 +0100 Subject: [PATCH 1/2] Add dynamic return type to ResponseHeaderBag::getCookies --- extension.neon | 5 ++ ...nseHeaderBagDynamicReturnTypeExtension.php | 57 +++++++++++++++++++ tests/Type/Symfony/ExtensionTest.php | 1 + .../data/response_header_bag_get_cookies.php | 11 ++++ 4 files changed, 74 insertions(+) create mode 100644 src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php create mode 100644 tests/Type/Symfony/data/response_header_bag_get_cookies.php diff --git a/extension.neon b/extension.neon index 4870f24c..cd18f378 100644 --- a/extension.neon +++ b/extension.neon @@ -273,3 +273,8 @@ services: - factory: PHPStan\Type\Symfony\CommandGetHelperDynamicReturnTypeExtension tags: [phpstan.broker.dynamicMethodReturnTypeExtension] + + # ResponseHeaderBag::getCookies() return type + - + factory: PHPStan\Type\Symfony\ResponseHeaderBagDynamicReturnTypeExtension + tags: [phpstan.broker.dynamicMethodReturnTypeExtension] diff --git a/src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php b/src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php new file mode 100644 index 00000000..0a0a7f57 --- /dev/null +++ b/src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php @@ -0,0 +1,57 @@ +getName() === 'getCookies'; + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type + { + if (isset($methodCall->getArgs()[0])) { + $argStrings = TypeUtils::getConstantStrings($scope->getType($methodCall->getArgs()[0]->value)); + + if (count($argStrings) === 1 && $argStrings[0]->getValue() === ResponseHeaderBag::COOKIES_ARRAY) { + return new ArrayType( + new StringType(), + new ArrayType( + new StringType(), + new ArrayType( + new StringType(), + new ObjectType(Cookie::class) + ) + ) + ); + } + } + + return new ArrayType(new IntegerType(), new ObjectType(Cookie::class)); + } + +} diff --git a/tests/Type/Symfony/ExtensionTest.php b/tests/Type/Symfony/ExtensionTest.php index 5da566b1..c0aa7f94 100644 --- a/tests/Type/Symfony/ExtensionTest.php +++ b/tests/Type/Symfony/ExtensionTest.php @@ -14,6 +14,7 @@ public function dataFileAsserts(): iterable { yield from $this->gatherAssertTypes(__DIR__ . '/data/envelope_all.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/header_bag_get.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/response_header_bag_get_cookies.php'); if (class_exists('Symfony\Component\HttpFoundation\InputBag')) { yield from $this->gatherAssertTypes(__DIR__ . '/data/input_bag.php'); diff --git a/tests/Type/Symfony/data/response_header_bag_get_cookies.php b/tests/Type/Symfony/data/response_header_bag_get_cookies.php new file mode 100644 index 00000000..c9d1df6f --- /dev/null +++ b/tests/Type/Symfony/data/response_header_bag_get_cookies.php @@ -0,0 +1,11 @@ +setCookie(Cookie::create('cookie_name')); + +assertType('array', $headerBag->getCookies()); +assertType('array>>', $headerBag->getCookies(ResponseHeaderBag::COOKIES_ARRAY)); From 6775797b4820e669fa7afc3ac86d27b5e5ee159d Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Tue, 1 Feb 2022 11:21:19 +0100 Subject: [PATCH 2/2] Use ClassConstFetch --- ...ResponseHeaderBagDynamicReturnTypeExtension.php | 14 +++++++++++--- .../data/response_header_bag_get_cookies.php | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php b/src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php index 0a0a7f57..a659c684 100644 --- a/src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php +++ b/src/Type/Symfony/ResponseHeaderBagDynamicReturnTypeExtension.php @@ -2,7 +2,10 @@ namespace PHPStan\Type\Symfony; +use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Type\ArrayType; @@ -11,7 +14,6 @@ use PHPStan\Type\ObjectType; use PHPStan\Type\StringType; use PHPStan\Type\Type; -use PHPStan\Type\TypeUtils; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\ResponseHeaderBag; @@ -35,9 +37,15 @@ public function getTypeFromMethodCall( ): Type { if (isset($methodCall->getArgs()[0])) { - $argStrings = TypeUtils::getConstantStrings($scope->getType($methodCall->getArgs()[0]->value)); + $node = $methodCall->getArgs()[0]->value; - if (count($argStrings) === 1 && $argStrings[0]->getValue() === ResponseHeaderBag::COOKIES_ARRAY) { + if ( + $node instanceof ClassConstFetch && + $node->class instanceof Name && + $node->name instanceof Identifier && + $node->class->toString() === ResponseHeaderBag::class && + $node->name->name === 'COOKIES_ARRAY' + ) { return new ArrayType( new StringType(), new ArrayType( diff --git a/tests/Type/Symfony/data/response_header_bag_get_cookies.php b/tests/Type/Symfony/data/response_header_bag_get_cookies.php index c9d1df6f..f07d5e5b 100644 --- a/tests/Type/Symfony/data/response_header_bag_get_cookies.php +++ b/tests/Type/Symfony/data/response_header_bag_get_cookies.php @@ -8,4 +8,5 @@ $headerBag->setCookie(Cookie::create('cookie_name')); assertType('array', $headerBag->getCookies()); +assertType('array', $headerBag->getCookies(ResponseHeaderBag::COOKIES_FLAT)); assertType('array>>', $headerBag->getCookies(ResponseHeaderBag::COOKIES_ARRAY));

AltStyle によって変換されたページ (->オリジナル) /