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 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<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