1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Rules\RestrictedUsage;
4:
5: use PhpParser\Node;
6: use PhpParser\Node\Identifier;
7: use PHPStan\Analyser\Scope;
8: use PHPStan\DependencyInjection\AutowiredService;
9: use PHPStan\DependencyInjection\Container;
10: use PHPStan\Reflection\ReflectionProvider;
11: use PHPStan\Rules\Rule;
12: use PHPStan\Rules\RuleErrorBuilder;
13:
14: /**
15: * @implements Rule<Node\Expr\PropertyFetch>
16: */
17: #[AutowiredService]
18: final class RestrictedPropertyUsageRule implements Rule
19: {
20:
21: public function __construct(
22: private Container $container,
23: private ReflectionProvider $reflectionProvider,
24: )
25: {
26: }
27:
28: public function getNodeType(): string
29: {
30: return Node\Expr\PropertyFetch::class;
31: }
32:
33: /**
34: * @api
35: */
36: public function processNode(Node $node, Scope $scope): array
37: {
38: if (!$node->name instanceof Identifier) {
39: return [];
40: }
41:
42: /** @var RestrictedPropertyUsageExtension[] $extensions */
43: $extensions = $this->container->getServicesByTag(RestrictedPropertyUsageExtension::PROPERTY_EXTENSION_TAG);
44: if ($extensions === []) {
45: return [];
46: }
47:
48: $propertyName = $node->name->name;
49: $propertyCalledOnType = $scope->getType($node->var);
50: $referencedClasses = $propertyCalledOnType->getObjectClassNames();
51:
52: $errors = [];
53:
54: foreach ($referencedClasses as $referencedClass) {
55: if (!$this->reflectionProvider->hasClass($referencedClass)) {
56: continue;
57: }
58:
59: $classReflection = $this->reflectionProvider->getClass($referencedClass);
60: if (!$classReflection->hasProperty($propertyName)) {
61: continue;
62: }
63:
64: $propertyReflection = $classReflection->getProperty($propertyName, $scope);
65: foreach ($extensions as $extension) {
66: $restrictedUsage = $extension->isRestrictedPropertyUsage($propertyReflection, $scope);
67: if ($restrictedUsage === null) {
68: continue;
69: }
70:
71: $errors[] = RuleErrorBuilder::message($restrictedUsage->errorMessage)
72: ->identifier($restrictedUsage->identifier)
73: ->build();
74: }
75: }
76:
77: return $errors;
78: }
79:
80: }
81: