Skip to content

Commit ce6afae

Browse files
committed
Merge branch '1.3.x' into 1.4.x
2 parents 4f58abc + a9d0aaf commit ce6afae

20 files changed

+338
-154
lines changed

.github/workflows/build.yml

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ jobs:
2323
- "8.0"
2424
- "8.1"
2525
- "8.2"
26+
- "8.3"
2627

2728
steps:
2829
- name: "Checkout"
@@ -143,6 +144,7 @@ jobs:
143144
- "8.0"
144145
- "8.1"
145146
- "8.2"
147+
- "8.3"
146148

147149
steps:
148150
- name: "Checkout"

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"doctrine/dbal": "^2.13.8 || ^3.3.3",
2525
"doctrine/lexer": "^1.2.1",
2626
"doctrine/mongodb-odm": "^1.3 || ^2.1",
27-
"doctrine/orm": "^2.11.0",
27+
"doctrine/orm": "^2.14.0",
2828
"doctrine/persistence": "^1.3.8 || ^2.2.1",
2929
"gedmo/doctrine-extensions": "^3.8",
3030
"nesbot/carbon": "^2.49",

extension.neon

+10-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ conditionalTags:
7474
services:
7575
-
7676
class: PHPStan\Type\Doctrine\DescriptorRegistryFactory
77-
-
78-
class: PHPStan\Type\Doctrine\DescriptorRegistry
77+
78+
doctrineTypeDescriptorRegistry:
79+
class: PHPStan\Type\Doctrine\DefaultDescriptorRegistry
7980
factory: @PHPStan\Type\Doctrine\DescriptorRegistryFactory::createRegistry
8081

8182
-
@@ -115,6 +116,7 @@ services:
115116
arguments:
116117
queryBuilderClass: %doctrine.queryBuilderClass%
117118
argumentsProcessor: @doctrineQueryBuilderArgumentsProcessor
119+
descriptorRegistry: @doctrineTypeDescriptorRegistry
118120
tags:
119121
- phpstan.broker.dynamicMethodReturnTypeExtension
120122
-
@@ -138,6 +140,7 @@ services:
138140
class: PHPStan\Type\Doctrine\CreateQueryDynamicReturnTypeExtension
139141
arguments:
140142
objectMetadataResolver: @PHPStan\Type\Doctrine\ObjectMetadataResolver
143+
descriptorRegistry: @doctrineTypeDescriptorRegistry
141144
tags:
142145
- phpstan.broker.dynamicMethodReturnTypeExtension
143146
-
@@ -166,6 +169,11 @@ services:
166169
descendIntoOtherMethods: %doctrine.searchOtherMethodsForQueryBuilderBeginning%
167170
parser: @defaultAnalysisParser
168171

172+
-
173+
class: PHPStan\Type\Doctrine\QueryBuilder\ReturnQueryBuilderExpressionTypeResolverExtension
174+
tags:
175+
- phpstan.broker.expressionTypeResolverExtension
176+
169177
-
170178
class: PHPStan\Stubs\Doctrine\StubFilesExtensionLoader
171179
tags:

rules.neon

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ services:
3535
class: PHPStan\Rules\Doctrine\ORM\QueryBuilderDqlRule
3636
arguments:
3737
reportDynamicQueryBuilders: %doctrine.reportDynamicQueryBuilders%
38-
searchOtherMethodsForQueryBuilderBeginning: %doctrine.searchOtherMethodsForQueryBuilderBeginning%
3938
tags:
4039
- phpstan.rules.rule
4140
-
@@ -44,6 +43,7 @@ services:
4443
reportUnknownTypes: %doctrine.reportUnknownTypes%
4544
allowNullablePropertyForRequiredField: %doctrine.allowNullablePropertyForRequiredField%
4645
bleedingEdge: %featureToggles.bleedingEdge%
46+
descriptorRegistry: @doctrineTypeDescriptorRegistry
4747
tags:
4848
- phpstan.rules.rule
4949
-

src/Rules/Doctrine/ORM/QueryBuilderDqlRule.php

