Skip to content

Commit e2503c4

Browse files
committed
Dynamic return type extension for getComponent
1 parent 8f9a91e commit e2503c4

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"require": {
88
"php": "~7.0",
99
"phpstan/phpstan": "^0.6",
10+
"nette/component-model": "^2.3.0",
1011
"nette/utils": "^2.3.0"
1112
},
1213
"require-dev": {

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ services:
2323
class: PHPStan\Reflection\Nette\SmartObjectPropertiesClassReflectionExtension
2424
tags:
2525
- phpstan.broker.propertiesClassReflectionExtension
26+
27+
-
28+
class: PHPStan\Type\Nette\ComponentModelDynamicReturnTypeExtension
29+
tags:
30+
- phpstan.broker.dynamicMethodReturnTypeExtension
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Nette;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\BrokerAwareClassReflectionExtension;
8+
use PHPStan\Reflection\MethodReflection;
9+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
10+
use PHPStan\Type\MixedType;
11+
use PHPStan\Type\Type;
12+
13+
class ComponentModelDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension, BrokerAwareClassReflectionExtension
14+
{
15+
16+
/** @var \PHPStan\Broker\Broker */
17+
private $broker;
18+
19+
public function setBroker(\PHPStan\Broker\Broker $broker)
20+
{
21+
$this->broker = $broker;
22+
}
23+
24+
public static function getClass(): string
25+
{
26+
return \Nette\ComponentModel\Container::class;
27+
}
28+
29+
public function isMethodSupported(
30+
MethodReflection $methodReflection
31+
): bool
32+
{
33+
return $methodReflection->getName() === 'getComponent';
34+
}
35+
36+
public function getTypeFromMethodCall(
37+
MethodReflection $methodReflection,
38+
MethodCall $methodCall,
39+
Scope $scope
40+
): Type
41+
{
42+
$calledOnType = $scope->getType($methodCall->var);
43+
$mixedType = new MixedType();
44+
if ($calledOnType->getClass() === null || !$this->broker->hasClass($calledOnType->getClass())) {
45+
return $mixedType;
46+
}
47+
48+
$args = $methodCall->args;
49+
if (count($args) !== 1) {
50+
return $mixedType;
51+
}
52+
53+
$arg = $args[0]->value;
54+
if (!$arg instanceof \PhpParser\Node\Scalar\String_) {
55+
return $mixedType;
56+
}
57+
58+
$componentName = $arg->value;
59+
60+
$class = $this->broker->getClass($calledOnType->getClass());
61+
$methodName = sprintf('createComponent%s', ucfirst($componentName));
62+
if (!$class->hasMethod($methodName)) {
63+
return $mixedType;
64+
}
65+
66+
return $class->getMethod($methodName)->getReturnType();
67+
}
68+
69+
}

0 commit comments

Comments
 (0)