1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00

Improve returning

This commit is contained in:
Matthew Brown 2020-03-23 13:23:23 -04:00
parent 4c081f7835
commit ce9eef9ed7

View File

@ -40,8 +40,6 @@ class MethodCallReturnTypeFetcher
$fq_class_name = $method_id->fq_class_name;
$method_name = $method_id->method_name;
$return_type_candidate = null;
if ($codebase->methods->return_type_provider->has($fq_class_name)) {
$return_type_candidate = $codebase->methods->return_type_provider->getReturnType(
$statements_analyzer,
@ -52,9 +50,13 @@ class MethodCallReturnTypeFetcher
new CodeLocation($statements_analyzer->getSource(), $stmt->name),
$lhs_type_part instanceof TGenericObject ? $lhs_type_part->type_params : null
);
if ($return_type_candidate) {
return $return_type_candidate;
}
}
if (!$return_type_candidate && $declaring_method_id && $declaring_method_id !== $method_id) {
if ($declaring_method_id && $declaring_method_id !== $method_id) {
$declaring_fq_class_name = $declaring_method_id->fq_class_name;
$declaring_method_name = $declaring_method_id->method_name;
@ -70,126 +72,130 @@ class MethodCallReturnTypeFetcher
$fq_class_name,
$method_name
);
if ($return_type_candidate) {
return $return_type_candidate;
}
}
}
$return_type_candidate = null;
$class_storage = $codebase->methods->getClassLikeStorageForMethod($method_id);
if (!$return_type_candidate) {
if (CallMap::inCallMap((string) $call_map_id)) {
if (($template_result->generic_params || $class_storage->stubbed)
&& isset($class_storage->methods[$method_id->method_name])
&& ($method_storage = $class_storage->methods[$method_id->method_name])
&& $method_storage->return_type
) {
$return_type_candidate = clone $method_storage->return_type;
if (CallMap::inCallMap((string) $call_map_id)) {
if (($template_result->generic_params || $class_storage->stubbed)
&& isset($class_storage->methods[$method_id->method_name])
&& ($method_storage = $class_storage->methods[$method_id->method_name])
&& $method_storage->return_type
) {
$return_type_candidate = clone $method_storage->return_type;
if ($template_result->generic_params) {
$return_type_candidate->replaceTemplateTypesWithArgTypes(
$template_result->generic_params,
$codebase
);
}
} else {
$callmap_callables = CallMap::getCallablesFromCallMap((string) $call_map_id);
if ($template_result->generic_params) {
$return_type_candidate->replaceTemplateTypesWithArgTypes(
$template_result->generic_params,
$codebase
);
}
} else {
$callmap_callables = CallMap::getCallablesFromCallMap((string) $call_map_id);
if (!$callmap_callables || $callmap_callables[0]->return_type === null) {
throw new \UnexpectedValueException('Shouldnt get here');
}
$return_type_candidate = $callmap_callables[0]->return_type;
if (!$callmap_callables || $callmap_callables[0]->return_type === null) {
throw new \UnexpectedValueException('Shouldnt get here');
}
if ($return_type_candidate->isFalsable()) {
$return_type_candidate->ignore_falsable_issues = true;
$return_type_candidate = $callmap_callables[0]->return_type;
}
if ($return_type_candidate->isFalsable()) {
$return_type_candidate->ignore_falsable_issues = true;
}
$return_type_candidate = ExpressionAnalyzer::fleshOutType(
$codebase,
$return_type_candidate,
$fq_class_name,
$static_type,
$class_storage->parent_class
);
} else {
$self_fq_class_name = $fq_class_name;
$return_type_candidate = $codebase->methods->getMethodReturnType(
$method_id,
$self_fq_class_name,
$statements_analyzer,
$args
);
if ($return_type_candidate) {
$return_type_candidate = clone $return_type_candidate;
if ($template_result->template_types) {
$bindable_template_types = $return_type_candidate->getTemplateTypes();
foreach ($bindable_template_types as $template_type) {
if ($template_type->defining_class !== $fq_class_name
&& !isset(
$template_result->generic_params
[$template_type->param_name]
[$template_type->defining_class]
)
) {
$template_result->generic_params[$template_type->param_name] = [
($template_type->defining_class) => [Type::getEmpty(), 0]
];
}
}
}
if ($template_result->generic_params) {
$return_type_candidate->replaceTemplateTypesWithArgTypes(
$template_result->generic_params,
$codebase
);
}
$return_type_candidate = ExpressionAnalyzer::fleshOutType(
$codebase,
$return_type_candidate,
$fq_class_name,
$self_fq_class_name,
$static_type,
$class_storage->parent_class
);
} else {
$self_fq_class_name = $fq_class_name;
$return_type_candidate = $codebase->methods->getMethodReturnType(
$return_type_candidate->sources = [
new Source(
strtolower((string) $method_id),
$cased_method_id,
new CodeLocation($statements_analyzer, $stmt->name)
)
];
$return_type_location = $codebase->methods->getMethodReturnTypeLocation(
$method_id,
$self_fq_class_name,
$statements_analyzer,
$args
$secondary_return_type_location
);
if ($return_type_candidate) {
$return_type_candidate = clone $return_type_candidate;
if ($template_result->template_types) {
$bindable_template_types = $return_type_candidate->getTemplateTypes();
foreach ($bindable_template_types as $template_type) {
if ($template_type->defining_class !== $fq_class_name
&& !isset(
$template_result->generic_params
[$template_type->param_name]
[$template_type->defining_class]
)
) {
$template_result->generic_params[$template_type->param_name] = [
($template_type->defining_class) => [Type::getEmpty(), 0]
];
}
}
}
if ($template_result->generic_params) {
$return_type_candidate->replaceTemplateTypesWithArgTypes(
$template_result->generic_params,
$codebase
);
}
$return_type_candidate = ExpressionAnalyzer::fleshOutType(
$codebase,
$return_type_candidate,
$self_fq_class_name,
$static_type,
$class_storage->parent_class
);
$return_type_candidate->sources = [
new Source(
strtolower((string) $method_id),
$cased_method_id,
new CodeLocation($statements_analyzer, $stmt->name)
)
];
$return_type_location = $codebase->methods->getMethodReturnTypeLocation(
$method_id,
$secondary_return_type_location
);
if ($secondary_return_type_location) {
$return_type_location = $secondary_return_type_location;
}
$config = \Psalm\Config::getInstance();
// only check the type locally if it's defined externally
if ($return_type_location && !$config->isInProjectDirs($return_type_location->file_path)) {
$return_type_candidate->check(
$statements_analyzer,
new CodeLocation($statements_analyzer, $stmt),
$statements_analyzer->getSuppressedIssues(),
$context->phantom_classes
);
}
} else {
$result->returns_by_ref =
$result->returns_by_ref
|| $codebase->methods->getMethodReturnsByRef($method_id);
if ($secondary_return_type_location) {
$return_type_location = $secondary_return_type_location;
}
$config = \Psalm\Config::getInstance();
// only check the type locally if it's defined externally
if ($return_type_location && !$config->isInProjectDirs($return_type_location->file_path)) {
$return_type_candidate->check(
$statements_analyzer,
new CodeLocation($statements_analyzer, $stmt),
$statements_analyzer->getSuppressedIssues(),
$context->phantom_classes
);
}
} else {
$result->returns_by_ref =
$result->returns_by_ref
|| $codebase->methods->getMethodReturnsByRef($method_id);
}
}