diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index ebb599d056..275ebd2acd 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5,7 +5,6 @@ use ArrayAccess; use Closure; use IteratorAggregate; -use Override; use PhpParser\Comment\Doc; use PhpParser\Modifiers; use PhpParser\Node; @@ -49,7 +48,6 @@ use PhpParser\Node\Stmt\While_; use PhpParser\NodeFinder; use PhpParser\NodeTraverser; -use PhpParser\NodeVisitorAbstract; use PHPStan\Analyser\ExprHandler\AssignHandler; use PHPStan\Analyser\ExprHandler\Helper\ImplicitToStringCallHelper; use PHPStan\Analyser\ExprHandler\Helper\MethodThrowPointHelper; @@ -73,7 +71,6 @@ use PHPStan\Node\ClassPropertyNode; use PHPStan\Node\ClassStatementsGatherer; use PHPStan\Node\ClosureReturnStatementsNode; -use PHPStan\Node\DeepNodeCloner; use PHPStan\Node\DoWhileLoopConditionNode; use PHPStan\Node\ExecutionEndNode; use PHPStan\Node\Expr\ExistingArrayDimFetch; @@ -259,7 +256,6 @@ public function __construct( #[AutowiredExtensions(of: StaticMethodParameterClosureTypeExtension::class)] private readonly ExtensionsCollection $staticMethodParameterClosureTypeExtensions, private readonly ScopeFactory $scopeFactory, - private readonly DeepNodeCloner $deepNodeCloner, #[AutowiredParameter] private readonly bool $polluteScopeWithLoopInitialAssignments, #[AutowiredParameter] @@ -2406,25 +2402,21 @@ public function processStmtNode( )); } - $clonedVar = $this->deepNodeCloner->cloneNode($var->var); - $traverser = new NodeTraverser(); - $traverser->addVisitor(new class () extends NodeVisitorAbstract { - - #[Override] - public function leaveNode(Node $node): ?ExistingArrayDimFetch - { - if (!$node instanceof ArrayDimFetch || $node->dim === null) { - return null; - } - - return new ExistingArrayDimFetch($node->var, $node->dim); + // wrap the already-processed chain in ExistingArrayDimFetch nodes + // referencing the original sub-expressions - the unset statement's + // own walk already processed them, and the assign target + // preparation prices the chain without re-walking it + $buildExistingChain = static function (Expr $node) use (&$buildExistingChain): Expr { + if (!$node instanceof ArrayDimFetch || $node->dim === null) { + return $node; } - }); - - /** @var Expr $clonedVar */ - [$clonedVar] = $traverser->traverse([$clonedVar]); - $scope = $this->processVirtualAssign($scope, $storage, $stmt, $clonedVar, new UnsetOffsetExpr($var->var, $var->dim), $nodeCallback)->getScope(); + return new ExistingArrayDimFetch( + $buildExistingChain($node->var), + $node->dim, + ); + }; + $scope = $this->processVirtualAssign($scope, $storage, $stmt, $buildExistingChain($var->var), new UnsetOffsetExpr($var->var, $var->dim), $nodeCallback)->getScope(); } elseif ($var instanceof PropertyFetch) { $scope = $scope->invalidateExpression($var); $impurePoints[] = new ImpurePoint( diff --git a/src/Node/DeepNodeCloner.php b/src/Node/DeepNodeCloner.php deleted file mode 100644 index 8372bfd018..0000000000 --- a/src/Node/DeepNodeCloner.php +++ /dev/null @@ -1,29 +0,0 @@ -traverse([$node]); - - /** @var T */ - return $clonedNode; - } - -} diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 04f550f51b..d070726072 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -24,7 +24,6 @@ use PHPStan\File\FileHelper; use PHPStan\File\FileReader; use PHPStan\Fixable\Patcher; -use PHPStan\Node\DeepNodeCloner; use PHPStan\PhpDoc\PhpDocInheritanceResolver; use PHPStan\Reflection\ClassReflectionFactory; use PHPStan\Reflection\InitializerExprTypeResolver; @@ -122,7 +121,6 @@ protected function createNodeScopeResolver(): NodeScopeResolver self::getContainer()->getExtensionsCollection(MethodParameterClosureTypeExtension::class), self::getContainer()->getExtensionsCollection(StaticMethodParameterClosureTypeExtension::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), - self::getContainer()->getByType(DeepNodeCloner::class), $this->shouldPolluteScopeWithLoopInitialAssignments(), $this->shouldPolluteScopeWithAlwaysIterableForeach(), self::getContainer()->getParameter('polluteScopeWithBlock'), diff --git a/src/Testing/TypeInferenceTestCase.php b/src/Testing/TypeInferenceTestCase.php index 13e9a907da..f19adc7dbe 100644 --- a/src/Testing/TypeInferenceTestCase.php +++ b/src/Testing/TypeInferenceTestCase.php @@ -15,7 +15,6 @@ use PHPStan\Analyser\ScopeContext; use PHPStan\File\FileHelper; use PHPStan\File\SystemAgnosticSimpleRelativePathHelper; -use PHPStan\Node\DeepNodeCloner; use PHPStan\Node\InClassNode; use PHPStan\PhpDoc\PhpDocInheritanceResolver; use PHPStan\PhpDoc\TypeStringResolver; @@ -97,7 +96,6 @@ protected static function createNodeScopeResolver(): NodeScopeResolver $container->getExtensionsCollection(MethodParameterClosureTypeExtension::class), $container->getExtensionsCollection(StaticMethodParameterClosureTypeExtension::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), - self::getContainer()->getByType(DeepNodeCloner::class), $container->getParameter('polluteScopeWithLoopInitialAssignments'), $container->getParameter('polluteScopeWithAlwaysIterableForeach'), $container->getParameter('polluteScopeWithBlock'), diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index 04417b7ab9..586aa79133 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -14,7 +14,6 @@ use PHPStan\Dependency\ExportedNodeResolver; use PHPStan\Dependency\PackageDependencyResolver; use PHPStan\DependencyInjection\DirectExtensionsCollection; -use PHPStan\Node\DeepNodeCloner; use PHPStan\Node\Printer\ExprPrinter; use PHPStan\Node\Printer\Printer; use PHPStan\Parser\RichParser; @@ -838,7 +837,6 @@ private function createAnalyser(): Analyser $container->getExtensionsCollection(MethodParameterClosureTypeExtension::class), $container->getExtensionsCollection(StaticMethodParameterClosureTypeExtension::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), - $container->getByType(DeepNodeCloner::class), false, true, true, diff --git a/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverRuleTest.php b/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverRuleTest.php index c9732b873d..88d4aae93e 100644 --- a/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverRuleTest.php +++ b/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverRuleTest.php @@ -9,7 +9,6 @@ use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\DirectExtensionsCollection; use PHPStan\File\FileHelper; -use PHPStan\Node\DeepNodeCloner; use PHPStan\PhpDoc\PhpDocInheritanceResolver; use PHPStan\Reflection\ClassReflectionFactory; use PHPStan\Reflection\InitializerExprTypeResolver; @@ -142,7 +141,6 @@ protected function createNodeScopeResolver(): NodeScopeResolver self::getContainer()->getExtensionsCollection(MethodParameterClosureTypeExtension::class), self::getContainer()->getExtensionsCollection(StaticMethodParameterClosureTypeExtension::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), - self::getContainer()->getByType(DeepNodeCloner::class), $this->shouldPolluteScopeWithLoopInitialAssignments(), $this->shouldPolluteScopeWithAlwaysIterableForeach(), self::getContainer()->getParameter('polluteScopeWithBlock'), diff --git a/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverTest.php b/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverTest.php index 00038bbc18..bfaac47349 100644 --- a/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverTest.php @@ -6,7 +6,6 @@ use PHPStan\Analyser\ExprHandler\Helper\ImplicitToStringCallHelper; use PHPStan\Analyser\NodeScopeResolver; use PHPStan\File\FileHelper; -use PHPStan\Node\DeepNodeCloner; use PHPStan\PhpDoc\PhpDocInheritanceResolver; use PHPStan\Reflection\ClassReflectionFactory; use PHPStan\Reflection\InitializerExprTypeResolver; @@ -75,7 +74,6 @@ protected static function createNodeScopeResolver(): NodeScopeResolver $container->getExtensionsCollection(MethodParameterClosureTypeExtension::class), $container->getExtensionsCollection(StaticMethodParameterClosureTypeExtension::class), self::createScopeFactory($reflectionProvider, $typeSpecifier), - $container->getByType(DeepNodeCloner::class), $container->getParameter('polluteScopeWithLoopInitialAssignments'), $container->getParameter('polluteScopeWithAlwaysIterableForeach'), $container->getParameter('polluteScopeWithBlock'),