Skip to content

Commit aa35eec

Browse files
janedbalondrejmirtes
authored andcommitted
ExpressionTypeResolverExtension
1 parent bed73a3 commit aa35eec

15 files changed

+225
-0
lines changed

conf/config.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,10 @@ services:
588588
class: PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider
589589
factory: PHPStan\DependencyInjection\Type\LazyDynamicReturnTypeExtensionRegistryProvider
590590

591+
-
592+
class: PHPStan\DependencyInjection\Type\ExpressionTypeResolverExtensionRegistryProvider
593+
factory: PHPStan\DependencyInjection\Type\LazyExpressionTypeResolverExtensionRegistryProvider
594+
591595
-
592596
class: PHPStan\DependencyInjection\Type\OperatorTypeSpecifyingExtensionRegistryProvider
593597
factory: PHPStan\DependencyInjection\Type\LazyOperatorTypeSpecifyingExtensionRegistryProvider

src/Analyser/DirectInternalScopeFactory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Analyser;
44

55
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
6+
use PHPStan\DependencyInjection\Type\ExpressionTypeResolverExtensionRegistryProvider;
67
use PHPStan\Node\Printer\ExprPrinter;
78
use PHPStan\Parser\Parser;
89
use PHPStan\Php\PhpVersion;
@@ -26,6 +27,7 @@ public function __construct(
2627
private ReflectionProvider $reflectionProvider,
2728
private InitializerExprTypeResolver $initializerExprTypeResolver,
2829
private DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider,
30+
private ExpressionTypeResolverExtensionRegistryProvider $expressionTypeResolverExtensionRegistryProvider,
2931
private ExprPrinter $exprPrinter,
3032
private TypeSpecifier $typeSpecifier,
3133
private PropertyReflectionFinder $propertyReflectionFinder,
@@ -76,6 +78,7 @@ public function create(
7678
$this->reflectionProvider,
7779
$this->initializerExprTypeResolver,
7880
$this->dynamicReturnTypeExtensionRegistryProvider->getRegistry(),
81+
$this->expressionTypeResolverExtensionRegistryProvider->getRegistry(),
7982
$this->exprPrinter,
8083
$this->typeSpecifier,
8184
$this->propertyReflectionFinder,

src/Analyser/LazyInternalScopeFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPStan\DependencyInjection\Container;
66
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
7+
use PHPStan\DependencyInjection\Type\ExpressionTypeResolverExtensionRegistryProvider;
78
use PHPStan\Node\Printer\ExprPrinter;
89
use PHPStan\Php\PhpVersion;
910
use PHPStan\Reflection\FunctionReflection;
@@ -72,6 +73,7 @@ public function create(
7273
$this->container->getByType(ReflectionProvider::class),
7374
$this->container->getByType(InitializerExprTypeResolver::class),
7475
$this->container->getByType(DynamicReturnTypeExtensionRegistryProvider::class)->getRegistry(),
76+
$this->container->getByType(ExpressionTypeResolverExtensionRegistryProvider::class)->getRegistry(),
7577
$this->container->getByType(ExprPrinter::class),
7678
$this->container->getByType(TypeSpecifier::class),
7779
$this->container->getByType(PropertyReflectionFinder::class),

src/Analyser/MutatingScope.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
use PHPStan\Type\ConstantTypeHelper;
8787
use PHPStan\Type\DynamicReturnTypeExtensionRegistry;
8888
use PHPStan\Type\ErrorType;
89+
use PHPStan\Type\ExpressionTypeResolverExtensionRegistry;
8990
use PHPStan\Type\GeneralizePrecision;
9091
use PHPStan\Type\Generic\GenericClassStringType;
9192
use PHPStan\Type\Generic\GenericObjectType;
@@ -178,6 +179,7 @@ public function __construct(
178179
private ReflectionProvider $reflectionProvider,
179180
private InitializerExprTypeResolver $initializerExprTypeResolver,
180181
private DynamicReturnTypeExtensionRegistry $dynamicReturnTypeExtensionRegistry,
182+
private ExpressionTypeResolverExtensionRegistry $expressionTypeResolverExtensionRegistry,
181183
private ExprPrinter $exprPrinter,
182184
private TypeSpecifier $typeSpecifier,
183185
private PropertyReflectionFinder $propertyReflectionFinder,
@@ -679,6 +681,13 @@ private function getNodeKey(Expr $node): string
679681

680682
private function resolveType(string $exprString, Expr $node): Type
681683
{
684+
foreach ($this->expressionTypeResolverExtensionRegistry->getExtensions() as $extension) {
685+
$type = $extension->getType($node, $this);
686+
if ($type !== null) {
687+
return $type;
688+
}
689+
}
690+
682691
if ($node instanceof Expr\Exit_ || $node instanceof Expr\Throw_) {
683692
return new NonAcceptingNeverType();
684693
}

src/Broker/BrokerFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class BrokerFactory
1515
public const DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG = 'phpstan.broker.dynamicStaticMethodReturnTypeExtension';
1616
public const DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG = 'phpstan.broker.dynamicFunctionReturnTypeExtension';
1717
public const OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.broker.operatorTypeSpecifyingExtension';
18+
public const EXPRESSION_TYPE_RESOLVER_EXTENSION_TAG = 'phpstan.broker.expressionTypeResolverExtension';
1819

1920
public function __construct(private Container $container)
2021
{

src/DependencyInjection/ConditionalTagsExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public function getConfigSchema(): Nette\Schema\Schema
3333
BrokerFactory::DYNAMIC_METHOD_RETURN_TYPE_EXTENSION_TAG => $bool,
3434
BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG => $bool,
3535
BrokerFactory::DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG => $bool,
36+
BrokerFactory::EXPRESSION_TYPE_RESOLVER_EXTENSION_TAG => $bool,
3637
BrokerFactory::OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG => $bool,
3738
BrokerFactory::ALLOWED_SUB_TYPES_CLASS_REFLECTION_EXTENSION_TAG => $bool,
3839
LazyRegistry::RULE_TAG => $bool,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\DependencyInjection\Type;
4+
5+
use PHPStan\Type\ExpressionTypeResolverExtensionRegistry;
6+
7+
interface ExpressionTypeResolverExtensionRegistryProvider
8+
{
9+
10+
public function getRegistry(): ExpressionTypeResolverExtensionRegistry;
11+
12+
}
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+
namespace PHPStan\DependencyInjection\Type;
4+
5+
use PHPStan\Broker\BrokerFactory;
6+
use PHPStan\DependencyInjection\Container;
7+
use PHPStan\Type\ExpressionTypeResolverExtensionRegistry;
8+
9+
class LazyExpressionTypeResolverExtensionRegistryProvider implements ExpressionTypeResolverExtensionRegistryProvider
10+
{
11+
12+
private ?ExpressionTypeResolverExtensionRegistry $registry = null;
13+
14+
public function __construct(private Container $container)
15+
{
16+
}
17+
18+
public function getRegistry(): ExpressionTypeResolverExtensionRegistry
19+
{
20+
if ($this->registry === null) {
21+
$this->registry = new ExpressionTypeResolverExtensionRegistry(
22+
$this->container->getServicesByTag(BrokerFactory::EXPRESSION_TYPE_RESOLVER_EXTENSION_TAG),
23+
);
24+
}
25+
26+
return $this->registry;
27+
}
28+
29+
}

src/Testing/PHPStanTestCase.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPStan\DependencyInjection\ContainerFactory;
1919
use PHPStan\DependencyInjection\Reflection\ClassReflectionExtensionRegistryProvider;
2020
use PHPStan\DependencyInjection\Type\DynamicReturnTypeExtensionRegistryProvider;
21+
use PHPStan\DependencyInjection\Type\ExpressionTypeResolverExtensionRegistryProvider;
2122
use PHPStan\DependencyInjection\Type\OperatorTypeSpecifyingExtensionRegistryProvider;
2223
use PHPStan\File\FileHelper;
2324
use PHPStan\Internal\DirectoryCreator;
@@ -180,6 +181,7 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider
180181
$container->getParameter('usePathConstantsAsConstantString'),
181182
),
182183
$container->getByType(DynamicReturnTypeExtensionRegistryProvider::class),
184+
$container->getByType(ExpressionTypeResolverExtensionRegistryProvider::class),
183185
$container->getByType(ExprPrinter::class),
184186
$typeSpecifier,
185187
new PropertyReflectionFinder(),
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type;
4+
5+
use PhpParser\Node\Expr;
6+
use PHPStan\Analyser\Scope;
7+
8+
/**
9+
* To register it in the configuration file use the `phpstan.broker.expressionTypeResolverExtension` service tag:
10+
*
11+
* ```
12+
* services:
13+
* -
14+
* class: App\PHPStan\MyExtension
15+
* tags:
16+
* - phpstan.broker.expressionTypeResolverExtension
17+
* ```
18+
*
19+
* You should return null in your extension if you don't care about given Expr.
20+
*
21+
* @api
22+
*/
23+
interface ExpressionTypeResolverExtension
24+
{
25+
26+
public function getType(Expr $expr, Scope $scope): ?Type;
27+
28+
}

0 commit comments

Comments
 (0)