From 7958ef688910d53ba4233ccdb9f79c75fc668f00 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Wed, 24 Feb 2021 00:03:55 -0500 Subject: [PATCH] Decomplicate method --- .../ExistingAtomicStaticCallAnalyzer.php | 258 ++++++++++-------- 1 file changed, 148 insertions(+), 110 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php index d9f3364a2..c8bf71919 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticMethod/ExistingAtomicStaticCallAnalyzer.php @@ -26,6 +26,7 @@ use function explode; use function strpos; use function strlen; use function substr; +use function in_array; class ExistingAtomicStaticCallAnalyzer { @@ -220,118 +221,20 @@ class ExistingAtomicStaticCallAnalyzer } if (!$return_type_candidate) { - $return_type_candidate = $codebase->methods->getMethodReturnType( - $method_id, - $self_fq_class_name, + $return_type_candidate = self::getMethodReturnType( $statements_analyzer, - $args + $codebase, + $stmt, + $method_id, + $args, + $template_result, + $self_fq_class_name, + $lhs_type_part, + $context, + $fq_class_name, + $class_storage, + $config ); - - 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 (!isset( - $template_result->upper_bounds - [$template_type->param_name] - [$template_type->defining_class] - )) { - if ($template_type->param_name === 'TFunctionArgCount') { - $template_result->upper_bounds[$template_type->param_name] = [ - 'fn-' . strtolower((string) $method_id) => new TemplateBound( - Type::getInt(false, count($stmt->args)) - ) - ]; - } elseif ($template_type->param_name === 'TPhpMajorVersion') { - $template_result->upper_bounds[$template_type->param_name] = [ - 'fn-' . strtolower((string) $method_id) => new TemplateBound( - Type::getInt(false, $codebase->php_major_version) - ) - ]; - } else { - $template_result->upper_bounds[$template_type->param_name] = [ - ($template_type->defining_class) => new TemplateBound(Type::getEmpty()) - ]; - } - } - } - } - - if ($lhs_type_part instanceof Type\Atomic\TTemplateParam) { - $static_type = $lhs_type_part; - } elseif ($lhs_type_part instanceof Type\Atomic\TTemplateParamClass) { - $static_type = new Type\Atomic\TTemplateParam( - $lhs_type_part->param_name, - $lhs_type_part->as_type - ? new Type\Union([$lhs_type_part->as_type]) - : Type::getObject(), - $lhs_type_part->defining_class - ); - } elseif ($stmt->class instanceof PhpParser\Node\Name - && count($stmt->class->parts) === 1 - && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true) - && $lhs_type_part instanceof Type\Atomic\TNamedObject - ) { - $static_type = $context->self; - } else { - $static_type = $fq_class_name; - } - - if ($template_result->upper_bounds) { - $return_type_candidate = \Psalm\Internal\Type\TypeExpander::expandUnion( - $codebase, - $return_type_candidate, - null, - null, - null - ); - - TemplateInferredTypeReplacer::replace( - $return_type_candidate, - $template_result, - $codebase - ); - } - - $return_type_candidate = \Psalm\Internal\Type\TypeExpander::expandUnion( - $codebase, - $return_type_candidate, - $self_fq_class_name, - $static_type, - $class_storage->parent_class, - true, - false, - \is_string($static_type) - && ($static_type !== $context->self - || $class_storage->final) - ); - - $return_type_location = $codebase->methods->getMethodReturnTypeLocation( - $method_id, - $secondary_return_type_location - ); - - if ($secondary_return_type_location) { - $return_type_location = $secondary_return_type_location; - } - - // 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, - true, - false, - false, - $context->calling_method_id - ); - } - } } $method_storage = $codebase->methods->getUserMethodStorage($method_id); @@ -544,4 +447,139 @@ class ExistingAtomicStaticCallAnalyzer } } } + + /** + * @param list $args + */ + private static function getMethodReturnType( + StatementsAnalyzer $statements_analyzer, + \Psalm\Codebase $codebase, + PhpParser\Node\Expr\StaticCall $stmt, + MethodIdentifier $method_id, + array $args, + \Psalm\Internal\Type\TemplateResult $template_result, + ?string &$self_fq_class_name, + Type\Atomic $lhs_type_part, + Context $context, + string $fq_class_name, + ClassLikeStorage $class_storage, + \Psalm\Config $config + ): ?Type\Union { + $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 (!isset( + $template_result->upper_bounds + [$template_type->param_name] + [$template_type->defining_class] + )) { + if ($template_type->param_name === 'TFunctionArgCount') { + $template_result->upper_bounds[$template_type->param_name] = [ + 'fn-' . strtolower((string)$method_id) => new TemplateBound( + Type::getInt(false, count($stmt->args)) + ) + ]; + } elseif ($template_type->param_name === 'TPhpMajorVersion') { + $template_result->upper_bounds[$template_type->param_name] = [ + 'fn-' . strtolower((string)$method_id) => new TemplateBound( + Type::getInt(false, $codebase->php_major_version) + ) + ]; + } else { + $template_result->upper_bounds[$template_type->param_name] = [ + ($template_type->defining_class) => new TemplateBound(Type::getEmpty()) + ]; + } + } + } + } + + if ($lhs_type_part instanceof Type\Atomic\TTemplateParam) { + $static_type = $lhs_type_part; + } elseif ($lhs_type_part instanceof Type\Atomic\TTemplateParamClass) { + $static_type = new Type\Atomic\TTemplateParam( + $lhs_type_part->param_name, + $lhs_type_part->as_type + ? new Type\Union([$lhs_type_part->as_type]) + : Type::getObject(), + $lhs_type_part->defining_class + ); + } elseif ($stmt->class instanceof PhpParser\Node\Name + && count($stmt->class->parts) === 1 + && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true) + && $lhs_type_part instanceof Type\Atomic\TNamedObject + ) { + $static_type = $context->self; + } else { + $static_type = $fq_class_name; + } + + if ($template_result->upper_bounds) { + $return_type_candidate = \Psalm\Internal\Type\TypeExpander::expandUnion( + $codebase, + $return_type_candidate, + null, + null, + null + ); + + TemplateInferredTypeReplacer::replace( + $return_type_candidate, + $template_result, + $codebase + ); + } + + $return_type_candidate = \Psalm\Internal\Type\TypeExpander::expandUnion( + $codebase, + $return_type_candidate, + $self_fq_class_name, + $static_type, + $class_storage->parent_class, + true, + false, + \is_string($static_type) + && ($static_type !== $context->self + || $class_storage->final) + ); + + $secondary_return_type_location = null; + + $return_type_location = $codebase->methods->getMethodReturnTypeLocation( + $method_id, + $secondary_return_type_location + ); + + if ($secondary_return_type_location) { + $return_type_location = $secondary_return_type_location; + } + + // 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, + true, + false, + false, + $context->calling_method_id + ); + } + } + + return $return_type_candidate; + } }