diff --git a/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php b/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php index b4d09082..9ce33420 100644 --- a/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php +++ b/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php @@ -33,7 +33,6 @@ function it_forces_class_to_implement_ProphecySubjectInterface(ClassNode $node) $node->getMethods()->willReturn(array()); $node->hasMethod(Argument::any())->willReturn(false); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); - $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); $this->apply($node); } @@ -50,7 +49,6 @@ function it_forces_all_class_methods_except_constructor_to_proxy_calls_into_prop $node->addProperty('objectProphecyClosure', 'private')->willReturn(null); $node->hasMethod(Argument::any())->willReturn(false); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); - $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); $constructor->getName()->willReturn('__construct'); $method1->getName()->willReturn('method1'); @@ -58,6 +56,11 @@ function it_forces_all_class_methods_except_constructor_to_proxy_calls_into_prop $method3->getName()->willReturn('method3'); $method4->getName()->willReturn('method4'); + $method1->isStatic()->willReturn(false); + $method2->isStatic()->willReturn(false); + $method3->isStatic()->willReturn(false); + $method4->isStatic()->willReturn(false); + $method1->getReturnTypeNode()->willReturn(new ReturnTypeNode('int')); $method2->getReturnTypeNode()->willReturn(new ReturnTypeNode('int')); $method3->getReturnTypeNode()->willReturn(new ReturnTypeNode('void')); @@ -83,4 +86,49 @@ function it_forces_all_class_methods_except_constructor_to_proxy_calls_into_prop $this->apply($node); } + + function it_returns_the_object_when_not_static_and_return_type_is_self_or_static( + ClassNode $node, + MethodNode $method1, + MethodNode $method2, + MethodNode $method3, + MethodNode $method4 + ) { + $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface')->willReturn(null); + $node->addProperty('objectProphecyClosure', 'private')->willReturn(null); + $node->hasMethod(Argument::any())->willReturn(false); + $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); + + $method1->getName()->willReturn('method1'); + $method2->getName()->willReturn('method2'); + $method3->getName()->willReturn('method3'); + $method4->getName()->willReturn('method4'); + + $method1->isStatic()->willReturn(false); + $method2->isStatic()->willReturn(false); + $method3->isStatic()->willReturn(true); + $method4->isStatic()->willReturn(true); + + $method1->getReturnTypeNode()->willReturn(new ReturnTypeNode('self')); + $method2->getReturnTypeNode()->willReturn(new ReturnTypeNode('static')); + $method3->getReturnTypeNode()->willReturn(new ReturnTypeNode('self')); + $method4->getReturnTypeNode()->willReturn(new ReturnTypeNode('static')); + $node->getMethods()->willReturn(array( + 'method1' => $method1, + 'method2' => $method2, + 'method3' => $method3, + 'method4' => $method4, + )); + + $method1->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args()) ?? $this;') + ->shouldBeCalled(); + $method2->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args()) ?? $this;') + ->shouldBeCalled(); + $method3->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());') + ->shouldBeCalled(); + $method4->setCode('return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());') + ->shouldBeCalled(); + + $this->apply($node); + } } diff --git a/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php b/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php index b1ae8268..39125774 100644 --- a/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php +++ b/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php @@ -56,6 +56,10 @@ public function apply(ClassNode $node) $method->setCode( '$this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());' ); + } elseif (!$method->isStatic() && $method->getReturnTypeNode()->isSelfOrStatic()) { + $method->setCode( + 'return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args()) ?? $this;' + ); } else { $method->setCode( 'return $this->getProphecy()->makeProphecyMethodCall(__FUNCTION__, func_get_args());' diff --git a/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php b/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php index a731c9a2..fde5e410 100644 --- a/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php +++ b/src/Prophecy/Doubler/Generator/Node/ReturnTypeNode.php @@ -44,4 +44,10 @@ public function hasReturnStatement(): bool return $this->types !== ['void' => 'void'] && $this->types !== ['never' => 'never']; } + + public function isSelfOrStatic(): bool + { + return $this->types === ['self' => 'self'] + || $this->types === ['static' => 'static']; + } }