diff --git a/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php b/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php index 7a1d3dcd52..bf9d69b4a8 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php +++ b/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php @@ -87,6 +87,7 @@ use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\NodeScopeResolver; use PHPStan\Analyser\ScopeContext; +use PHPStan\Node\Expr\AlwaysRememberedExpr; use PHPStan\Node\FunctionCallableNode; use PHPStan\Node\InstantiationCallableNode; use PHPStan\Node\MethodCallableNode; @@ -163,10 +164,13 @@ public function processNodes( $scope = $formerMutatingScope ?? $this->scopeFactory->createFromFile($filePath); $hasUnreachableStatementNode = false; + $hasAlwaysRememberedExpr = false; + $nodeCallback = function (Node $node, MutatingScope $mutatingScope) use ( &$nodeCallback, $filePath, - &$hasUnreachableStatementNode + &$hasUnreachableStatementNode, + &$hasAlwaysRememberedExpr ): void { // the class reflection is resolved AFTER entering to class node // so we need to get it from the first after this one @@ -198,6 +202,8 @@ public function processNodes( // do not return early, as its properties will be checked next if (! $node instanceof VirtualNode) { $node->setAttribute(AttributeKey::SCOPE, $mutatingScope); + } elseif ($node instanceof AlwaysRememberedExpr) { + $hasAlwaysRememberedExpr = true; } if ($node instanceof FileWithoutNamespace) { @@ -411,8 +417,15 @@ public function processNodes( RectorNodeScopeResolver::processNodes($stmts, $scope); } + if (! $hasAlwaysRememberedExpr && ! $hasUnreachableStatementNode) { + return $stmts; + } + $nodeTraverser = new NodeTraverser(); - $nodeTraverser->addVisitor(new WrappedNodeRestoringNodeVisitor()); + + if ($hasAlwaysRememberedExpr) { + $nodeTraverser->addVisitor(new WrappedNodeRestoringNodeVisitor()); + } if ($hasUnreachableStatementNode) { $nodeTraverser->addVisitor(new UnreachableStatementNodeVisitor($this, $filePath, $scope));