Skip to content

Commit 35b9a65

Browse files
committed
Support MockBuilder
1 parent 17ad5dc commit 35b9a65

4 files changed

+136
-0
lines changed

extension.neon

+8
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,11 @@ services:
1010
class: PHPStan\Type\PHPUnit\CreateMockDynamicReturnTypeExtension
1111
tags:
1212
- phpstan.broker.dynamicMethodReturnTypeExtension
13+
-
14+
class: PHPStan\Type\PHPUnit\GetMockBuilderDynamicReturnTypeExtension
15+
tags:
16+
- phpstan.broker.dynamicMethodReturnTypeExtension
17+
-
18+
class: PHPStan\Type\PHPUnit\MockBuilderDynamicReturnTypeExtension
19+
tags:
20+
- phpstan.broker.dynamicMethodReturnTypeExtension
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\PHPUnit;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Type\Type;
9+
10+
class GetMockBuilderDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension
11+
{
12+
13+
public static function getClass(): string
14+
{
15+
return \PHPUnit\Framework\TestCase::class;
16+
}
17+
18+
public function isMethodSupported(MethodReflection $methodReflection): bool
19+
{
20+
return $methodReflection->getName() === 'getMockBuilder';
21+
}
22+
23+
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
24+
{
25+
if (count($methodCall->args) === 0) {
26+
return $methodReflection->getReturnType();
27+
}
28+
$arg = $methodCall->args[0]->value;
29+
if (!($arg instanceof \PhpParser\Node\Expr\ClassConstFetch)) {
30+
return $methodReflection->getReturnType();
31+
}
32+
33+
$class = $arg->class;
34+
if (!($class instanceof \PhpParser\Node\Name)) {
35+
return $methodReflection->getReturnType();
36+
}
37+
38+
$class = (string) $class;
39+
if ($class === 'static') {
40+
return $methodReflection->getReturnType();
41+
}
42+
43+
if ($class === 'self') {
44+
$class = $scope->getClassReflection()->getName();
45+
}
46+
47+
return new MockBuilderType($class);
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\PHPUnit;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Type\ObjectType;
9+
use PHPStan\Type\Type;
10+
use PHPStan\Type\TypeCombinator;
11+
12+
class MockBuilderDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension
13+
{
14+
15+
public static function getClass(): string
16+
{
17+
return \PHPUnit_Framework_MockObject_MockBuilder::class;
18+
}
19+
20+
public function isMethodSupported(MethodReflection $methodReflection): bool
21+
{
22+
return true;
23+
}
24+
25+
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
26+
{
27+
$calledOnType = $scope->getType($methodCall->var);
28+
if (!in_array(
29+
$methodReflection->getName(),
30+
[
31+
'getMock',
32+
'getMockForAbstractClass',
33+
],
34+
true
35+
)) {
36+
return $calledOnType;
37+
}
38+
39+
if (!$calledOnType instanceof MockBuilderType) {
40+
return $methodReflection->getReturnType();
41+
}
42+
43+
$mockedClassType = new ObjectType($calledOnType->getMockedClass());
44+
$mockType = new ObjectType(\PHPUnit_Framework_MockObject_MockObject::class);
45+
46+
return TypeCombinator::intersect($mockedClassType, $mockType);
47+
}
48+
49+
}

src/Type/PHPUnit/MockBuilderType.php

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\PHPUnit;
4+
5+
class MockBuilderType extends \PHPStan\Type\ObjectType
6+
{
7+
8+
/**
9+
* @var string
10+
*/
11+
private $mockedClass;
12+
13+
public function __construct(string $mockedClass)
14+
{
15+
parent::__construct(\PHPUnit_Framework_MockObject_MockBuilder::class);
16+
$this->mockedClass = $mockedClass;
17+
}
18+
19+
public function getMockedClass(): string
20+
{
21+
return $this->mockedClass;
22+
}
23+
24+
public function describe(): string
25+
{
26+
return sprintf('%s<%s>', parent::describe(), $this->mockedClass);
27+
}
28+
29+
}

0 commit comments

Comments
 (0)