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