Skip to content

Commit caf2f83

Browse files
eiriksmmglaman
authored andcommitted
Add a rule for loadIncludes. Fix #124
1 parent fc7e1f5 commit caf2f83

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

extension.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ parametersSchema:
2323
entityTypeStorageMapping: arrayOf(string())
2424
])
2525
rules:
26+
- PHPStan\Rules\Drupal\LoadIncludes
2627
- PHPStan\Rules\Classes\PluginManagerInspectionRule
2728
- PHPStan\Rules\Drupal\Coder\DiscouragedFunctionsRule
2829
- PHPStan\Rules\Drupal\GlobalDrupalDependencyInjectionRule

src/Rules/Drupal/LoadIncludes.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace PHPStan\Rules\Drupal;
4+
5+
use Drupal\Core\Extension\ModuleHandler;
6+
use Drupal\Core\Extension\ModuleHandlerInterface;
7+
use DrupalFinder\DrupalFinder;
8+
use PhpParser\Node;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Drupal\ExtensionDiscovery;
11+
use PHPStan\Reflection\MethodReflection;
12+
use PHPStan\Rules\Rule;
13+
use PHPStan\ShouldNotHappenException;
14+
15+
class LoadIncludes implements Rule
16+
{
17+
public function getNodeType(): string
18+
{
19+
return Node\Expr\MethodCall::class;
20+
}
21+
22+
public function processNode(Node $node, Scope $scope): array
23+
{
24+
assert($node instanceof Node\Expr\MethodCall);
25+
26+
try {
27+
$method_name = $node->name;
28+
if ($method_name instanceof Node\Identifier) {
29+
$method_name = $method_name->name;
30+
}
31+
if ($method_name !== 'loadInclude') {
32+
return [];
33+
}
34+
$var_name = $node->var->name;
35+
if ($var_name instanceof Node\Identifier) {
36+
$var_name = $var_name->name;
37+
}
38+
if (!$var_name) {
39+
return [];
40+
}
41+
$type = $scope->getVariableType($var_name);
42+
$reflected = new \ReflectionClass($type->getClassName());
43+
$implements = $reflected->implementsInterface(ModuleHandlerInterface::class);
44+
if (!$implements) {
45+
return [];
46+
}
47+
// Try to invoke it similarily as the module handler itself.
48+
$finder = new DrupalFinder();
49+
$finder->locateRoot(dirname($GLOBALS['autoloaderInWorkingDirectory']));
50+
$drupal_root = $finder->getDrupalRoot();
51+
$extensionDiscovery = new ExtensionDiscovery($drupal_root);
52+
$modules = $extensionDiscovery->scan('module');
53+
$module_arg = $node->args[0]->value->value;
54+
$type_arg = $node->args[1]->value->value;
55+
$name_arg = !empty($node->args[2]) ? $node->args[2] : null;
56+
if (!$name_arg) {
57+
$name_arg = $module_arg;
58+
} else {
59+
$name_arg = $name_arg->value->value;
60+
}
61+
if (empty($modules[$module_arg])) {
62+
return [];
63+
}
64+
/** @var \PHPStan\Drupal\Extension $module */
65+
$module = $modules[$module_arg];
66+
$file = $drupal_root . '/' . $module->getPath() . "/$name_arg.$type_arg";
67+
if (is_file($file)) {
68+
require_once $file;
69+
return [];
70+
}
71+
return ['File could not be loaded from ModuleHandler::loadInclude'];
72+
} catch (\Throwable $e) {
73+
}
74+
75+
return [];
76+
}
77+
}

0 commit comments

Comments
 (0)