1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Decomplicate method

This commit is contained in:
Matt Brown 2021-02-24 00:03:55 -05:00
parent fe9eb6d91e
commit 7958ef6889

View File

@ -26,6 +26,7 @@ use function explode;
use function strpos; use function strpos;
use function strlen; use function strlen;
use function substr; use function substr;
use function in_array;
class ExistingAtomicStaticCallAnalyzer class ExistingAtomicStaticCallAnalyzer
{ {
@ -220,118 +221,20 @@ class ExistingAtomicStaticCallAnalyzer
} }
if (!$return_type_candidate) { if (!$return_type_candidate) {
$return_type_candidate = $codebase->methods->getMethodReturnType( $return_type_candidate = self::getMethodReturnType(
$method_id,
$self_fq_class_name,
$statements_analyzer, $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, $codebase,
$return_type_candidate, $stmt,
null, $method_id,
null, $args,
null
);
TemplateInferredTypeReplacer::replace(
$return_type_candidate,
$template_result, $template_result,
$codebase
);
}
$return_type_candidate = \Psalm\Internal\Type\TypeExpander::expandUnion(
$codebase,
$return_type_candidate,
$self_fq_class_name, $self_fq_class_name,
$static_type, $lhs_type_part,
$class_storage->parent_class, $context,
true, $fq_class_name,
false, $class_storage,
\is_string($static_type) $config
&& ($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); $method_storage = $codebase->methods->getUserMethodStorage($method_id);
@ -544,4 +447,139 @@ class ExistingAtomicStaticCallAnalyzer
} }
} }
} }
/**
* @param list<PhpParser\Node\Arg> $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;
}
} }