Skip to content

Commit 7fe9bc2

Browse files
committed
Introduce PropertyHookReturnStatementsNode similar to MethodReturnStatementsNode
1 parent 869f3d5 commit 7fe9bc2

File tree

2 files changed

+146
-1
lines changed

2 files changed

+146
-1
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
use PHPStan\Node\MethodReturnStatementsNode;
115115
use PHPStan\Node\NoopExpressionNode;
116116
use PHPStan\Node\PropertyAssignNode;
117+
use PHPStan\Node\PropertyHookReturnStatementsNode;
117118
use PHPStan\Node\PropertyHookStatementNode;
118119
use PHPStan\Node\ReturnStatement;
119120
use PHPStan\Node\StaticMethodCallableNode;
@@ -4702,7 +4703,47 @@ private function processPropertyHooks(
47024703
$this->processExprNode($stmt, $hook->body, $hookScope, $nodeCallback, ExpressionContext::createTopLevel());
47034704
$nodeCallback(new PropertyAssignNode(new PropertyFetch(new Variable('this'), $propertyName, $hook->body->getAttributes()), $hook->body, false), $hookScope);
47044705
} elseif (is_array($hook->body)) {
4705-
$this->processStmtNodes(new PropertyHookStatementNode($hook), $hook->body, $hookScope, $nodeCallback, StatementContext::createTopLevel());
4706+
$gatheredReturnStatements = [];
4707+
$executionEnds = [];
4708+
$methodImpurePoints = [];
4709+
$statementResult = $this->processStmtNodes(new PropertyHookStatementNode($hook), $hook->body, $hookScope, static function (Node $node, Scope $scope) use ($nodeCallback, $hookScope, &$gatheredReturnStatements, &$executionEnds, &$hookImpurePoints): void {
4710+
$nodeCallback($node, $scope);
4711+
if ($scope->getFunction() !== $hookScope->getFunction()) {
4712+
return;
4713+
}
4714+
if ($scope->isInAnonymousFunction()) {
4715+
return;
4716+
}
4717+
if ($node instanceof PropertyAssignNode) {
4718+
$hookImpurePoints[] = new ImpurePoint(
4719+
$scope,
4720+
$node,
4721+
'propertyAssign',
4722+
'property assignment',
4723+
true,
4724+
);
4725+
return;
4726+
}
4727+
if ($node instanceof ExecutionEndNode) {
4728+
$executionEnds[] = $node;
4729+
return;
4730+
}
4731+
if (!$node instanceof Return_) {
4732+
return;
4733+
}
4734+
4735+
$gatheredReturnStatements[] = new ReturnStatement($scope, $node);
4736+
}, StatementContext::createTopLevel());
4737+
4738+
$nodeCallback(new PropertyHookReturnStatementsNode(
4739+
$hook,
4740+
$gatheredReturnStatements,
4741+
$statementResult,
4742+
$executionEnds,
4743+
array_merge($statementResult->getImpurePoints(), $methodImpurePoints),
4744+
$classReflection,
4745+
$hookReflection,
4746+
), $hookScope);
47064747
}
47074748

47084749
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Node;
4+
5+
use PhpParser\Node\PropertyHook;
6+
use PhpParser\NodeAbstract;
7+
use PHPStan\Analyser\ImpurePoint;
8+
use PHPStan\Analyser\StatementResult;
9+
use PHPStan\Reflection\ClassReflection;
10+
use PHPStan\Reflection\Php\PhpMethodFromParserNodeReflection;
11+
12+
/**
13+
* @api
14+
*/
15+
final class PropertyHookReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode
16+
{
17+
18+
/**
19+
* @param list<ReturnStatement> $returnStatements
20+
* @param list<ExecutionEndNode> $executionEnds
21+
* @param ImpurePoint[] $impurePoints
22+
*/
23+
public function __construct(
24+
private PropertyHook $hook,
25+
private array $returnStatements,
26+
private StatementResult $statementResult,
27+
private array $executionEnds,
28+
private array $impurePoints,
29+
private ClassReflection $classReflection,
30+
private PhpMethodFromParserNodeReflection $hookReflection,
31+
)
32+
{
33+
parent::__construct($hook->getAttributes());
34+
}
35+
36+
public function getPropertyHookNode(): PropertyHook
37+
{
38+
return $this->hook;
39+
}
40+
41+
public function returnsByRef(): bool
42+
{
43+
return $this->hook->byRef;
44+
}
45+
46+
public function hasNativeReturnTypehint(): bool
47+
{
48+
return false;
49+
}
50+
51+
public function getYieldStatements(): array
52+
{
53+
return [];
54+
}
55+
56+
public function isGenerator(): bool
57+
{
58+
return false;
59+
}
60+
61+
public function getReturnStatements(): array
62+
{
63+
return $this->returnStatements;
64+
}
65+
66+
public function getStatementResult(): StatementResult
67+
{
68+
return $this->statementResult;
69+
}
70+
71+
public function getExecutionEnds(): array
72+
{
73+
return $this->executionEnds;
74+
}
75+
76+
public function getImpurePoints(): array
77+
{
78+
return $this->impurePoints;
79+
}
80+
81+
public function getClassReflection(): ClassReflection
82+
{
83+
return $this->classReflection;
84+
}
85+
86+
public function getHookReflection(): PhpMethodFromParserNodeReflection
87+
{
88+
return $this->hookReflection;
89+
}
90+
91+
public function getType(): string
92+
{
93+
return 'PHPStan_Node_PropertyHookReturnStatementsNode';
94+
}
95+
96+
/**
97+
* @return string[]
98+
*/
99+
public function getSubNodeNames(): array
100+
{
101+
return [];
102+
}
103+
104+
}

0 commit comments

Comments
 (0)