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 cc9d9ac

Browse files
authored
Add full support for Config/TreeBuilder
1 parent 6f27071 commit cc9d9ac

13 files changed

+495
-52
lines changed

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This extension provides following features:
1313
* Provides correct return type for `Request::getContent()` method based on the `$asResource` parameter.
1414
* Provides correct return type for `HeaderBag::get()` method based on the `$first` parameter.
1515
* Provides correct return type for `Envelope::all()` method based on the `$stampFqcn` parameter.
16+
* Provides correct return types for `TreeBuilder` and `NodeDefinition` objects.
1617
* Notifies you when you try to get an unregistered service from the container.
1718
* Notifies you when you try to get a private service from the container.
1819
* Optionally correct return types for `InputInterface::getArgument()`, `::getOption`, `::hasArgument`, and `::hasOption`.

‎extension.neon‎

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ services:
4444
# console resolver
4545
-
4646
factory: PHPStan\Symfony\ConsoleApplicationResolver
47-
arguments: [%symfony.console_application_loader%]
47+
arguments:
48+
consoleApplicationLoader: %symfony.console_application_loader%
4849

4950
# service map
5051
symfony.serviceMapFactory:
@@ -146,12 +147,57 @@ services:
146147
factory: PHPStan\Type\Symfony\InputInterfaceHasOptionDynamicReturnTypeExtension
147148
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
148149

150+
# ArrayNodeDefinition::*prototype() return type
151+
-
152+
factory: PHPStan\Type\Symfony\Config\ArrayNodeDefinitionPrototypeDynamicReturnTypeExtension
153+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
154+
155+
# ExprBuilder::end() return type
156+
-
157+
factory: PHPStan\Type\Symfony\Config\ReturnParentDynamicReturnTypeExtension
158+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
159+
arguments:
160+
className: Symfony\Component\Config\Definition\Builder\ExprBuilder
161+
methods: [end]
162+
163+
# NodeBuilder::*node() return type
164+
-
165+
factory: PHPStan\Type\Symfony\Config\PassParentObjectDynamicReturnTypeExtension
166+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
167+
arguments:
168+
className: Symfony\Component\Config\Definition\Builder\NodeBuilder
169+
methods: [arrayNode, scalarNode, booleanNode, integerNode, floatNode, enumNode, variableNode]
170+
171+
# NodeBuilder::end() return type
172+
-
173+
factory: PHPStan\Type\Symfony\Config\ReturnParentDynamicReturnTypeExtension
174+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
175+
arguments:
176+
className: Symfony\Component\Config\Definition\Builder\NodeBuilder
177+
methods: [end]
178+
179+
# NodeDefinition::children() return type
180+
-
181+
factory: PHPStan\Type\Symfony\Config\PassParentObjectDynamicReturnTypeExtension
182+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
183+
arguments:
184+
className: Symfony\Component\Config\Definition\Builder\NodeDefinition
185+
methods: [children, validate]
186+
187+
# NodeDefinition::end() return type
188+
-
189+
factory: PHPStan\Type\Symfony\Config\ReturnParentDynamicReturnTypeExtension
190+
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
191+
arguments:
192+
className: Symfony\Component\Config\Definition\Builder\NodeDefinition
193+
methods: [end]
194+
149195
# new TreeBuilder() return type
150196
-
151-
factory: PHPStan\Type\Symfony\TreeBuilderDynamicReturnTypeExtension
197+
factory: PHPStan\Type\Symfony\Config\TreeBuilderDynamicReturnTypeExtension
152198
tags: [phpstan.broker.dynamicStaticMethodReturnTypeExtension]
153199

