From 8425c9090832424c6c93638af5c71592151e92d6 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 20 Apr 2023 20:46:07 +0700 Subject: [PATCH] [Php56][Php70] Handle infinite loop on TernaryToNullCoalescingRector+AddDefaultValueForUndefinedVariableRector (#3639) * reproduce hang * Closes https://github.com/rectorphp/rector/issues/7889 * clean up * [ci-review] Rector Rectify --------- Co-authored-by: GitHub Action --- .../NodeTypeResolver/NodeTypeResolver.php | 2 ++ .../UndefinedVariableResolver.php | 8 ++--- .../Fixture/fixture.php.inc | 29 +++++++++++++++++++ .../TernaryCoalesceDefaultTest.php | 28 ++++++++++++++++++ .../config/configured_rule.php | 13 +++++++++ 5 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tests/Issues/TernaryCoalesceDefault/Fixture/fixture.php.inc create mode 100644 tests/Issues/TernaryCoalesceDefault/TernaryCoalesceDefaultTest.php create mode 100644 tests/Issues/TernaryCoalesceDefault/config/configured_rule.php diff --git a/packages/NodeTypeResolver/NodeTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver.php index aad6d4824bc..af0483cefc7 100644 --- a/packages/NodeTypeResolver/NodeTypeResolver.php +++ b/packages/NodeTypeResolver/NodeTypeResolver.php @@ -350,11 +350,13 @@ private function isObjectTypeOfObjectType(ObjectType $resolvedObjectType, Object if (! $this->reflectionProvider->hasClass($requiredClassName)) { return false; } + $requiredClassReflection = $this->reflectionProvider->getClass($requiredClassName); if (! $this->reflectionProvider->hasClass($resolvedClassName)) { return false; } + $resolvedClassReflection = $this->reflectionProvider->getClass($resolvedClassName); if ($requiredClassReflection->isTrait()) { diff --git a/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php b/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php index 495fd444fe7..b68ef68c19c 100644 --- a/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php +++ b/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php @@ -142,19 +142,19 @@ private function isAssign(Node $parentNode): bool private function shouldSkipVariable(Variable $variable, Node $parentNode): bool { - if ($this->variableAnalyzer->isStaticOrGlobal($variable)) { + if ($this->isAsCoalesceLeftOrAssignOpCoalesceVar($parentNode, $variable)) { return true; } - if ($this->isAssign($parentNode)) { + if ($this->variableAnalyzer->isStaticOrGlobal($variable)) { return true; } - if ($this->issetOrUnsetOrEmptyParent($parentNode)) { + if ($this->isAssign($parentNode)) { return true; } - if ($this->isAsCoalesceLeftOrAssignOpCoalesceVar($parentNode, $variable)) { + if ($this->issetOrUnsetOrEmptyParent($parentNode)) { return true; } diff --git a/tests/Issues/TernaryCoalesceDefault/Fixture/fixture.php.inc b/tests/Issues/TernaryCoalesceDefault/Fixture/fixture.php.inc new file mode 100644 index 00000000000..4cc8e307c6c --- /dev/null +++ b/tests/Issues/TernaryCoalesceDefault/Fixture/fixture.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/tests/Issues/TernaryCoalesceDefault/TernaryCoalesceDefaultTest.php b/tests/Issues/TernaryCoalesceDefault/TernaryCoalesceDefaultTest.php new file mode 100644 index 00000000000..426098805e7 --- /dev/null +++ b/tests/Issues/TernaryCoalesceDefault/TernaryCoalesceDefaultTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/tests/Issues/TernaryCoalesceDefault/config/configured_rule.php b/tests/Issues/TernaryCoalesceDefault/config/configured_rule.php new file mode 100644 index 00000000000..209659ef2df --- /dev/null +++ b/tests/Issues/TernaryCoalesceDefault/config/configured_rule.php @@ -0,0 +1,13 @@ +rules([ + TernaryToNullCoalescingRector::class, + AddDefaultValueForUndefinedVariableRector::class, + ]); +};