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

Support for TreeBuilder::getRootNode() #126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
ondrejmirtes merged 4 commits into phpstan:master from ruudk:configuration
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"phpstan/phpstan-strict-rules": "^0.12.5",
"phpunit/phpunit": "^7.5.20",
"symfony/console": "^4.0",
"symfony/config": "^4.2",
"symfony/framework-bundle": "^4.0",
"symfony/http-foundation": "^4.0",
"symfony/messenger": "^4.2",
Expand Down
10 changes: 10 additions & 0 deletions extension.neon
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,13 @@ services:
-
factory: PHPStan\Type\Symfony\InputInterfaceHasOptionDynamicReturnTypeExtension
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]

# new TreeBuilder() return type
-
factory: PHPStan\Type\Symfony\TreeBuilderDynamicReturnTypeExtension
tags: [phpstan.broker.dynamicStaticMethodReturnTypeExtension]

# TreeBuilder::getRootNode() return type
-
factory: PHPStan\Type\Symfony\TreeBuilderGetRootNodeDynamicReturnTypeExtension
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
56 changes: 56 additions & 0 deletions src/Type/Symfony/TreeBuilderDynamicReturnTypeExtension.php
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Symfony;

use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;

final class TreeBuilderDynamicReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension
{

private const MAPPING = [
'variable' => 'Symfony\Component\Config\Definition\Builder\VariableNodeDefinition',
'scalar' => 'Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition',
'boolean' => 'Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition',
'integer' => 'Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition',
'float' => 'Symfony\Component\Config\Definition\Builder\FloatNodeDefinition',
'array' => 'Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition',
'enum' => 'Symfony\Component\Config\Definition\Builder\EnumNodeDefinition',
];

public function getClass(): string
{
return 'Symfony\Component\Config\Definition\Builder\TreeBuilder';
}

public function isStaticMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === '__construct';
}

public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): Type
{
if (!$methodCall->class instanceof Name) {
throw new \PHPStan\ShouldNotHappenException();
}

$className = $scope->resolveName($methodCall->class);

$type = 'array';

if (isset($methodCall->args[1])) {
$argStrings = TypeUtils::getConstantStrings($scope->getType($methodCall->args[1]->value));
if (count($argStrings) === 1 && isset(self::MAPPING[$argStrings[0]->getValue()])) {
$type = $argStrings[0]->getValue();
}
}

return new TreeBuilderType($className, self::MAPPING[$type]);
}

}
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Symfony;

use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;

final class TreeBuilderGetRootNodeDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
{

public function getClass(): string
{
return 'Symfony\Component\Config\Definition\Builder\TreeBuilder';
}

public function isMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === 'getRootNode';
}

public function getTypeFromMethodCall(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type
{
$calledOnType = $scope->getType($methodCall->var);
if ($calledOnType instanceof TreeBuilderType) {
return new ObjectType($calledOnType->getRootNodeClassName());
}

return $methodReflection->getVariants()[0]->getReturnType();
}

}
25 changes: 25 additions & 0 deletions src/Type/Symfony/TreeBuilderType.php
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Symfony;

use PHPStan\Type\ObjectType;

class TreeBuilderType extends ObjectType
{

/** @var string */
private $rootNodeClassName;

public function __construct(string $className, string $rootNodeClassName)
{
parent::__construct($className);

$this->rootNodeClassName = $rootNodeClassName;
}

public function getRootNodeClassName(): string
{
return $this->rootNodeClassName;
}

}
2 changes: 1 addition & 1 deletion tests/Type/Symfony/EnvelopeReturnTypeExtensionTest.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function testAll(string $expression, string $type): void
__DIR__ . '/envelope_all.php',
$expression,
$type,
new EnvelopeReturnTypeExtension()
[new EnvelopeReturnTypeExtension()]
);
}

Expand Down
13 changes: 10 additions & 3 deletions tests/Type/Symfony/ExtensionTestCase.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,28 @@
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\Reflection\ReflectionProvider\DirectReflectionProviderProvider;
use PHPStan\Testing\TestCase;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\FileTypeMapper;
use PHPStan\Type\VerbosityLevel;

abstract class ExtensionTestCase extends TestCase
{

/**
* @param string $file
* @param string $expression
* @param string $type
* @param \PHPStan\Type\DynamicMethodReturnTypeExtension[] $dynamicMethodReturnTypeExtensions
* @param \PHPStan\Type\DynamicStaticMethodReturnTypeExtension[] $dynamicStaticMethodReturnTypeExtensions
*/
protected function processFile(
string $file,
string $expression,
string $type,
DynamicMethodReturnTypeExtension $extension
array $dynamicMethodReturnTypeExtensions = [],
array $dynamicStaticMethodReturnTypeExtensions = []
): void
{
$broker = $this->createBroker([$extension]);
$broker = $this->createBroker($dynamicMethodReturnTypeExtensions, $dynamicStaticMethodReturnTypeExtensions);
$parser = $this->getParser();
$currentWorkingDirectory = $this->getCurrentWorkingDirectory();
$fileHelper = new FileHelper($currentWorkingDirectory);
Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function testGet(string $expression, string $type): void
__DIR__ . '/header_bag_get.php',
$expression,
$type,
new HeaderBagDynamicReturnTypeExtension()
[new HeaderBagDynamicReturnTypeExtension()]
);
}

Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function testGet(string $expression, string $type): void
__DIR__ . '/input_bag_get.php',
$expression,
$type,
new InputBagDynamicReturnTypeExtension()
[new InputBagDynamicReturnTypeExtension()]
);
}

Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function testArgumentTypes(string $expression, string $type): void
__DIR__ . '/ExampleBaseCommand.php',
$expression,
$type,
new InputInterfaceGetArgumentDynamicReturnTypeExtension(new ConsoleApplicationResolver(__DiR__ . '/console_application_loader.php'))
[new InputInterfaceGetArgumentDynamicReturnTypeExtension(new ConsoleApplicationResolver(__DiR__ . '/console_application_loader.php'))]
);
}

Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function testArgumentTypes(string $expression, string $type): void
__DIR__ . '/ExampleOptionCommand.php',
$expression,
$type,
new InputInterfaceGetOptionDynamicReturnTypeExtension(new ConsoleApplicationResolver(__DiR__ . '/console_application_loader.php'))
[new InputInterfaceGetOptionDynamicReturnTypeExtension(new ConsoleApplicationResolver(__DiR__ . '/console_application_loader.php'))]
);
}

Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function testGet(string $expression, string $type): void
__DIR__ . '/kernel_interface.php',
$expression,
$type,
new KernelInterfaceDynamicReturnTypeExtension()
[new KernelInterfaceDynamicReturnTypeExtension()]
);
}

Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function testGetContent(string $expression, string $type): void
__DIR__ . '/request_get_content.php',
$expression,
$type,
new RequestDynamicReturnTypeExtension()
[new RequestDynamicReturnTypeExtension()]
);
}