154200
# TreeBuilder::getRootNode() return type
155201
-
156-
factory: PHPStan\Type\Symfony\TreeBuilderGetRootNodeDynamicReturnTypeExtension
202+
factory: PHPStan\Type\Symfony\Config\TreeBuilderGetRootNodeDynamicReturnTypeExtension
157203
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony\Config;
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\Symfony\Config\ValueObject\ParentObjectType;
11+
use PHPStan\Type\Type;
12+
use PHPStan\Type\TypeUtils;
13+
use PHPStan\Type\VerbosityLevel;
14+
15+
final class ArrayNodeDefinitionPrototypeDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
16+
{
17+
18+
private const PROTOTYPE_METHODS = [
19+
'arrayPrototype',
20+
'scalarPrototype',
21+
'booleanPrototype',
22+
'integerPrototype',
23+
'floatPrototype',
24+
'enumPrototype',
25+
'variablePrototype',
26+
];
27+
28+
private const MAPPING = [
29+
'variable' => 'Symfony\Component\Config\Definition\Builder\VariableNodeDefinition',
30+
'scalar' => 'Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition',
31+
'boolean' => 'Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition',
32+
'integer' => 'Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition',
33+
'float' => 'Symfony\Component\Config\Definition\Builder\FloatNodeDefinition',
34+
'array' => 'Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition',
35+
'enum' => 'Symfony\Component\Config\Definition\Builder\EnumNodeDefinition',
36+
];
37+
38+
public function getClass(): string
39+
{
40+
return 'Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition';
41+
}
42+
43+
public function isMethodSupported(MethodReflection $methodReflection): bool
44+
{
45+
return $methodReflection->getName() === 'prototype' || in_array($methodReflection->getName(), self::PROTOTYPE_METHODS, true);
46+
}
47+
48+
public function getTypeFromMethodCall(
49+
MethodReflection $methodReflection,
50+
MethodCall $methodCall,
51+
Scope $scope
52+
): Type
53+
{
54+
$calledOnType = $scope->getType($methodCall->var);
55+
56+
$defaultType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
57+
58+
if ($methodReflection->getName() === 'prototype') {
59+
if (!isset($methodCall->args[0])) {
60+
return $defaultType;
61+
}
62+
63+
$argStrings = TypeUtils::getConstantStrings($scope->getType($methodCall->args[0]->value));
64+
if (count($argStrings) === 1 && isset(self::MAPPING[$argStrings[0]->getValue()])) {
65+
$type = $argStrings[0]->getValue();
66+
67+
return new ParentObjectType(self::MAPPING[$type], $calledOnType);
68+
}
69+
}
70+
71+
return new ParentObjectType(
72+
$defaultType->describe(VerbosityLevel::typeOnly()),
73+
$calledOnType
74+
);
75+
}
76+
77+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony\Config;
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\Symfony\Config\ValueObject\ParentObjectType;
11+
use PHPStan\Type\Type;
12+
use PHPStan\Type\VerbosityLevel;
13+
14+
final class PassParentObjectDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
15+
{
16+
17+
/** @var string */
18+
private $className;
19+
20+
/** @var string[] */
21+
private $methods;
22+
23+
/**
24+
* @param string $className
25+
* @param string[] $methods
26+
*/
27+
public function __construct(string $className, array $methods)
28+
{
29+
$this->className = $className;
30+
$this->methods = $methods;
31+
}
32+
33+
public function getClass(): string
34+
{
35+
return $this->className;
36+
}
37+
38+
public function isMethodSupported(MethodReflection $methodReflection): bool
39+
{
40+
return in_array($methodReflection->getName(), $this->methods, true);
41+
}
42+
43+
public function getTypeFromMethodCall(
44+
MethodReflection $methodReflection,
45+
MethodCall $methodCall,
46+
Scope $scope
47+
): Type
48+
{
49+
$calledOnType = $scope->getType($methodCall->var);
50+
51+
$defaultType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
52+
53+
return new ParentObjectType($defaultType->describe(VerbosityLevel::typeOnly()), $calledOnType);
54+
}
55+
56+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony\Config;
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\Symfony\Config\ValueObject\ParentObjectType;
11+
use PHPStan\Type\Type;
12+
13+
final class ReturnParentDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
14+
{
15+
16+
/** @var string */
17+
private $className;
18+
19+
/** @var string[] */
20+
private $methods;
21+
22+
/**
23+
* @param string $className
24+
* @param string[] $methods
25+
*/
26+
public function __construct(string $className, array $methods)
27+
{
28+
$this->className = $className;
29+
$this->methods = $methods;
30+
}
31+
32+
public function getClass(): string
33+
{
34+
return $this->className;
35+
}
36+
37+
public function isMethodSupported(MethodReflection $methodReflection): bool
38+
{
39+
return in_array($methodReflection->getName(), $this->methods, true);
40+
}
41+
42+
public function getTypeFromMethodCall(
43+
MethodReflection $methodReflection,
44+
MethodCall $methodCall,
45+
Scope $scope
46+
): Type
47+
{
48+
$calledOnType = $scope->getType($methodCall->var);
49+
if ($calledOnType instanceof ParentObjectType) {
50+
return $calledOnType->getParent();
51+
}
52+
53+
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
54+
}
55+
56+
}

‎src/Type/Symfony/TreeBuilderDynamicReturnTypeExtension.php‎ renamed to ‎src/Type/Symfony/Config/TreeBuilderDynamicReturnTypeExtension.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<?php declare(strict_types = 1);
22

3-
namespace PHPStan\Type\Symfony;
3+
namespace PHPStan\Type\Symfony\Config;
44

55
use PhpParser\Node\Expr\StaticCall;
66
use PhpParser\Node\Name;
77
use PHPStan\Analyser\Scope;
88
use PHPStan\Reflection\MethodReflection;
99
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
10+
use PHPStan\Type\Symfony\Config\ValueObject\TreeBuilderType;
1011
use PHPStan\Type\Type;
1112
use PHPStan\Type\TypeUtils;
1213

‎src/Type/Symfony/TreeBuilderGetRootNodeDynamicReturnTypeExtension.php‎ renamed to ‎src/Type/Symfony/Config/TreeBuilderGetRootNodeDynamicReturnTypeExtension.php‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
<?php declare(strict_types = 1);
22

3-
namespace PHPStan\Type\Symfony;
3+
namespace PHPStan\Type\Symfony\Config;
44

55
use PhpParser\Node\Expr\MethodCall;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Reflection\MethodReflection;
8+
use PHPStan\Reflection\ParametersAcceptorSelector;
89
use PHPStan\Type\DynamicMethodReturnTypeExtension;
9-
use PHPStan\Type\ObjectType;
10+
use PHPStan\Type\Symfony\Config\ValueObject\ParentObjectType;
11+
use PHPStan\Type\Symfony\Config\ValueObject\TreeBuilderType;
1012
use PHPStan\Type\Type;
1113

1214
final class TreeBuilderGetRootNodeDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
@@ -29,11 +31,17 @@ public function getTypeFromMethodCall(
2931
): Type
3032
{
3133
$calledOnType = $scope->getType($methodCall->var);
34+
35+
$defaultType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
36+
3237
if ($calledOnType instanceof TreeBuilderType) {
33-
return new ObjectType($calledOnType->getRootNodeClassName());
38+
return new ParentObjectType(
39+
$calledOnType->getRootNodeClassName(),
40+
$calledOnType
41+
);
3442
}
3543

36-
return $methodReflection->getVariants()[0]->getReturnType();
44+
return $defaultType;
3745
}
3846

3947
}
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\Config\ValueObject;
4+
5+
use PHPStan\Type\ObjectType;
6+
use PHPStan\Type\Type;
7+
8+
class ParentObjectType extends ObjectType
9+
{
10+
11+
/** @var Type */
12+
private $parent;
13+
14+
public function __construct(string $className, Type $parent)
15+
{
16+
parent::__construct($className);
17+
18+
$this->parent = $parent;
19+
}
20+
21+
public function getParent(): Type
22+
{
23+
return $this->parent;
24+
}
25+
26+
}

‎src/Type/Symfony/TreeBuilderType.php‎ renamed to ‎src/Type/Symfony/Config/ValueObject/TreeBuilderType.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php declare(strict_types = 1);
22

3-
namespace PHPStan\Type\Symfony;
3+
namespace PHPStan\Type\Symfony\Config\ValueObject;
44

55
use PHPStan\Type\ObjectType;
66

0 commit comments

Comments
(0)

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