Skip to content

Commit 9be1376

Browse files
committed
Scope::getFunctionCallStack()
1 parent bbd9a68 commit 9be1376

5 files changed

Lines changed: 89 additions & 1 deletion

File tree

src/Analyser/MutatingScope.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class MutatingScope implements Scope
174174
* @param array<string, true> $currentlyAssignedExpressions
175175
* @param array<string, true> $currentlyAllowedUndefinedExpressions
176176
* @param array<string, ExpressionTypeHolder> $nativeExpressionTypes
177-
* @param array<MethodReflection|FunctionReflection> $inFunctionCallsStack
177+
* @param list<MethodReflection|FunctionReflection> $inFunctionCallsStack
178178
*/
179179
public function __construct(
180180
private InternalScopeFactory $scopeFactory,
@@ -2493,6 +2493,11 @@ public function isInClassExists(string $className): bool
24932493
return $this->getType($expr)->isTrue()->yes();
24942494
}
24952495

2496+
public function getFunctionCallStack(): array
2497+
{
2498+
return $this->inFunctionCallsStack;
2499+
}
2500+
24962501
/** @api */
24972502
public function isInFunctionExists(string $functionName): bool
24982503
{

src/Analyser/Scope.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PHPStan\Reflection\ConstantReflection;
1212
use PHPStan\Reflection\ExtendedMethodReflection;
1313
use PHPStan\Reflection\FunctionReflection;
14+
use PHPStan\Reflection\MethodReflection;
1415
use PHPStan\Reflection\NamespaceAnswerer;
1516
use PHPStan\Reflection\ParametersAcceptor;
1617
use PHPStan\Reflection\PropertyReflection;
@@ -104,6 +105,9 @@ public function isInFunctionExists(string $functionName): bool;
104105

105106
public function isInClosureBind(): bool;
106107

108+
/** @return list<FunctionReflection|MethodReflection> */
109+
public function getFunctionCallStack(): array;
110+
107111
public function isParameterValueNullable(Param $parameter): bool;
108112

109113
/**
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\Throw_;
7+
use PHPStan\Analyser\Scope;
8+
use PHPStan\Reflection\FunctionReflection;
9+
use function implode;
10+
use function sprintf;
11+
12+
/** @implements Rule<Throw_> */
13+
class ScopeFunctionCallStackRule implements Rule
14+
{
15+
16+
public function getNodeType(): string
17+
{
18+
return Throw_::class;
19+
}
20+
21+
public function processNode(Node $node, Scope $scope): array
22+
{
23+
$messages = [];
24+
foreach ($scope->getFunctionCallStack() as $reflection) {
25+
if ($reflection instanceof FunctionReflection) {
26+
$messages[] = $reflection->getName();
27+
continue;
28+
}
29+
30+
$messages[] = sprintf('%s::%s', $reflection->getDeclaringClass()->getDisplayName(), $reflection->getName());
31+
}
32+
33+
return [
34+
RuleErrorBuilder::message(implode("\n", $messages))->identifier('dummy')->build(),
35+
];
36+
}
37+
38+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use PHPStan\Testing\RuleTestCase;
6+
use const PHP_VERSION_ID;
7+
8+
/**
9+
* @extends RuleTestCase<ScopeFunctionCallStackRule>
10+
*/
11+
class ScopeFunctionCallStackRuleTest extends RuleTestCase
12+
{
13+
14+
protected function getRule(): Rule
15+
{
16+
return new ScopeFunctionCallStackRule();
17+
}
18+
19+
public function testRule(): void
20+
{
21+
if (PHP_VERSION_ID < 80000) {
22+
$this->markTestSkipped('Test requires PHP 8.0.');
23+
}
24+
25+
$this->analyse([__DIR__ . '/data/scope-function-call-stack.php'], [
26+
[
27+
"var_dump\nprint_r\nsleep",
28+
7,
29+
],
30+
]);
31+
}
32+
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php // lint >= 8.0
2+
3+
namespace ScopeFunctionCallStack;
4+
5+
function (): void
6+
{
7+
var_dump(print_r(sleep(throw new \Exception())));
8+
};

0 commit comments

Comments
 (0)