Skip to content

Commit 20539fc

Browse files
committed
resolveType in PropertyFetchHandler
1 parent 23faebb commit 20539fc

File tree

2 files changed

+73
-73
lines changed

2 files changed

+73
-73
lines changed

src/Analyser/ExprHandler/PropertyFetchHandler.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,27 @@
44

55
use PhpParser\Node\Expr;
66
use PhpParser\Node\Expr\PropertyFetch;
7+
use PhpParser\Node\Identifier;
8+
use PhpParser\Node\Scalar\String_;
79
use PhpParser\Node\Stmt;
810
use PHPStan\Analyser\ExpressionContext;
911
use PHPStan\Analyser\ExpressionResult;
1012
use PHPStan\Analyser\ExpressionResultStorage;
1113
use PHPStan\Analyser\ExprHandler;
14+
use PHPStan\Analyser\ExprHandler\Helper\NullsafeShortCircuitingHelper;
1215
use PHPStan\Analyser\InternalThrowPoint;
1316
use PHPStan\Analyser\MutatingScope;
1417
use PHPStan\Analyser\NodeScopeResolver;
1518
use PHPStan\DependencyInjection\AutowiredService;
1619
use PHPStan\Php\PhpVersion;
20+
use PHPStan\Rules\Properties\PropertyReflectionFinder;
21+
use PHPStan\Type\ErrorType;
22+
use PHPStan\Type\MixedType;
23+
use PHPStan\Type\Type;
24+
use PHPStan\Type\TypeCombinator;
25+
use function array_map;
1726
use function array_merge;
27+
use function count;
1828

1929
/**
2030
* @implements ExprHandler<PropertyFetch>
@@ -25,6 +35,7 @@ final class PropertyFetchHandler implements ExprHandler
2535

2636
public function __construct(
2737
private PhpVersion $phpVersion,
38+
private PropertyReflectionFinder $propertyReflectionFinder,
2839
)
2940
{
3041
}
@@ -77,4 +88,66 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
7788
);
7889
}
7990

91+
/**
92+
* @param PropertyFetch $expr
93+
*/
94+
public function resolveType(MutatingScope $scope, Expr $expr): Type
95+
{
96+
if ($expr->name instanceof Identifier) {
97+
if ($scope->nativeTypesPromoted) {
98+
$propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($expr, $scope);
99+
if ($propertyReflection === null) {
100+
return new ErrorType();
101+
}
102+
103+
if (!$propertyReflection->hasNativeType()) {
104+
return new MixedType();
105+
}
106+
107+
$nativeType = $propertyReflection->getNativeType();
108+
109+
return NullsafeShortCircuitingHelper::getType($scope, $expr->var, $nativeType);
110+
}
111+
112+
$returnType = $this->propertyFetchType(
113+
$scope,
114+
$scope->getType($expr->var),
115+
$expr->name->name,
116+
$expr,
117+
);
118+
if ($returnType === null) {
119+
$returnType = new ErrorType();
120+
}
121+
122+
return NullsafeShortCircuitingHelper::getType($scope, $expr->var, $returnType);
123+
}
124+
125+
$nameType = $scope->getType($expr->name);
126+
if (count($nameType->getConstantStrings()) > 0) {
127+
return TypeCombinator::union(
128+
...array_map(static fn ($constantString) => $constantString->getValue() === '' ? new ErrorType() : $scope
129+
->filterByTruthyValue(new Expr\BinaryOp\Identical($expr->name, new String_($constantString->getValue())))
130+
->getType(
131+
new PropertyFetch($expr->var, new Identifier($constantString->getValue())),
132+
), $nameType->getConstantStrings()),
133+
);
134+
}
135+
136+
return new MixedType();
137+
}
138+
139+
private function propertyFetchType(MutatingScope $scope, Type $fetchedOnType, string $propertyName, PropertyFetch $propertyFetch): ?Type
140+
{
141+
$propertyReflection = $scope->getInstancePropertyReflection($fetchedOnType, $propertyName);
142+
if ($propertyReflection === null) {
143+
return null;
144+
}
145+
146+
if ($scope->isInExpressionAssign($propertyFetch)) {
147+
return $propertyReflection->getWritableType();
148+
}
149+
150+
return $propertyReflection->getReadableType();
151+
}
152+
80153
}

