From b0fac9956781fc0cef325e9bb9286273a9157397 Mon Sep 17 00:00:00 2001 From: ondrejmirtes <104888+ondrejmirtes@users.noreply.github.com> Date: Thu, 12 Feb 2026 19:32:13 +0000 Subject: [PATCH 01/12] Resolve method reflection for $var::method() static calls - When $expr->class is an Expr (variable), resolve method reflection and parameters acceptor using getObjectTypeOrClassStringObjectType() so by-reference parameters and other argument analysis work correctly - Guard $this invalidation and constructor property initialization blocks with $expr->class instanceof Name to prevent $other::__construct() from incorrectly affecting $this - New regression test in tests/PHPStan/Analyser/nsrt/bug-5020.php --- src/Analyser/NodeScopeResolver.php | 21 ++++++++++ tests/PHPStan/Analyser/nsrt/bug-5020.php | 52 ++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-5020.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index bb361d5615..9d8188a36b 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3381,6 +3381,25 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto foreach ($additionalThrowPoints as $throwPoint) { $throwPoints[] = $throwPoint; } + + if ($expr->name instanceof Identifier && $methodReflection === null) { + $staticMethodCalledOnType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); + $methodName = $expr->name->name; + if ($staticMethodCalledOnType->hasMethod($methodName)->yes()) { + $methodReflection = $staticMethodCalledOnType->getMethod($methodName, $scope); + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $scope, + $expr->getArgs(), + $methodReflection->getVariants(), + $methodReflection->getNamedArgumentsVariants(), + ); + + $methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope); + if ($methodThrowPoint !== null) { + $throwPoints[] = $methodThrowPoint; + } + } + } } if ($methodReflection !== null) { @@ -3410,6 +3429,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto if ( $methodReflection !== null + && $expr->class instanceof Name && ( ( !$methodReflection->isStatic() @@ -3425,6 +3445,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto if ( $methodReflection !== null + && $expr->class instanceof Name && !$methodReflection->isStatic() && $methodReflection->getName() === '__construct' && $scopeFunction instanceof MethodReflection diff --git a/tests/PHPStan/Analyser/nsrt/bug-5020.php b/tests/PHPStan/Analyser/nsrt/bug-5020.php new file mode 100644 index 0000000000..cefd581368 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-5020.php @@ -0,0 +1,52 @@ + $transformer */ + $transformer = 'Bug5020\Transformer'; + $input = ' asdasda asdasd '; + $error = false; + $output = $transformer::Transform($input, $error); + assertType('string', $output); + assertType('bool', $error); +} From 601e4ac1f165452cada9c58cae4b079a08e66497 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 19:39:52 +0100 Subject: [PATCH 02/12] de-duplicate --- src/Analyser/NodeScopeResolver.php | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 9d8188a36b..34e0a9eb3e 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3296,7 +3296,9 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } $parametersAcceptor = null; + $classType = null; $methodReflection = null; + $methodName = null; if ($expr->name instanceof Expr) { $result = $this->processExprNode($stmt, $expr->name, $scope, $storage, $nodeCallback, $context->enterDeep()); $hasYield = $hasYield || $result->hasYield(); @@ -3306,6 +3308,12 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } elseif ($expr->class instanceof Name) { $classType = $scope->resolveTypeByName($expr->class); $methodName = $expr->name->name; + } elseif ($expr->class instanceof Expr && $expr->name instanceof Identifier) { + $classType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); + $methodName = $expr->name->name; + } + + if ($classType !== null && $methodName !== null) { if ($classType->hasMethod($methodName)->yes()) { $methodReflection = $classType->getMethod($methodName, $scope); $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( @@ -3381,25 +3389,6 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto foreach ($additionalThrowPoints as $throwPoint) { $throwPoints[] = $throwPoint; } - - if ($expr->name instanceof Identifier && $methodReflection === null) { - $staticMethodCalledOnType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); - $methodName = $expr->name->name; - if ($staticMethodCalledOnType->hasMethod($methodName)->yes()) { - $methodReflection = $staticMethodCalledOnType->getMethod($methodName, $scope); - $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( - $scope, - $expr->getArgs(), - $methodReflection->getVariants(), - $methodReflection->getNamedArgumentsVariants(), - ); - - $methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope); - if ($methodThrowPoint !== null) { - $throwPoints[] = $methodThrowPoint; - } - } - } } if ($methodReflection !== null) { From eab5b45d016397e0e7eaa654dc9234c0897a9956 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 19:44:15 +0100 Subject: [PATCH 03/12] Update NodeScopeResolver.php --- src/Analyser/NodeScopeResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 34e0a9eb3e..9f25f35de0 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3308,7 +3308,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } elseif ($expr->class instanceof Name) { $classType = $scope->resolveTypeByName($expr->class); $methodName = $expr->name->name; - } elseif ($expr->class instanceof Expr && $expr->name instanceof Identifier) { + } elseif ($expr->class instanceof Expr) { $classType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); $methodName = $expr->name->name; } From 48601a3d7c1f8855d2321829413e66bf477b6b50 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 19:46:57 +0100 Subject: [PATCH 04/12] Update NodeScopeResolver.php --- src/Analyser/NodeScopeResolver.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 9f25f35de0..9e84d2a5ff 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3375,22 +3375,6 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } } - if ($expr->class instanceof Expr) { - $objectClasses = $scope->getType($expr->class)->getObjectClassNames(); - if (count($objectClasses) !== 1) { - $objectClasses = $scope->getType(new New_($expr->class))->getObjectClassNames(); - } - if (count($objectClasses) === 1) { - $objectExprResult = $this->processExprNode($stmt, new StaticCall(new Name($objectClasses[0]), $expr->name, []), $scope, $storage, new NoopNodeCallback(), $context->enterDeep()); - $additionalThrowPoints = $objectExprResult->getThrowPoints(); - } else { - $additionalThrowPoints = [InternalThrowPoint::createImplicit($scope, $expr)]; - } - foreach ($additionalThrowPoints as $throwPoint) { - $throwPoints[] = $throwPoint; - } - } - if ($methodReflection !== null) { $impurePoint = SimpleImpurePoint::createFromVariant($methodReflection, $parametersAcceptor, $scope, $expr->getArgs()); if ($impurePoint !== null) { From cf3c807bec3aa4c6f9216668f88df970997f26e0 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 20:04:57 +0100 Subject: [PATCH 05/12] Update CallToStaticMethodStatementWithoutSideEffectsRuleTest.php --- .../CallToStaticMethodStatementWithoutSideEffectsRuleTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php index f9e047e295..bb9822d0ff 100644 --- a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php @@ -42,6 +42,10 @@ public function testRulePhp7(): void 'Call to static method DateTimeImmutable::createFromFormat() on a separate line has no effect.', 12, ], + [ + 'Call to static method DateTimeImmutable::createFromFormat() on a separate line has no effect.', + 13, + ], [ 'Call to method DateTime::format() on a separate line has no effect.', 23, From a3990fc4fa44e4a9d2e08e0c0ac3a0ecc8feb10a Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 21:39:00 +0100 Subject: [PATCH 06/12] Revert "Update CallToStaticMethodStatementWithoutSideEffectsRuleTest.php" This reverts commit cf3c807bec3aa4c6f9216668f88df970997f26e0. --- .../CallToStaticMethodStatementWithoutSideEffectsRuleTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php index bb9822d0ff..f9e047e295 100644 --- a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php @@ -42,10 +42,6 @@ public function testRulePhp7(): void 'Call to static method DateTimeImmutable::createFromFormat() on a separate line has no effect.', 12, ], - [ - 'Call to static method DateTimeImmutable::createFromFormat() on a separate line has no effect.', - 13, - ], [ 'Call to method DateTime::format() on a separate line has no effect.', 23, From 7f4485f22ff3229afe6d5192757cd270bdf4ae9e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 21:39:04 +0100 Subject: [PATCH 07/12] Revert "Update NodeScopeResolver.php" This reverts commit 48601a3d7c1f8855d2321829413e66bf477b6b50. --- src/Analyser/NodeScopeResolver.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 9e84d2a5ff..9f25f35de0 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3375,6 +3375,22 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } } + if ($expr->class instanceof Expr) { + $objectClasses = $scope->getType($expr->class)->getObjectClassNames(); + if (count($objectClasses) !== 1) { + $objectClasses = $scope->getType(new New_($expr->class))->getObjectClassNames(); + } + if (count($objectClasses) === 1) { + $objectExprResult = $this->processExprNode($stmt, new StaticCall(new Name($objectClasses[0]), $expr->name, []), $scope, $storage, new NoopNodeCallback(), $context->enterDeep()); + $additionalThrowPoints = $objectExprResult->getThrowPoints(); + } else { + $additionalThrowPoints = [InternalThrowPoint::createImplicit($scope, $expr)]; + } + foreach ($additionalThrowPoints as $throwPoint) { + $throwPoints[] = $throwPoint; + } + } + if ($methodReflection !== null) { $impurePoint = SimpleImpurePoint::createFromVariant($methodReflection, $parametersAcceptor, $scope, $expr->getArgs()); if ($impurePoint !== null) { From 9f4d18d76714742457441cb015389ddc598ff172 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 22:04:02 +0100 Subject: [PATCH 08/12] Update NodeScopeResolver.php --- src/Analyser/NodeScopeResolver.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 9f25f35de0..438259c863 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3299,6 +3299,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $classType = null; $methodReflection = null; $methodName = null; + $dynamicCall = false; if ($expr->name instanceof Expr) { $result = $this->processExprNode($stmt, $expr->name, $scope, $storage, $nodeCallback, $context->enterDeep()); $hasYield = $hasYield || $result->hasYield(); @@ -3311,6 +3312,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } elseif ($expr->class instanceof Expr) { $classType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); $methodName = $expr->name->name; + $dynamicCall = true; } if ($classType !== null && $methodName !== null) { @@ -3323,9 +3325,11 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $methodReflection->getNamedArgumentsVariants(), ); - $methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope); - if ($methodThrowPoint !== null) { - $throwPoints[] = $methodThrowPoint; + if (!$dynamicCall) { + $methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope); + if ($methodThrowPoint !== null) { + $throwPoints[] = $methodThrowPoint; + } } $declaringClass = $methodReflection->getDeclaringClass(); From f7d0e437cec2b69529e883cf34d4b250c61e2fce Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 22:16:09 +0100 Subject: [PATCH 09/12] Update NodeScopeResolver.php --- src/Analyser/NodeScopeResolver.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 438259c863..8b493d5cbf 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3299,7 +3299,6 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $classType = null; $methodReflection = null; $methodName = null; - $dynamicCall = false; if ($expr->name instanceof Expr) { $result = $this->processExprNode($stmt, $expr->name, $scope, $storage, $nodeCallback, $context->enterDeep()); $hasYield = $hasYield || $result->hasYield(); @@ -3312,7 +3311,6 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto } elseif ($expr->class instanceof Expr) { $classType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); $methodName = $expr->name->name; - $dynamicCall = true; } if ($classType !== null && $methodName !== null) { @@ -3325,7 +3323,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $methodReflection->getNamedArgumentsVariants(), ); - if (!$dynamicCall) { + if (!$expr->class instanceof Expr) { $methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope); if ($methodThrowPoint !== null) { $throwPoints[] = $methodThrowPoint; From a297b6a00301b22054baab8ab3461bd072aa15b1 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 22:26:35 +0100 Subject: [PATCH 10/12] Update static-method-call-statement-no-side-effects.php --- .../data/static-method-call-statement-no-side-effects.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Methods/data/static-method-call-statement-no-side-effects.php b/tests/PHPStan/Rules/Methods/data/static-method-call-statement-no-side-effects.php index 9c4e984e42..8a21b6f47a 100644 --- a/tests/PHPStan/Rules/Methods/data/static-method-call-statement-no-side-effects.php +++ b/tests/PHPStan/Rules/Methods/data/static-method-call-statement-no-side-effects.php @@ -10,7 +10,7 @@ class Foo public function doFoo(\DateTimeImmutable $dt) { DateTimeImmutable::createFromFormat('Y-m-d', '2019-07-24'); - $dt::createFromFormat('Y-m-d', '2019-07-24'); + $dt::createFromFormat('Y-m-d', '2019-07-24'); // method might be impure in DateTimeImmutable subclass } } From 4d24433b56bbc864bd0797a9a05a38fd4203bad5 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 23:00:35 +0100 Subject: [PATCH 11/12] lsb --- src/Analyser/MutatingScope.php | 12 ++++++++++++ src/Analyser/NodeScopeResolver.php | 10 ++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 8bdf7894e6..0e2cfb9e52 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1921,6 +1921,18 @@ public function resolveTypeByName(Name $name): TypeWithClassName return new ObjectType($originalClass); } + public function resolveStaticCallWithLateStaticBinding(Expr\StaticCall $expr): ?TypeWithClassName + { + $objectClasses = TypeCombinator::removeNull($this->getType($expr->class))->getObjectTypeOrClassStringObjectType()->getObjectClassNames(); + if (count($objectClasses) !== 1) { + return null; + } + if (!$expr->name instanceof Identifier) { + return null; + } + return $this->resolveTypeByNameWithLateStaticBinding(new Name($objectClasses[0]), $expr->name); + } + private function resolveTypeByNameWithLateStaticBinding(Name $class, Node\Identifier $name): TypeWithClassName { $classType = $this->resolveTypeByName($class); diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 8b493d5cbf..d927ffc978 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3309,7 +3309,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $classType = $scope->resolveTypeByName($expr->class); $methodName = $expr->name->name; } elseif ($expr->class instanceof Expr) { - $classType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType(); + $classType = $scope->resolveStaticCallWithLateStaticBinding($expr); $methodName = $expr->name->name; } @@ -3323,11 +3323,9 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $methodReflection->getNamedArgumentsVariants(), ); - if (!$expr->class instanceof Expr) { - $methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope); - if ($methodThrowPoint !== null) { - $throwPoints[] = $methodThrowPoint; - } + $methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope); + if ($methodThrowPoint !== null) { + $throwPoints[] = $methodThrowPoint; } $declaringClass = $methodReflection->getDeclaringClass(); From 02f124778f246d801416b749c6514df461cf72c2 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 19 Feb 2026 23:08:24 +0100 Subject: [PATCH 12/12] simplify --- src/Analyser/MutatingScope.php | 14 +------------- src/Analyser/NodeScopeResolver.php | 7 +++++-- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 0e2cfb9e52..69ab471021 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1921,19 +1921,7 @@ public function resolveTypeByName(Name $name): TypeWithClassName return new ObjectType($originalClass); } - public function resolveStaticCallWithLateStaticBinding(Expr\StaticCall $expr): ?TypeWithClassName - { - $objectClasses = TypeCombinator::removeNull($this->getType($expr->class))->getObjectTypeOrClassStringObjectType()->getObjectClassNames(); - if (count($objectClasses) !== 1) { - return null; - } - if (!$expr->name instanceof Identifier) { - return null; - } - return $this->resolveTypeByNameWithLateStaticBinding(new Name($objectClasses[0]), $expr->name); - } - - private function resolveTypeByNameWithLateStaticBinding(Name $class, Node\Identifier $name): TypeWithClassName + public function resolveTypeByNameWithLateStaticBinding(Name $class, Node\Identifier $name): TypeWithClassName { $classType = $this->resolveTypeByName($class); diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index d927ffc978..3c8ccdee17 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3309,8 +3309,11 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto $classType = $scope->resolveTypeByName($expr->class); $methodName = $expr->name->name; } elseif ($expr->class instanceof Expr) { - $classType = $scope->resolveStaticCallWithLateStaticBinding($expr); - $methodName = $expr->name->name; + $objectClasses = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType()->getObjectClassNames(); + if (count($objectClasses) === 1) { + $classType = $scope->resolveTypeByNameWithLateStaticBinding(new Name($objectClasses[0]), $expr->name); + $methodName = $expr->name->name; + } } if ($classType !== null && $methodName !== null) {