Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a0c1c7b

Browse files
committed
Support TreeBuilder::getRootNode()
1 parent 97a55aa commit a0c1c7b

File tree

7 files changed

+213
-0
lines changed

7 files changed

+213
-0
lines changed

‎composer.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"phpstan/phpstan-strict-rules": "^0.12.5",
2828
"phpunit/phpunit": "^7.5.20",
2929
"symfony/console": "^4.0",
30+
"symfony/config": "^4.2",
3031
"symfony/framework-bundle": "^4.0",
3132
"symfony/http-foundation": "^4.0",
3233
"symfony/messenger": "^4.2",

‎extension.neon‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,13 @@ services:
145145
-
146146
factory: PHPStan\Type\Symfony\InputInterfaceHasOptionDynamicReturnTypeExtension
147147
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
148+
149+
# new TreeBuilder() return type
150+
-
151+
factory: PHPStan\Type\Symfony\TreeBuilderDynamicReturnTypeExtension
152+
tags: [phpstan.broker.dynamicStaticMethodReturnTypeExtension]
153+
154+
# TreeBuilder::getRootNode() return type
155+
-
156+
factory: PHPStan\Type\Symfony\TreeBuilderGetRootNodeDynamicReturnTypeExtension
157+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use PhpParser\Node\Expr\StaticCall;
6+
use PhpParser\Node\Name;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Broker\Broker;
9+
use PHPStan\Reflection\BrokerAwareExtension;
10+
use PHPStan\Reflection\MethodReflection;
11+
use PHPStan\Reflection\ParametersAcceptorSelector;
12+
use PHPStan\Type\ConstantScalarType;
13+
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
14+
use PHPStan\Type\Type;
15+
16+
final class TreeBuilderDynamicReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension, BrokerAwareExtension
17+
{
18+
19+
/** @var Broker */
20+
private $broker;
21+
22+
public function setBroker(Broker $broker): void
23+
{
24+
$this->broker = $broker;
25+
}
26+
27+
public function getClass(): string
28+
{
29+
return 'Symfony\Component\Config\Definition\Builder\TreeBuilder';
30+
}
31+
32+
public function isStaticMethodSupported(MethodReflection $methodReflection): bool
33+
{
34+
return $methodReflection->getName() === '__construct';
35+
}
36+
37+
public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): Type
38+
{
39+
if (!$methodCall->class instanceof Name) {
40+
throw new \PHPStan\ShouldNotHappenException();
41+
}
42+
43+
$className = $scope->resolveName($methodCall->class);
44+
if (!$this->broker->hasClass($className)) {
45+
return ParametersAcceptorSelector::selectSingle(
46+
$methodReflection->getVariants()
47+
)->getReturnType();
48+
}
49+
50+
$args = [];
51+
foreach ($methodCall->args as $arg) {
52+
$value = $scope->getType($arg->value);
53+
54+
if (!$value instanceof ConstantScalarType) {
55+
throw new \LogicException();
56+
}
57+
58+
$args[] = $value->getValue();
59+
}
60+
61+
$treeBuilder = new $className(
62+
...$args
63+
);
64+
65+
return new TreeBuilderType($className, $treeBuilder->getRootNode());
66+
}
67+
68+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
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\Type;
10+
11+
final class TreeBuilderGetRootNodeDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
12+
{
13+
14+
public function getClass(): string
15+
{
16+
return 'Symfony\Component\Config\Definition\Builder\TreeBuilder';
17+
}
18+
19+
public function isMethodSupported(MethodReflection $methodReflection): bool
20+
{
21+
return $methodReflection->getName() === 'getRootNode';
22+
}
23+
24+
public function getTypeFromMethodCall(
25+
MethodReflection $methodReflection,
26+
MethodCall $methodCall,
27+
Scope $scope
28+
): Type
29+
{
30+
$calledOnType = $scope->getType($methodCall->var);
31+
if ($calledOnType instanceof TreeBuilderType) {
32+
$nodeDefinition = $calledOnType->getNodeDefinition();
33+
34+
return new \PHPStan\Type\ObjectType(get_class($nodeDefinition));
35+
}
36+
37+
return new \PHPStan\Type\ObjectType('Symfony\Component\Config\Definition\Builder\NodeDefinition');
38+
}
39+
40+
}

‎src/Type/Symfony/TreeBuilderType.php‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use PHPStan\Type\ObjectType;
6+
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
7+
8+
class TreeBuilderType extends ObjectType
9+
{
10+
11+
/** @var NodeDefinition */
12+
private $nodeDefinition;
13+
14+
public function __construct(string $className, NodeDefinition $nodeDefinition)
15+
{
16+
parent::__construct($className);
17+
18+
$this->nodeDefinition = $nodeDefinition;
19+
}
20+
21+
public function getNodeDefinition(): NodeDefinition
22+
{
23+
return $this->nodeDefinition;
24+
}
25+
26+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use Iterator;
6+
7+
final class TreeBuilderDynamicReturnTypeExtensionTest extends ExtensionTestCase
8+
{
9+
10+
/**
11+
* @dataProvider getProvider
12+
*/
13+
public function testGet(string $expression, string $type): void
14+
{
15+
$this->processFile(
16+
__DIR__ . '/tree_builder.php',
17+
$expression,
18+
$type,
19+
[new TreeBuilderGetRootNodeDynamicReturnTypeExtension()],
20+
[new TreeBuilderDynamicReturnTypeExtension()]
21+
);
22+
}
23+
24+
/**
25+
* @return \Iterator<array{string, string}>
26+
*/
27+
public function getProvider(): Iterator
28+
{
29+
yield ['$treeRootNode', 'Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition'];
30+
yield ['$variableRootNode', 'Symfony\Component\Config\Definition\Builder\VariableNodeDefinition'];
31+
yield ['$scalarRootNode', 'Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition'];
32+
yield ['$booleanRootNode', 'Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition'];
33+
yield ['$integerRootNode', 'Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition'];
34+
yield ['$floatRootNode', 'Symfony\Component\Config\Definition\Builder\FloatNodeDefinition'];
35+
yield ['$arrayRootNode', 'Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition'];
36+
yield ['$enumRootNode', 'Symfony\Component\Config\Definition\Builder\EnumNodeDefinition'];
37+
}
38+
39+
}

‎tests/Type/Symfony/tree_builder.php‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
4+
5+
$treeBuilder = new TreeBuilder('my_tree');
6+
$treeRootNode = $treeBuilder->getRootNode();
7+
8+
$variableTreeBuilder = new TreeBuilder('my_tree', 'variable');
9+
$variableRootNode = $variableTreeBuilder->getRootNode();
10+
11+
$scalarTreeBuilder = new TreeBuilder('my_tree', 'scalar');
12+
$scalarRootNode = $scalarTreeBuilder->getRootNode();
13+
14+
$booleanTreeBuilder = new TreeBuilder('my_tree', 'boolean');
15+
$booleanRootNode = $booleanTreeBuilder->getRootNode();
16+
17+
$integerTreeBuilder = new TreeBuilder('my_tree', 'integer');
18+
$integerRootNode = $integerTreeBuilder->getRootNode();
19+
20+
$floatTreeBuilder = new TreeBuilder('my_tree', 'float');
21+
$floatRootNode = $floatTreeBuilder->getRootNode();
22+
23+
$arrayTreeBuilder = new TreeBuilder('my_tree', 'array');
24+
$arrayRootNode = $arrayTreeBuilder->getRootNode();
25+
26+
$enumTreeBuilder = new TreeBuilder('my_tree', 'enum');
27+
$enumRootNode = $enumTreeBuilder->getRootNode();
28+
29+
die;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /