From 0cdf661f174c800c4c8008c2e4454316395ffad2 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Wed, 29 Nov 2017 16:18:39 +0100 Subject: [PATCH 1/4] Implement classes for Prophecy --- ...jectProphecyDynamicReturnTypeExtension.php | 32 ++++++++++++ src/Type/Prophecy/ObjectProphecyType.php | 31 ++++++++++++ .../ProphetDynamicReturnTypeExtension.php | 50 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php create mode 100644 src/Type/Prophecy/ObjectProphecyType.php create mode 100644 src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php diff --git a/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php b/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php new file mode 100644 index 0000000..43b6025 --- /dev/null +++ b/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php @@ -0,0 +1,32 @@ +getName() === 'reveal') { + return $scope->getType($methodCall->var); + } + + return $methodReflection->getReturnType(); + } + +} diff --git a/src/Type/Prophecy/ObjectProphecyType.php b/src/Type/Prophecy/ObjectProphecyType.php new file mode 100644 index 0000000..f607747 --- /dev/null +++ b/src/Type/Prophecy/ObjectProphecyType.php @@ -0,0 +1,31 @@ +mockedClass = $mockedClass; + } + + public function getMockedClass(): string + { + return $this->mockedClass; + } + + public function describe(): string + { + return sprintf('%s<%s>', parent::describe(), $this->mockedClass); + } + +} diff --git a/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php b/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php new file mode 100644 index 0000000..a2449ea --- /dev/null +++ b/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php @@ -0,0 +1,50 @@ +getName() === 'prophesize'; + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + { + if (count($methodCall->args) === 0) { + return $methodReflection->getReturnType(); + } + $arg = $methodCall->args[0]->value; + if (!($arg instanceof \PhpParser\Node\Expr\ClassConstFetch)) { + return $methodReflection->getReturnType(); + } + + $class = $arg->class; + if (!($class instanceof \PhpParser\Node\Name)) { + return $methodReflection->getReturnType(); + } + + $class = (string) $class; + if ($class === 'static') { + return $methodReflection->getReturnType(); + } + + if ($class === 'self') { + $class = $scope->getClassReflection()->getName(); + } + + return new ObjectProphecyType($class); + } + +} From 4ef610a15a9d50fab4d458d7d1c7a6a7f9c57e1d Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Wed, 29 Nov 2017 16:20:29 +0100 Subject: [PATCH 2/4] Add dynamic extensions to the config --- extension.neon | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extension.neon b/extension.neon index f3a1e35..d26555d 100644 --- a/extension.neon +++ b/extension.neon @@ -18,3 +18,11 @@ services: class: PHPStan\Type\PHPUnit\MockBuilderDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Type\Prophecy\ProphetDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Type\Prophecy\ObjectProphecyDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension From 1e7f01dfcaa508c4dfb28d83b44495b229b5f090 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Thu, 30 Nov 2017 09:12:35 +0100 Subject: [PATCH 3/4] Fix getClass methods --- src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php | 3 ++- src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php b/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php index 43b6025..9e4277c 100644 --- a/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php +++ b/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php @@ -6,13 +6,14 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Type\Type; +use Prophecy\Prophecy\ObjectProphecy; class ObjectProphecyDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension { public function getClass(): string { - return \PHPUnit_Framework_MockObject_MockBuilder::class; + return ObjectProphecy::class; } public function isMethodSupported(MethodReflection $methodReflection): bool diff --git a/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php b/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php index a2449ea..41e80f7 100644 --- a/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php +++ b/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php @@ -6,13 +6,14 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Type\Type; +use Prophecy\Prophet; class ProphetDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension { public function getClass(): string { - return \PHPUnit_Framework_MockObject_MockBuilder::class; + return Prophet::class; } public function isMethodSupported(MethodReflection $methodReflection): bool From e5446f835f72e513a53e9416633f1458d702089d Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Thu, 30 Nov 2017 09:37:20 +0100 Subject: [PATCH 4/4] Make prophesize->reveal sequence work --- .../Prophecy/ObjectProphecyDynamicReturnTypeExtension.php | 7 ++++++- src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php b/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php index 9e4277c..afd663d 100644 --- a/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php +++ b/src/Type/Prophecy/ObjectProphecyDynamicReturnTypeExtension.php @@ -5,6 +5,7 @@ use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; +use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use Prophecy\Prophecy\ObjectProphecy; @@ -24,7 +25,11 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { if ($methodReflection->getName() === 'reveal') { - return $scope->getType($methodCall->var); + $calledOnType = $scope->getType($methodCall->var); + + if ($calledOnType instanceof ObjectProphecyType) { + return new ObjectType($calledOnType->getMockedClass()); + } } return $methodReflection->getReturnType(); diff --git a/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php b/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php index 41e80f7..0a58022 100644 --- a/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php +++ b/src/Type/Prophecy/ProphetDynamicReturnTypeExtension.php @@ -6,14 +6,14 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\MethodReflection; use PHPStan\Type\Type; -use Prophecy\Prophet; +use PHPUnit\Framework\TestCase; class ProphetDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension { public function getClass(): string { - return Prophet::class; + return TestCase::class; } public function isMethodSupported(MethodReflection $methodReflection): bool