Skip to content

Commit 31fa5e0

Browse files
committed
getConstantStrings() can handle all the manipulation of the path
1 parent 67ce86b commit 31fa5e0

File tree

3 files changed

+30
-80
lines changed

3 files changed

+30
-80
lines changed

src/Rules/Keywords/RequireFileExistsRule.php

Lines changed: 5 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,10 @@
33
namespace PHPStan\Rules\Keywords;
44

55
use PhpParser\Node;
6-
use PhpParser\Node\Expr\BinaryOp\Concat;
7-
use PhpParser\Node\Expr\ClassConstFetch;
8-
use PhpParser\Node\Expr\ConstFetch;
96
use PhpParser\Node\Expr\Include_;
10-
use PhpParser\Node\Identifier;
11-
use PhpParser\Node\Name;
12-
use PhpParser\Node\Scalar\MagicConst\Dir;
13-
use PhpParser\Node\Scalar\String_;
147
use PHPStan\Analyser\Scope;
15-
use PHPStan\Reflection\ReflectionProvider;
168
use PHPStan\Rules\Rule;
179
use PHPStan\Rules\RuleErrorBuilder;
18-
use function constant;
19-
use function defined;
20-
use function dirname;
2110
use function is_string;
2211
use function sprintf;
2312

@@ -26,11 +15,6 @@
2615
*/
2716
final class RequireFileExistsRule implements Rule
2817
{
29-
30-
public function __construct(private ReflectionProvider $reflectionProvider)
31-
{
32-
}
33-
3418
public function getNodeType(): string
3519
{
3620
return Include_::class;
@@ -39,7 +23,7 @@ public function getNodeType(): string
3923
public function processNode(Node $node, Scope $scope): array
4024
{
4125
if ($this->shouldProcessNode($node)) {
42-
$filePath = $this->resolveFilePath($node->expr, $scope);
26+
$filePath = $this->resolveFilePath($node, $scope);
4327
if (is_string($filePath) && !is_file($filePath)) {
4428
return [
4529
$this->getErrorMessage($node, $filePath)->build()
@@ -73,67 +57,11 @@ private function getErrorMessage(Include_ $node, string $filePath): RuleErrorBui
7357
);
7458
}
7559

76-
private function resolveFilePath(Node $node, Scope $scope): ?string
77-
{
78-
if ($node instanceof String_) {
79-
return $node->value;
80-
}
81-
82-
if ($node instanceof Dir) {
83-
return dirname($scope->getFile());
84-
}
85-
86-
if ($node instanceof ClassConstFetch) {
87-
return $this->resolveClassConstant($node);
88-
}
89-
90-
if ($node instanceof ConstFetch) {
91-
return $this->resolveConstant($node);
92-
}
93-
94-
if ($node instanceof Concat) {
95-
$left = $this->resolveFilePath($node->left, $scope);
96-
$right = $this->resolveFilePath($node->right, $scope);
97-
if ($left !== null && $right !== null) {
98-
return $left . $right;
99-
}
100-
}
101-
102-
return null;
103-
}
104-
105-
private function resolveClassConstant(ClassConstFetch $node): ?string
60+
private function resolveFilePath(Include_ $node, Scope $scope): ?string
10661
{
107-
if ($node->class instanceof Name && $node->name instanceof Identifier) {
108-
$className = (string) $node->class;
109-
$constantName = $node->name->toString();
62+
$type = $scope->getType($node->expr);
63+
$paths = $type->getConstantStrings();
11064

111-
if ($this->reflectionProvider->hasClass($className)) {
112-
$classReflection = $this->reflectionProvider->getClass($className);
113-
if ($classReflection->hasConstant($constantName)) {
114-
$constantReflection = $classReflection->getConstant($constantName);
115-
$constantValue = $constantReflection->getValue();
116-
if (is_string($constantValue)) {
117-
return $constantValue;
118-
}
119-
}
120-
}
121-
}
122-
return null;
65+
return $paths ? $paths[0]->getValue() : null;
12366
}
124-
125-
private function resolveConstant(ConstFetch $node): ?string
126-
{
127-
if ($node->name instanceof Name) {
128-
$constantName = (string) $node->name;
129-
if (defined($constantName)) {
130-
$constantValue = constant($constantName);
131-
if (is_string($constantValue)) {
132-
return $constantValue;
133-
}
134-
}
135-
}
136-
return null;
137-
}
138-
13967
}

tests/PHPStan/Rules/Keywords/RequireFileExistsRuleTest.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,28 @@ public function testFileExistsUsingDIR(): void
8383
$this->analyse([__DIR__ . '/data/file-exists-using-DIR.php'], []);
8484
}
8585

86-
public function testFileDoesNotExistButUsesClassProperties(): void
86+
public function testFileExistsUsingVariables(): void
8787
{
88-
$this->analyse([__DIR__ . '/data/file-does-not-exist-but-uses-a-class-property.php'], []);
88+
$this->analyse([__DIR__ . '/data/file-exists-using-a-variable.php'], []);
8989
}
9090

9191
public function testFileDoesNotExistButUsesVariables(): void
9292
{
93-
$this->analyse([__DIR__ . '/data/file-does-not-exist-but-uses-a-variable.php'], []);
93+
$this->analyse([__DIR__ . '/data/file-does-not-exist-but-uses-a-variable.php'], [
94+
[
95+
'Path in require() "a-file-that-does-not-exist.php" is not a file or it does not exist.',
96+
7,
97+
],
98+
[
99+
'Path in require_once() "a-file-that-does-not-exist.php" is not a file or it does not exist.',
100+
8,
101+
],
102+
]);
103+
}
104+
105+
public function testFileDoesNotExistButUsesClassProperties(): void
106+
{
107+
$this->analyse([__DIR__ . '/data/file-does-not-exist-but-uses-a-class-property.php'], []);
94108
}
95109

96110
public function testFileDoesNotExistButUsesClassMethods(): void
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php declare(strict_types=1);
2+
3+
$includedFile = __DIR__ . 'include-me-to-prove-you-work.txt';
4+
5+
include $includedFile;
6+
include_once $includedFile;
7+
require $includedFile;
8+
require_once $includedFile;

0 commit comments

Comments
 (0)