Skip to content

Commit c66d80c

Browse files
committed
Get the right component type with array access
1 parent 1a8acd1 commit c66d80c

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
},
1212
"require": {
1313
"php": "~7.1",
14-
"phpstan/phpstan": "^0.10",
14+
"phpstan/phpstan": "^0.10.2",
1515
"nikic/php-parser": "^4.0"
1616
},
1717
"require-dev": {

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ services:
2828
- phpstan.broker.propertiesClassReflectionExtension
2929
- phpstan.broker.methodsClassReflectionExtension
3030

31+
-
32+
class: PHPStan\Type\Nette\ComponentModelArrayAccessDynamicReturnTypeExtension
33+
tags:
34+
- phpstan.broker.dynamicMethodReturnTypeExtension
35+
3136
-
3237
class: PHPStan\Type\Nette\ComponentModelDynamicReturnTypeExtension
3338
tags:
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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\MethodReflection;
8+
use PHPStan\Reflection\ParametersAcceptorSelector;
9+
use PHPStan\Type\Constant\ConstantStringType;
10+
use PHPStan\Type\DynamicMethodReturnTypeExtension;
11+
use PHPStan\Type\MixedType;
12+
use PHPStan\Type\Type;
13+
14+
class ComponentModelArrayAccessDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
15+
{
16+
17+
public function getClass(): string
18+
{
19+
return 'Nette\Application\UI\Component';
20+
}
21+
22+
public function isMethodSupported(
23+
MethodReflection $methodReflection
24+
): bool
25+
{
26+
return $methodReflection->getName() === 'offsetGet';
27+
}
28+
29+
public function getTypeFromMethodCall(
30+
MethodReflection $methodReflection,
31+
MethodCall $methodCall,
32+
Scope $scope
33+
): Type
34+
{
35+
$calledOnType = $scope->getType($methodCall->var);
36+
$mixedType = new MixedType();
37+
$args = $methodCall->args;
38+
if (count($args) !== 1) {
39+
return $mixedType;
40+
}
41+
42+
$argType = $scope->getType($args[0]->value);
43+
if (!$argType instanceof ConstantStringType) {
44+
return $mixedType;
45+
}
46+
47+
$componentName = $argType->getValue();
48+
49+
$methodName = sprintf('createComponent%s', ucfirst($componentName));
50+
if (!$calledOnType->hasMethod($methodName)) {
51+
return $mixedType;
52+
}
53+
54+
$method = $calledOnType->getMethod($methodName, $scope);
55+
56+
return ParametersAcceptorSelector::selectSingle($method->getVariants())->getReturnType();
57+
}
58+
59+
}

0 commit comments

Comments
 (0)