+1-20
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use PHPStan\Rules\RuleErrorBuilder;
1313
use PHPStan\Type\Doctrine\DoctrineTypeUtils;
1414
use PHPStan\Type\Doctrine\ObjectMetadataResolver;
15-
use PHPStan\Type\Doctrine\QueryBuilder\OtherMethodQueryBuilderParser;
1615
use PHPStan\Type\ObjectType;
1716
use PHPStan\Type\TypeUtils;
1817
use Throwable;
@@ -32,23 +31,13 @@ class QueryBuilderDqlRule implements Rule
3231
/** @var bool */
3332
private $reportDynamicQueryBuilders;
3433

35-
/** @var OtherMethodQueryBuilderParser */
36-
private $otherMethodQueryBuilderParser;
37-
38-
/** @var bool */
39-
private $searchOtherMethodsForQueryBuilderBeginning;
40-
4134
public function __construct(
4235
ObjectMetadataResolver $objectMetadataResolver,
43-
OtherMethodQueryBuilderParser $otherMethodQueryBuilderParser,
44-
bool $reportDynamicQueryBuilders,
45-
bool $searchOtherMethodsForQueryBuilderBeginning
36+
bool $reportDynamicQueryBuilders
4637
)
4738
{
4839
$this->objectMetadataResolver = $objectMetadataResolver;
49-
$this->otherMethodQueryBuilderParser = $otherMethodQueryBuilderParser;
5040
$this->reportDynamicQueryBuilders = $reportDynamicQueryBuilders;
51-
$this->searchOtherMethodsForQueryBuilderBeginning = $searchOtherMethodsForQueryBuilderBeginning;
5241
}
5342