Expand Down
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public function testSerializerInterface(string $expression, string $type): void
__DIR__ . '/serializer.php',
$expression,
$type,
new SerializerDynamicReturnTypeExtension(
[new SerializerDynamicReturnTypeExtension(
'Symfony\Component\Serializer\SerializerInterface',
'deserialize'
)
)]
);
}

Expand All @@ -32,10 +32,10 @@ public function testDenormalizerInterface(string $expression, string $type): voi
__DIR__ . '/denormalizer.php',
$expression,
$type,
new SerializerDynamicReturnTypeExtension(
[new SerializerDynamicReturnTypeExtension(
'Symfony\Component\Serializer\Normalizer\DenormalizerInterface',
'denormalize'
)
)]
);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/Type/Symfony/ServiceDynamicReturnTypeExtensionTest.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function testServices(string $expression, string $type, ?string $containe
__DIR__ . '/ExampleController.php',
$expression,
$type,
new ServiceDynamicReturnTypeExtension(Controller::class, true, (new XmlServiceMapFactory($container))->create())
[new ServiceDynamicReturnTypeExtension(Controller::class, true, (new XmlServiceMapFactory($container))->create())]
);
}

Expand Down Expand Up @@ -55,7 +55,7 @@ public function testConstantHassersOff(string $expression, string $type, ?string
__DIR__ . '/ExampleController.php',
$expression,
$type,
new ServiceDynamicReturnTypeExtension(Controller::class, false, (new XmlServiceMapFactory($container))->create())
[new ServiceDynamicReturnTypeExtension(Controller::class, false, (new XmlServiceMapFactory($container))->create())]
);
}

Expand Down
39 changes: 39 additions & 0 deletions tests/Type/Symfony/TreeBuilderDynamicReturnTypeExtensionTest.php
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types = 1);

namespace PHPStan\Type\Symfony;

use Iterator;

final class TreeBuilderDynamicReturnTypeExtensionTest extends ExtensionTestCase
{

/**
* @dataProvider getProvider
*/
public function testGet(string $expression, string $type): void
{
$this->processFile(
__DIR__ . '/tree_builder.php',
$expression,
$type,
[new TreeBuilderGetRootNodeDynamicReturnTypeExtension()],
[new TreeBuilderDynamicReturnTypeExtension()]
);
}

/**
* @return \Iterator<array{string, string}>
*/
public function getProvider(): Iterator
{
yield ['$treeRootNode', 'Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition'];
yield ['$variableRootNode', 'Symfony\Component\Config\Definition\Builder\VariableNodeDefinition'];
yield ['$scalarRootNode', 'Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition'];
yield ['$booleanRootNode', 'Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition'];
yield ['$integerRootNode', 'Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition'];
yield ['$floatRootNode', 'Symfony\Component\Config\Definition\Builder\FloatNodeDefinition'];
yield ['$arrayRootNode', 'Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition'];
yield ['$enumRootNode', 'Symfony\Component\Config\Definition\Builder\EnumNodeDefinition'];
}

}
29 changes: 29 additions & 0 deletions tests/Type/Symfony/tree_builder.php
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types = 1);

use Symfony\Component\Config\Definition\Builder\TreeBuilder;

$treeBuilder = new TreeBuilder('my_tree');
$treeRootNode = $treeBuilder->getRootNode();

$variableTreeBuilder = new TreeBuilder('my_tree', 'variable');
$variableRootNode = $variableTreeBuilder->getRootNode();

$scalarTreeBuilder = new TreeBuilder('my_tree', 'scalar');
$scalarRootNode = $scalarTreeBuilder->getRootNode();

$booleanTreeBuilder = new TreeBuilder('my_tree', 'boolean');
$booleanRootNode = $booleanTreeBuilder->getRootNode();

$integerTreeBuilder = new TreeBuilder('my_tree', 'integer');
$integerRootNode = $integerTreeBuilder->getRootNode();

$floatTreeBuilder = new TreeBuilder('my_tree', 'float');
$floatRootNode = $floatTreeBuilder->getRootNode();

$arrayTreeBuilder = new TreeBuilder('my_tree', 'array');
$arrayRootNode = $arrayTreeBuilder->getRootNode();

$enumTreeBuilder = new TreeBuilder('my_tree', 'enum');
$enumRootNode = $enumTreeBuilder->getRootNode();

die;

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