Skip to content

Commit

Permalink
Check for circular references with stubbed classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrolGenhald committed Dec 9, 2021
1 parent 115fa9d commit aac3656
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 78 deletions.
102 changes: 25 additions & 77 deletions src/Psalm/Internal/Codebase/Populator.php
Expand Up @@ -92,22 +92,6 @@ public function populateCodebase(): void
$this->populateClassLikeStorage($class_storage);
}

// After loading new classes, go over existing classes with
// invalid dependencies to see if any of those have been loaded
foreach ($this->classlike_storage_provider->getAll() as $class_storage) {
foreach ($class_storage->invalid_dependencies as $dependency => $dependency_type) {
if ($this->populateDataFromDependency(
$class_storage,
$this->classlike_storage_provider,
[], // TODO
$dependency,
$dependency_type
)) {
unset($class_storage->invalid_dependencies[$dependency]);
}
}
}

$this->progress->debug('ClassLikeStorage is populated' . "\n");

$this->progress->debug('FileStorage is populating' . "\n");
Expand Down Expand Up @@ -309,7 +293,21 @@ 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
)
);
}

continue;
}

$dependency->populated = false;
unset($dependency->invalid_dependencies[$fq_classlike_name_lc]);
$this->populateClassLikeStorage($dependency, $dependent_classlikes);
}

Expand Down Expand Up @@ -468,54 +466,12 @@ private function populateOverriddenMethods(
}
}

/**
* @param "implemented_interface"|"parent_interface"|"trait"|"parent_class" $dependency_type
*/
private function populateDataFromDependency(
ClassLikeStorage $storage,
ClassLikeStorageProvider $storage_provider,
array $dependent_classlikes,
string $dependency,
string $dependency_type
): bool {
switch ($dependency_type) {
case "implemented_interface":
return $this->populateDataFromImplementedInterface(
$storage,
$storage_provider,
$dependent_classlikes,
$dependency
);
case "parent_interface":
return $this->populateInterfaceDataFromParentInterface(
$storage,
$storage_provider,
$dependent_classlikes,
$dependency
);
case "trait":
return $this->populateDataFromTrait(
$storage,
$storage_provider,
$dependent_classlikes,
$dependency
);
case "parent_class":
return $this->populateDataFromParentClass(
$storage,
$storage_provider,
$dependent_classlikes,
$dependency
);
}
}

private function populateDataFromTrait(
ClassLikeStorage $storage,
ClassLikeStorageProvider $storage_provider,
array $dependent_classlikes,
string $used_trait_lc
): bool {
): void {
try {
$used_trait_lc = strtolower(
$this->classlikes->getUnAliasedName(
Expand All @@ -524,7 +480,7 @@ private function populateDataFromTrait(
);
$trait_storage = $storage_provider->get($used_trait_lc);
} catch (InvalidArgumentException $e) {
return false;
return;
}

$this->populateClassLikeStorage($trait_storage, $dependent_classlikes);
Expand Down Expand Up @@ -577,8 +533,6 @@ private function populateDataFromTrait(
$storage->pseudo_property_set_types += $trait_storage->pseudo_property_set_types;

$storage->pseudo_methods += $trait_storage->pseudo_methods;

return true;
}

private static function extendType(
Expand Down Expand Up @@ -617,7 +571,7 @@ private function populateDataFromParentClass(
ClassLikeStorageProvider $storage_provider,
array $dependent_classlikes,
string $parent_storage_class,
): bool {
): void {
$parent_storage_class = strtolower(
$this->classlikes->getUnAliasedName(
$parent_storage_class
Expand All @@ -629,11 +583,11 @@ private function populateDataFromParentClass(
} catch (InvalidArgumentException $e) {
$this->progress->debug('Populator could not find dependency (' . __LINE__ . ")\n");

$storage->invalid_dependencies[$parent_storage_class] = "parent_class";
$storage->invalid_dependencies[$parent_storage_class] = true;

$this->invalid_class_storages[$parent_storage_class][] = $storage;

return false;
return;
}

$this->populateClassLikeStorage($parent_storage, $dependent_classlikes);
Expand Down Expand Up @@ -735,8 +689,6 @@ function ($constant) {
$parent_storage->dependent_classlikes[strtolower($storage->name)] = true;

$storage->pseudo_methods += $parent_storage->pseudo_methods;

return true;
}

private function populateInterfaceData(
Expand Down Expand Up @@ -827,7 +779,7 @@ private function populateInterfaceDataFromParentInterface(
ClassLikeStorageProvider $storage_provider,
array $dependent_classlikes,
string $parent_interface_lc
): bool {
): void {
try {
$parent_interface_lc = strtolower(
$this->classlikes->getUnAliasedName(
Expand All @@ -838,8 +790,8 @@ private function populateInterfaceDataFromParentInterface(
} catch (InvalidArgumentException $e) {
$this->progress->debug('Populator could not find dependency (' . __LINE__ . ")\n");

$storage->invalid_dependencies[$parent_interface_lc] = "parent_interface";
return false;
$storage->invalid_dependencies[$parent_interface_lc] = true;
return;
}

$this->populateInterfaceData($storage, $parent_interface_storage, $storage_provider, $dependent_classlikes);
Expand All @@ -852,16 +804,14 @@ private function populateInterfaceDataFromParentInterface(
$parent_interface_storage->parent_interfaces,
$storage->parent_interfaces
);

return true;
}

private function populateDataFromImplementedInterface(
ClassLikeStorage $storage,
ClassLikeStorageProvider $storage_provider,
array $dependent_classlikes,
string $implemented_interface_lc
): bool {
): void {
try {
$implemented_interface_lc = strtolower(
$this->classlikes->getUnAliasedName(
Expand All @@ -872,8 +822,8 @@ private function populateDataFromImplementedInterface(
} catch (InvalidArgumentException $e) {
$this->progress->debug('Populator could not find dependency (' . __LINE__ . ")\n");

$storage->invalid_dependencies[$implemented_interface_lc] = "implemented_interface";
return false;
$storage->invalid_dependencies[$implemented_interface_lc] = true;
return;
}

$this->populateInterfaceData(
Expand All @@ -887,8 +837,6 @@ private function populateDataFromImplementedInterface(
$storage->class_implements,
$implemented_interface_storage->parent_interfaces
);

return true;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Psalm/Storage/ClassLikeStorage.php
Expand Up @@ -373,7 +373,7 @@ class ClassLikeStorage
public $initialized_properties = [];

/**
* @var array<string, "implemented_interface"|"parent_interface"|"trait"|"parent_class">
* @var array<string, true>
*/
public $invalid_dependencies = [];

Expand Down

0 comments on commit aac3656

Please sign in to comment.