5443
public function getNodeType(): string
@@ -69,14 +58,6 @@ public function processNode(Node $node, Scope $scope): array
6958
$calledOnType = $scope->getType($node->var);
7059
$queryBuilderTypes = DoctrineTypeUtils::getQueryBuilderTypes($calledOnType);
7160
if (count($queryBuilderTypes) === 0) {
72-
73-
if ($this->searchOtherMethodsForQueryBuilderBeginning) {
74-
$queryBuilderTypes = $this->otherMethodQueryBuilderParser->getQueryBuilderTypes($scope, $node);
75-
if (count($queryBuilderTypes) !== 0) {
76-
return [];
77-
}
78-
}
79-
8061
if (
8162
$this->reportDynamicQueryBuilders
8263
&& (new ObjectType('Doctrine\ORM\QueryBuilder'))->isSuperTypeOf($calledOnType)->yes()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Doctrine;
4+
5+
use Doctrine\DBAL\Types\Type;
6+
use PHPStan\Type\Doctrine\Descriptors\DoctrineTypeDescriptor;
7+
8+
class DefaultDescriptorRegistry implements DescriptorRegistry
9+
{
10+
11+
/** @var array<class-string<Type>, DoctrineTypeDescriptor> */
12+
private $descriptors = [];
13+
14+
/**
15+
* @param DoctrineTypeDescriptor[] $descriptors
16+
*/
17+
public function __construct(array $descriptors)
18+
{
19+
foreach ($descriptors as $descriptor) {
20+
$this->descriptors[$descriptor->getType()] = $descriptor;
21+
}
22+
}
23+
24+
public function get(string $type): DoctrineTypeDescriptor
25+
{
26+
$typesMap = Type::getTypesMap();
27+
if (!isset($typesMap[$type])) {
28+
throw new DescriptorNotRegisteredException();
29+
}
30+
31+
/** @var class-string<Type> $typeClass */
32+
$typeClass = $typesMap[$type];
33+
if (!isset($this->descriptors[$typeClass])) {
34+
throw new DescriptorNotRegisteredException();
35+
}
36+
return $this->descriptors[$typeClass];
37+
}
38+
39+
}

src/Type/Doctrine/DescriptorRegistry.php

+2-29
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,11 @@
22

33
namespace PHPStan\Type\Doctrine;
44

5-
use Doctrine\DBAL\Types\Type;
65
use PHPStan\Type\Doctrine\Descriptors\DoctrineTypeDescriptor;
76

8-
class DescriptorRegistry
7+
interface DescriptorRegistry
98
{
109

11-
/** @var array<class-string<Type>, DoctrineTypeDescriptor> */
12-
private $descriptors = [];
13-
14-
/**
15-
* @param DoctrineTypeDescriptor[] $descriptors
16-
*/
17-
public function __construct(array $descriptors)
18-
{
19-
foreach ($descriptors as $descriptor) {
20-
$this->descriptors[$descriptor->getType()] = $descriptor;
21-
}
22-
}
23-
24-
public function get(string $type): DoctrineTypeDescriptor
25-
{
26-
$typesMap = Type::getTypesMap();
27-
if (!isset($typesMap[$type])) {
28-
throw new DescriptorNotRegisteredException();
29-
}
30-
31-
/** @var class-string<Type> $typeClass */
32-
$typeClass = $typesMap[$type];
33-
if (!isset($this->descriptors[$typeClass])) {
34-
throw new DescriptorNotRegisteredException();
35-
}
36-
return $this->descriptors[$typeClass];
37-
}
10+
public function get(string $type): DoctrineTypeDescriptor;
3811

3912
}

src/Type/Doctrine/DescriptorRegistryFactory.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function __construct(Container $container)
1919

2020
public function createRegistry(): DescriptorRegistry
2121
{
22-
return new DescriptorRegistry($this->container->getServicesByTag(self::TYPE_DESCRIPTOR_TAG));
22+
return new DefaultDescriptorRegistry($this->container->getServicesByTag(self::TYPE_DESCRIPTOR_TAG));
2323
}
2424

2525
}

src/Type/Doctrine/QueryBuilder/OtherMethodQueryBuilderParser.php

+5-41
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
namespace PHPStan\Type\Doctrine\QueryBuilder;
44

55
use PhpParser\Node;
6-
use PhpParser\Node\Expr\MethodCall;
7-
use PhpParser\Node\Identifier;
86
use PhpParser\Node\Stmt;
97
use PhpParser\Node\Stmt\Class_;
108
use PhpParser\Node\Stmt\ClassMethod;
@@ -17,13 +15,12 @@
1715
use PHPStan\Analyser\ScopeFactory;
1816
use PHPStan\DependencyInjection\Container;
1917
use PHPStan\Parser\Parser;
20-
use PHPStan\Reflection\ReflectionProvider;
18+
use PHPStan\Reflection\MethodReflection;
2119
use PHPStan\Type\Generic\TemplateTypeMap;
2220
use PHPStan\Type\IntersectionType;
2321
use PHPStan\Type\Type;
2422
use PHPStan\Type\TypeTraverser;
2523
use PHPStan\Type\UnionType;
26-
use function count;
2724
use function is_array;
2825

2926
class OtherMethodQueryBuilderParser
@@ -32,61 +29,28 @@ class OtherMethodQueryBuilderParser
3229
/** @var bool */
3330
private $descendIntoOtherMethods;
3431

35-
/** @var ReflectionProvider */
36-
private $reflectionProvider;
37-
3832
/** @var Parser */
3933
private $parser;
4034

4135
/** @var Container */
4236
private $container;
4337

44-
public function __construct(bool $descendIntoOtherMethods, ReflectionProvider $reflectionProvider, Parser $parser, Container $container)
38+
public function __construct(bool $descendIntoOtherMethods, Parser $parser, Container $container)
4539
{
4640
$this->descendIntoOtherMethods = $descendIntoOtherMethods;
47-
$this->reflectionProvider = $reflectionProvider;
4841
$this->parser = $parser;
4942
$this->container = $container;
5043
}
5144

5245
/**
53-
* @return QueryBuilderType[]
46+
* @return list<QueryBuilderType>
5447
*/
55-
public function getQueryBuilderTypes(Scope $scope, MethodCall $methodCall): array
48+
public function findQueryBuilderTypesInCalledMethod(Scope $scope, MethodReflection $methodReflection): array
5649
{
57-
if (!$this->descendIntoOtherMethods || !$methodCall->var instanceof MethodCall) {
58-
return [];
59-
}
60-
61-
return $this->findQueryBuilderTypesInCalledMethod($scope, $methodCall->var);
62-
}
63-
/**
64-
* @return QueryBuilderType[]
65-
*/
66-
private function findQueryBuilderTypesInCalledMethod(Scope $scope, MethodCall $methodCall): array
67-
{
68-
$methodCalledOnType = $scope->getType($methodCall->var);
69-
if (!$methodCall->name instanceof Identifier) {
70-
return [];
71-
}
72-
73-
$methodCalledOnTypeClassNames = $methodCalledOnType->getObjectClassNames();
74-
75-
if (count($methodCalledOnTypeClassNames) !== 1) {
76-
return [];
77-
}
78-
79-
if (!$this->reflectionProvider->hasClass($methodCalledOnTypeClassNames[0])) {
80-
return [];
81-
}
82-
83-
$classReflection = $this->reflectionProvider->getClass($methodCalledOnTypeClassNames[0]);
84-
$methodName = $methodCall->name->toString();
85-
if (!$classReflection->hasNativeMethod($methodName)) {
50+
if (!$this->descendIntoOtherMethods) {
8651
return [];
8752
}
8853

89-
$methodReflection = $classReflection->getNativeMethod($methodName);
9054
$fileName = $methodReflection->getDeclaringClass()->getFileName();
9155
if ($fileName === null) {
9256
return [];

src/Type/Doctrine/QueryBuilder/QueryBuilderGetQueryDynamicReturnTypeExtension.php

+2-10
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,17 @@ class QueryBuilderGetQueryDynamicReturnTypeExtension implements DynamicMethodRet
6565
/** @var DescriptorRegistry */
6666
private $descriptorRegistry;
6767

68-
/** @var OtherMethodQueryBuilderParser */
69-
private $otherMethodQueryBuilderParser;
70-
7168
public function __construct(
7269
ObjectMetadataResolver $objectMetadataResolver,
7370
ArgumentsProcessor $argumentsProcessor,
7471
?string $queryBuilderClass,
75-
DescriptorRegistry $descriptorRegistry,
76-
OtherMethodQueryBuilderParser $otherMethodQueryBuilderParser
72+
DescriptorRegistry $descriptorRegistry
7773
)
7874
{
7975
$this->objectMetadataResolver = $objectMetadataResolver;
8076
$this->argumentsProcessor = $argumentsProcessor;
8177
$this->queryBuilderClass = $queryBuilderClass;
8278
$this->descriptorRegistry = $descriptorRegistry;
83-
$this->otherMethodQueryBuilderParser = $otherMethodQueryBuilderParser;
8479
}
8580

8681
public function getClass(): string
@@ -107,10 +102,7 @@ public function getTypeFromMethodCall(
107102
)->getReturnType();
108103
$queryBuilderTypes = DoctrineTypeUtils::getQueryBuilderTypes($calledOnType);
109104
if (count($queryBuilderTypes) === 0) {
110-
$queryBuilderTypes = $this->otherMethodQueryBuilderParser->getQueryBuilderTypes($scope, $methodCall);
111-
if (count($queryBuilderTypes) === 0) {
112-
return $defaultReturnType;
113-
}
105+
return $defaultReturnType;
114106
}
115107

116108
$objectManager = $this->objectMetadataResolver->getObjectManager();

src/Type/Doctrine/QueryBuilder/QueryBuilderMethodDynamicReturnTypeExtension.php

+2-10
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,11 @@ class QueryBuilderMethodDynamicReturnTypeExtension implements DynamicMethodRetur
2626
/** @var string|null */
2727
private $queryBuilderClass;
2828

29-
/** @var OtherMethodQueryBuilderParser */
30-
private $otherMethodQueryBuilderParser;
31-
3229
public function __construct(
33-
?string $queryBuilderClass,
34-
OtherMethodQueryBuilderParser $otherMethodQueryBuilderParser
30+
?string $queryBuilderClass
3531
)
3632
{
3733
$this->queryBuilderClass = $queryBuilderClass;
38-
$this->otherMethodQueryBuilderParser = $otherMethodQueryBuilderParser;
3934
}
4035

4136
public function getClass(): string
@@ -74,10 +69,7 @@ public function getTypeFromMethodCall(
7469

7570
$queryBuilderTypes = DoctrineTypeUtils::getQueryBuilderTypes($calledOnType);
7671
if (count($queryBuilderTypes) === 0) {
77-
$queryBuilderTypes = $this->otherMethodQueryBuilderParser->getQueryBuilderTypes($scope, $methodCall);
78-
if (count($queryBuilderTypes) === 0) {
79-
return $calledOnType;
80-
}
72+
return $calledOnType;
8173
}
8274

8375
if (count($queryBuilderTypes) > self::MAX_COMBINATIONS) {

0 commit comments

Comments
 (0)