Skip to content

Commit 4acbc6c

Browse files
committed
Calling parent:: preserves generic types
1 parent a1b7b38 commit 4acbc6c

13 files changed

+85
-26
lines changed

src/Analyser/MutatingScope.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,8 +854,7 @@ private function resolveType(Expr $node): Type
854854
$uncertainty = false;
855855

856856
if ($node->class instanceof Node\Name) {
857-
$className = $this->resolveName($node->class);
858-
$classType = new ObjectType($className);
857+
$classType = $this->resolveTypeByName($node->class);
859858
} else {
860859
$classType = $this->getType($node->class);
861860
$classType = TypeTraverser::map($classType, static function (Type $type, callable $traverse) use (&$uncertainty): Type {
@@ -1771,7 +1770,7 @@ private function resolveType(Expr $node): Type
17711770
if ($resolvedName === 'parent' && strtolower($constantName) === 'class') {
17721771
return new ClassStringType();
17731772
}
1774-
$constantClassType = new ObjectType($resolvedName);
1773+
$constantClassType = $this->resolveTypeByName($node->class);
17751774
}
17761775

17771776
if (strtolower($constantName) === 'class') {
@@ -1932,7 +1931,7 @@ private function resolveType(Expr $node): Type
19321931
if ($node instanceof Expr\StaticCall && $node->name instanceof Node\Identifier) {
19331932
$typeCallback = function () use ($node): Type {
19341933
if ($node->class instanceof Name) {
1935-
$staticMethodCalledOnType = new ObjectType($this->resolveName($node->class));
1934+
$staticMethodCalledOnType = $this->resolveTypeByName($node->class);
19361935
} else {
19371936
$staticMethodCalledOnType = $this->getType($node->class);
19381937
if ($staticMethodCalledOnType instanceof GenericClassStringType) {
@@ -2045,7 +2044,7 @@ private function resolveType(Expr $node): Type
20452044
) {
20462045
$typeCallback = function () use ($node): Type {
20472046
if ($node->class instanceof Name) {
2048-
$staticPropertyFetchedOnType = new ObjectType($this->resolveName($node->class));
2047+
$staticPropertyFetchedOnType = $this->resolveTypeByName($node->class);
20492048
} else {
20502049
$staticPropertyFetchedOnType = $this->getType($node->class);
20512050
if ($staticPropertyFetchedOnType instanceof GenericClassStringType) {
@@ -2448,6 +2447,25 @@ public function resolveName(Name $name): string
24482447
return $originalClass;
24492448
}
24502449

2450+
public function resolveTypeByName(Name $name): TypeWithClassName
2451+
{
2452+
if ($name->toLowerString() === 'static' && $this->isInClass()) {
2453+
$classReflection = $this->getClassReflection();
2454+
2455+
return new StaticType($classReflection->getName());
2456+
}
2457+
$originalClass = $this->resolveName($name);
2458+
if ($this->isInClass()) {
2459+
$thisType = new ThisType($this->getClassReflection());
2460+
$ancestor = $thisType->getAncestorWithClassName($originalClass);
2461+
if ($ancestor !== null) {
2462+
return $ancestor;
2463+
}
2464+
}
2465+
2466+
return new ObjectType($originalClass);
2467+
}
2468+
24512469
/**
24522470
* @param mixed $value
24532471
*/

src/Analyser/NodeScopeResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,7 @@ private function findEarlyTerminatingExpr(Expr $expr, Scope $scope): ?Expr
14381438
$methodCalledOnType = $scope->getType($expr->var);
14391439
} else {
14401440
if ($expr->class instanceof Name) {
1441-
$methodCalledOnType = new ObjectType($scope->resolveName($expr->class));
1441+
$methodCalledOnType = $scope->resolveTypeByName($expr->class);
14421442
} else {
14431443
$methodCalledOnType = $scope->getType($expr->class);
14441444
}
@@ -2770,7 +2770,7 @@ private function processAssignVar(
27702770

27712771
} elseif ($var instanceof Expr\StaticPropertyFetch) {
27722772
if ($var->class instanceof \PhpParser\Node\Name) {
2773-
$propertyHolderType = new ObjectType($scope->resolveName($var->class));
2773+
$propertyHolderType = $scope->resolveTypeByName($var->class);
27742774
} else {
27752775
$this->processExprNode($var->class, $scope, $nodeCallback, $context);
27762776
$propertyHolderType = $scope->getType($var->class);

src/Analyser/Scope.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public function doNotTreatPhpDocTypesAsCertain(): self;
7070

7171
public function resolveName(Name $name): string;
7272

73+
public function resolveTypeByName(Name $name): Type;
74+
7375
/**
7476
* @param mixed $value
7577
*/

src/Analyser/TypeSpecifier.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ public function specifyTypesInCondition(
549549
}
550550
} elseif ($expr instanceof StaticCall && $expr->name instanceof Node\Identifier) {
551551
if ($expr->class instanceof Name) {
552-
$calleeType = new ObjectType($scope->resolveName($expr->class));
552+
$calleeType = $scope->resolveTypeByName($expr->class);
553553
} else {
554554
$calleeType = $scope->getType($expr->class);
555555
}

src/Node/ClassPropertiesNode.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ private function getMethodsCalledFromConstructor(
213213
if (!$methodCallNode->class instanceof Name) {
214214
continue;
215215
}
216-
$calledOnType = new ObjectType($callScope->resolveName($methodCallNode->class));
216+
217+
$calledOnType = $callScope->resolveTypeByName($methodCallNode->class);
217218
}
218219
if ($classType->isSuperTypeOf($calledOnType)->no()) {
219220
continue;

src/Rules/Classes/ImpossibleInstanceOfRule.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Rules\RuleErrorBuilder;
88
use PHPStan\Type\Constant\ConstantBooleanType;
9-
use PHPStan\Type\ObjectType;
109
use PHPStan\Type\ObjectWithoutClassType;
1110
use PHPStan\Type\StringType;
1211
use PHPStan\Type\TypeCombinator;
@@ -42,8 +41,7 @@ public function processNode(Node $node, Scope $scope): array
4241
$expressionType = $scope->getType($node->expr);
4342

4443
if ($node->class instanceof Node\Name) {
45-
$className = $scope->resolveName($node->class);
46-
$classType = new ObjectType($className);
44+
$classType = $scope->resolveTypeByName($node->class);
4745
} else {
4846
$classType = $scope->getType($node->class);
4947
$allowed = TypeCombinator::union(

src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use PHPStan\Analyser\Scope;
88
use PHPStan\Reflection\MethodReflection;
99
use PHPStan\Rules\RuleErrorBuilder;
10-
use PHPStan\Type\ObjectType;
1110

1211
/**
1312
* @implements \PHPStan\Rules\Rule<\PhpParser\Node\Expr\StaticCall>
@@ -102,7 +101,7 @@ private function getMethod(
102101
): MethodReflection
103102
{
104103
if ($class instanceof Node\Name) {
105-
$calledOnType = new ObjectType($scope->resolveName($class));
104+
$calledOnType = $scope->resolveTypeByName($class);
106105
} else {
107106
$calledOnType = $scope->getType($class);
108107
}

src/Rules/DeadCode/UnusedPrivateMethodRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public function processNode(Node $node, Scope $scope): array
8484
if (!$methodCallNode->class instanceof Node\Name) {
8585
continue;
8686
}
87-
$calledOnType = new ObjectType($callScope->resolveName($methodCallNode->class));
87+
$calledOnType = $scope->resolveTypeByName($methodCallNode->class);
8888
}
8989
if ($classType->isSuperTypeOf($calledOnType)->no()) {
9090
continue;

src/Rules/DeadCode/UnusedPrivatePropertyRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public function processNode(Node $node, Scope $scope): array
147147
continue;
148148
}
149149

150-
$fetchedOnType = new ObjectType($usage->getScope()->resolveName($fetch->class));
150+
$fetchedOnType = $usage->getScope()->resolveTypeByName($fetch->class);
151151
}
152152

153153
if ($classType->isSuperTypeOf($fetchedOnType)->no()) {

src/Rules/Properties/PropertyReflectionFinder.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use PhpParser\Node\VarLikeIdentifier;
88
use PHPStan\Analyser\Scope;
99
use PHPStan\Type\Constant\ConstantStringType;
10-
use PHPStan\Type\ObjectType;
1110
use PHPStan\Type\StaticType;
1211
use PHPStan\Type\ThisType;
1312
use PHPStan\Type\Type;
@@ -57,7 +56,7 @@ public function findPropertyReflectionsFromNode($propertyFetch, Scope $scope): a
5756
}
5857

5958
if ($propertyFetch->class instanceof \PhpParser\Node\Name) {
60-
$propertyHolderType = new ObjectType($scope->resolveName($propertyFetch->class));
59+
$propertyHolderType = $scope->resolveTypeByName($propertyFetch->class);
6160
} else {
6261
$propertyHolderType = $scope->getType($propertyFetch->class);
6362
}
@@ -114,7 +113,7 @@ public function findPropertyReflectionFromNode($propertyFetch, Scope $scope): ?F
114113
}
115114

116115
if ($propertyFetch->class instanceof \PhpParser\Node\Name) {
117-
$propertyHolderType = new ObjectType($scope->resolveName($propertyFetch->class));
116+
$propertyHolderType = $scope->resolveTypeByName($propertyFetch->class);
118117
} else {
119118
$propertyHolderType = $scope->getType($propertyFetch->class);
120119
}

0 commit comments

Comments
 (0)