mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Decomplicate method
This commit is contained in:
parent
fe9eb6d91e
commit
7958ef6889
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user