/
ContainerHandler.php
68 lines (60 loc) · 1.95 KB
/
ContainerHandler.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?php
namespace mortenson\PsalmPluginDrupal;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Scalar\String_;
use Psalm\Codebase;
use Psalm\Context;
use Psalm\Plugin\Hook\AfterMethodCallAnalysisInterface;
use Psalm\StatementsSource;
use Psalm\SymfonyPsalmPlugin\Symfony\ContainerMeta;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Union;
// Copies Psalm\SymfonyPsalmPlugin\Handler\ContainerHandler to support Drupal::service.
class ContainerHandler implements AfterMethodCallAnalysisInterface
{
/**
* @var ContainerMeta|null
*/
private static $containerMeta;
public static function init(ContainerMeta $containerMeta): void
{
self::$containerMeta = $containerMeta;
}
/**
* {@inheritdoc}
*/
public static function afterMethodCallAnalysis(
Expr $expr,
string $method_id,
string $appearing_method_id,
string $declaring_method_id,
Context $context,
StatementsSource $statements_source,
Codebase $codebase,
array &$file_replacements = [],
Union &$return_type_candidate = null
): void {
if (!in_array($declaring_method_id, ['Drupal::service'], true)) {
return;
}
if (!self::$containerMeta) {
return;
}
if ($expr->args[0]->value instanceof String_) {
$serviceId = $expr->args[0]->value->value;
} elseif ($expr->args[0]->value instanceof ClassConstFetch) {
$serviceId = (string) $expr->args[0]->value->class->getAttribute('resolvedName');
} else {
return;
}
$service = self::$containerMeta->get($serviceId);
if ($service) {
$class = $service->getClass();
if ($class) {
$codebase->classlikes->addFullyQualifiedClassName($class);
$return_type_candidate = new Union([new TNamedObject($class)]);
}
}
}
}