src/Analyser/MutatingScope.php

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,13 +1170,6 @@ private function resolveType(string $exprString, Expr $node): Type
11701170
}
11711171
}
11721172

1173-
if ($node instanceof PropertyFetch) {
1174-
$fetchType = $this->getPropertyFetchType($node);
1175-
if ($fetchType !== null) {
1176-
return $fetchType;
1177-
}
1178-
}
1179-
11801173
if ($node instanceof FuncCall) {
11811174
return $this->getFunctionCallType($node);
11821175
}
@@ -5022,28 +5015,6 @@ public function getStaticPropertyReflection(Type $typeWithProperty, string $prop
50225015
return $typeWithProperty->getStaticProperty($propertyName, $this);
50235016
}
50245017

5025-
/**
5026-
* @param PropertyFetch|Node\Expr\StaticPropertyFetch $propertyFetch
5027-
*/
5028-
private function propertyFetchType(Type $fetchedOnType, string $propertyName, Expr $propertyFetch): ?Type
5029-
{
5030-
if ($propertyFetch instanceof PropertyFetch) {
5031-
$propertyReflection = $this->getInstancePropertyReflection($fetchedOnType, $propertyName);
5032-
} else {
5033-
$propertyReflection = $this->getStaticPropertyReflection($fetchedOnType, $propertyName);
5034-
}
5035-
5036-
if ($propertyReflection === null) {
5037-
return null;
5038-
}
5039-
5040-
if ($this->isInExpressionAssign($propertyFetch)) {
5041-
return $propertyReflection->getWritableType();
5042-
}
5043-
5044-
return $propertyReflection->getReadableType();
5045-
}
5046-
50475018
public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ClassConstantReflection
50485019
{
50495020
if ($typeWithConstant instanceof UnionType) {
@@ -5655,50 +5626,6 @@ private function getFunctionCallType(FuncCall $node): Type
56555626
return $this->transformVoidToNull($parametersAcceptor->getReturnType(), $node);
56565627
}
56575628

5658-
private function getPropertyFetchType(PropertyFetch $node): ?Type
5659-
{
5660-
if ($node->name instanceof Node\Identifier) {
5661-
if ($this->nativeTypesPromoted) {
5662-
$propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($node, $this);
5663-
if ($propertyReflection === null) {
5664-
return new ErrorType();
5665-
}
5666-
5667-
if (!$propertyReflection->hasNativeType()) {
5668-
return new MixedType();
5669-
}
5670-
5671-
$nativeType = $propertyReflection->getNativeType();
5672-
5673-
return NullsafeShortCircuitingHelper::getType($this, $node->var, $nativeType);
5674-
}
5675-
5676-
$returnType = $this->propertyFetchType(
5677-
$this->getType($node->var),
5678-
$node->name->name,
5679-
$node,
5680-
);
5681-
if ($returnType === null) {
5682-
$returnType = new ErrorType();
5683-
}
5684-
5685-
return NullsafeShortCircuitingHelper::getType($this, $node->var, $returnType);
5686-
}
5687-
5688-
$nameType = $this->getType($node->name);
5689-
if (count($nameType->getConstantStrings()) > 0) {
5690-
return TypeCombinator::union(
5691-
...array_map(fn ($constantString) => $constantString->getValue() === '' ? new ErrorType() : $this
5692-
->filterByTruthyValue(new BinaryOp\Identical($node->name, new String_($constantString->getValue())))
5693-
->getType(
5694-
new PropertyFetch($node->var, new Identifier($constantString->getValue())),
5695-
), $nameType->getConstantStrings()),
5696-
);
5697-
}
5698-
5699-
return null;
5700-
}
5701-
57025629
private function getStaticCallType(Expr\StaticCall $node): ?Type
57035630
{
57045631
if ($node->name instanceof Node\Identifier) {

0 commit comments

Comments
 (0)