Skip to content

Commit 59bd8eb

Browse files
committed
allows() support
1 parent e96b147 commit 59bd8eb

7 files changed

+198
-0
lines changed

extension.neon

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
11
services:
2+
-
3+
class: PHPStan\Mockery\Reflection\AllowsMethodsClassReflectionExtension
4+
tags:
5+
- phpstan.broker.methodsClassReflectionExtension
6+
7+
-
8+
class: PHPStan\Mockery\Type\AllowsDynamicReturnTypeExtension
9+
tags:
10+
- phpstan.broker.dynamicMethodReturnTypeExtension
11+
12+
-
13+
class: PHPStan\Mockery\Type\ExpectationAfterAllowsDynamicReturnTypeExtension
14+
tags:
15+
- phpstan.broker.dynamicMethodReturnTypeExtension
16+
217
-
318
class: PHPStan\Mockery\Type\MockDynamicReturnTypeExtension
419
tags:
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Mockery\Reflection;
4+
5+
use PHPStan\Reflection\ClassMemberReflection;
6+
use PHPStan\Reflection\ClassReflection;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Reflection\TrivialParametersAcceptor;
9+
10+
class AllowsMethodReflection implements MethodReflection
11+
{
12+
13+
/** @var ClassReflection */
14+
private $declaringClass;
15+
16+
/** @var string */
17+
private $name;
18+
19+
public function __construct(ClassReflection $declaringClass, string $name)
20+
{
21+
$this->declaringClass = $declaringClass;
22+
$this->name = $name;
23+
}
24+
25+
public function getDeclaringClass(): ClassReflection
26+
{
27+
return $this->declaringClass;
28+
}
29+
30+
public function isStatic(): bool
31+
{
32+
return false;
33+
}
34+
35+
public function isPrivate(): bool
36+
{
37+
return false;
38+
}
39+
40+
public function isPublic(): bool
41+
{
42+
return true;
43+
}
44+
45+
public function getName(): string
46+
{
47+
return $this->name;
48+
}
49+
50+
public function getPrototype(): ClassMemberReflection
51+
{
52+
return $this;
53+
}
54+
55+
/**
56+
* @return \PHPStan\Reflection\ParametersAcceptor[]
57+
*/
58+
public function getVariants(): array
59+
{
60+
return [
61+
new TrivialParametersAcceptor(),
62+
];
63+
}
64+
65+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Mockery\Reflection;
4+
5+
use PHPStan\Mockery\Type\Allows;
6+
use PHPStan\Reflection\ClassReflection;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Reflection\MethodsClassReflectionExtension;
9+
10+
class AllowsMethodsClassReflectionExtension implements MethodsClassReflectionExtension
11+
{
12+
13+
public function hasMethod(ClassReflection $classReflection, string $methodName): bool
14+
{
15+
return $classReflection->getName() === Allows::class;
16+
}
17+
18+
public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection
19+
{
20+
return new AllowsMethodReflection($classReflection, $methodName);
21+
}
22+
23+
}

src/Mockery/Type/Allows.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Mockery\Type;
4+
5+
interface Allows
6+
{
7+
8+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Mockery\Type;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Reflection\ParametersAcceptorSelector;
9+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
10+
use PHPStan\Type\IntersectionType;
11+
use PHPStan\Type\ObjectType;
12+
use PHPStan\Type\Type;
13+
use PHPStan\Type\TypeCombinator;
14+
use PHPStan\Type\TypeWithClassName;
15+
16+
class AllowsDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
17+
{
18+
19+
public function getClass(): string
20+
{
21+
return \Mockery\MockInterface::class;
22+
}
23+
24+
public function isMethodSupported(MethodReflection $methodReflection): bool
25+
{
26+
return $methodReflection->getName() === 'allows';
27+
}
28+
29+
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
30+
{
31+
$calledOnType = $scope->getType($methodCall->var);
32+
$defaultType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
33+
if (!$calledOnType instanceof IntersectionType || count($calledOnType->getTypes()) !== 2) {
34+
return $defaultType;
35+
}
36+
$mockedType = $calledOnType->getTypes()[1];
37+
if (!$mockedType instanceof TypeWithClassName) {
38+
return $defaultType;
39+
}
40+
41+
return TypeCombinator::intersect(
42+
new AllowsObjectType($mockedType->getClassName()),
43+
new ObjectType(Allows::class)
44+
);
45+
}
46+
47+
}

src/Mockery/Type/AllowsObjectType.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Mockery\Type;
4+
5+
use PHPStan\Type\ObjectType;
6+
7+
class AllowsObjectType extends ObjectType
8+
{
9+
10+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Mockery\Type;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
9+
use PHPStan\Type\ObjectType;
10+
use PHPStan\Type\Type;
11+
12+
class ExpectationAfterAllowsDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
13+
{
14+
15+
public function getClass(): string
16+
{
17+
return Allows::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+
return new ObjectType(\Mockery\CompositeExpectation::class);
28+
}
29+
30+
}

0 commit comments

Comments
 (0)