|
2 | 2 |
|
3 | 3 | namespace PHPStan\Rules\Properties;
|
4 | 4 |
|
| 5 | +use PhpParser\Node\VarLikeIdentifier; |
5 | 6 | use PHPStan\Analyser\Scope;
|
| 7 | +use PHPStan\Type\Constant\ConstantStringType; |
6 | 8 | use PHPStan\Type\ObjectType;
|
7 | 9 | use PHPStan\Type\StaticType;
|
8 | 10 | use PHPStan\Type\ThisType;
|
9 | 11 | use PHPStan\Type\Type;
|
10 | 12 | use PHPStan\Type\TypeTraverser;
|
| 13 | +use PHPStan\Type\TypeUtils; |
11 | 14 |
|
12 | 15 | class PropertyReflectionFinder
|
13 | 16 | {
|
14 | 17 |
|
| 18 | + /** |
| 19 | + * @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch $propertyFetch |
| 20 | + * @param \PHPStan\Analyser\Scope $scope |
| 21 | + * @return FoundPropertyReflection[] |
| 22 | + */ |
| 23 | + public function findPropertyReflectionsFromNode($propertyFetch, Scope $scope): array |
| 24 | + { |
| 25 | + if ($propertyFetch instanceof \PhpParser\Node\Expr\PropertyFetch) { |
| 26 | + if ($propertyFetch->name instanceof \PhpParser\Node\Identifier) { |
| 27 | + $names = [$propertyFetch->name->name]; |
| 28 | + } else { |
| 29 | + $names = array_map(static function (ConstantStringType $name): string { |
| 30 | + return $name->getValue(); |
| 31 | + }, TypeUtils::getConstantStrings($scope->getType($propertyFetch->name))); |
| 32 | + } |
| 33 | + |
| 34 | + $reflections = []; |
| 35 | + $propertyHolderType = $scope->getType($propertyFetch->var); |
| 36 | + $fetchedOnThis = $propertyHolderType instanceof ThisType && $scope->isInClass(); |
| 37 | + foreach ($names as $name) { |
| 38 | + $reflection = $this->findPropertyReflection($propertyHolderType, $name, $scope, $fetchedOnThis); |
| 39 | + if ($reflection === null) { |
| 40 | + continue; |
| 41 | + } |
| 42 | + |
| 43 | + $reflections[] = $reflection; |
| 44 | + } |
| 45 | + |
| 46 | + return $reflections; |
| 47 | + } |
| 48 | + |
| 49 | + if ($propertyFetch->class instanceof \PhpParser\Node\Name) { |
| 50 | + $propertyHolderType = new ObjectType($scope->resolveName($propertyFetch->class)); |
| 51 | + } else { |
| 52 | + $propertyHolderType = $scope->getType($propertyFetch->class); |
| 53 | + } |
| 54 | + |
| 55 | + $fetchedOnThis = $propertyHolderType instanceof ThisType && $scope->isInClass(); |
| 56 | + |
| 57 | + if ($propertyFetch->name instanceof VarLikeIdentifier) { |
| 58 | + $names = [$propertyFetch->name->name]; |
| 59 | + } else { |
| 60 | + $names = array_map(static function (ConstantStringType $name): string { |
| 61 | + return $name->getValue(); |
| 62 | + }, TypeUtils::getConstantStrings($scope->getType($propertyFetch->name))); |
| 63 | + } |
| 64 | + |
| 65 | + $reflections = []; |
| 66 | + foreach ($names as $name) { |
| 67 | + $reflection = $this->findPropertyReflection($propertyHolderType, $name, $scope, $fetchedOnThis); |
| 68 | + if ($reflection === null) { |
| 69 | + continue; |
| 70 | + } |
| 71 | + |
| 72 | + $reflections[] = $reflection; |
| 73 | + } |
| 74 | + |
| 75 | + return $reflections; |
| 76 | + } |
| 77 | + |
15 | 78 | /**
|
16 | 79 | * @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch $propertyFetch
|
17 | 80 | * @param \PHPStan\Analyser\Scope $scope
|
@@ -68,6 +131,7 @@ private function findPropertyReflection(Type $propertyHolderType, string $proper
|
68 | 131 |
|
69 | 132 | return new FoundPropertyReflection(
|
70 | 133 | $originalProperty,
|
| 134 | + $propertyName, |
71 | 135 | $readableType,
|
72 | 136 | $writableType
|
73 | 137 | );
|
|
0 commit comments