From ae169c9cbe7a4eb45dac11183c9e6c8045377ccf Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Tue, 14 Dec 2021 17:07:49 -0600 Subject: [PATCH] Check for indirect circular dependencies with stubbed parents. --- src/Psalm/Internal/Codebase/Populator.php | 32 ++++++++++++------- tests/StubTest.php | 4 +-- .../fixtures/stubs/CircularReference.phpstub | 2 ++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/Psalm/Internal/Codebase/Populator.php b/src/Psalm/Internal/Codebase/Populator.php index 136dad383af..a09e538b465 100644 --- a/src/Psalm/Internal/Codebase/Populator.php +++ b/src/Psalm/Internal/Codebase/Populator.php @@ -19,8 +19,10 @@ use function array_intersect_key; use function array_keys; use function array_merge; +use function array_splice; use function count; use function in_array; +use function key; use function reset; use function strlen; use function strpos; @@ -293,18 +295,26 @@ private function populateClassLikeStorage(ClassLikeStorage $storage, array $depe if (isset($this->invalid_class_storages[$fq_classlike_name_lc])) { foreach ($this->invalid_class_storages[$fq_classlike_name_lc] as $dependency) { - if (isset($dependency->dependent_classlikes[$fq_classlike_name_lc])) { - if ($dependency->location) { - IssueBuffer::maybeAdd( - new CircularReference( - 'Circular reference discovered when loading ' . $dependency->name, - $dependency->location - ) - ); - } + // Dependencies may not be fully set yet, so we have to loop through dependencies of dependencies + $dependencies = [strtolower($dependency->name) => true]; + do { + $current_dependency_name = key(array_splice($dependencies, 0, 1)); // Key shift + $current_dependency = $storage_provider->get($current_dependency_name); + $dependencies += $current_dependency->dependent_classlikes; + + if (isset($current_dependency->dependent_classlikes[$fq_classlike_name_lc])) { + if ($dependency->location) { + IssueBuffer::maybeAdd( + new CircularReference( + 'Circular reference discovered when loading ' . $dependency->name, + $dependency->location + ) + ); + } - continue; - } + continue 2; + } + } while (!empty($dependencies)); $dependency->populated = false; unset($dependency->invalid_dependencies[$fq_classlike_name_lc]); diff --git a/tests/StubTest.php b/tests/StubTest.php index cb513ee7f79..199205f1f6a 100644 --- a/tests/StubTest.php +++ b/tests/StubTest.php @@ -280,9 +280,7 @@ public function testStubFileCircularReference(): void $this->addFile( $file_path, '