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