Skip to content

Commit

Permalink
Decomplicate method
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Feb 24, 2021
1 parent fe9eb6d commit 7958ef6
Showing 1 changed file with 147 additions and 109 deletions.
Expand Up @@ -26,6 +26,7 @@
use function strpos;
use function strlen;
use function substr;
use function in_array;

class ExistingAtomicStaticCallAnalyzer
{
Expand Down Expand Up @@ -220,118 +221,20 @@ public static function analyze(
}

if (!$return_type_candidate) {
$return_type_candidate = $codebase->methods->getMethodReturnType(
$return_type_candidate = self::getMethodReturnType(
$statements_analyzer,
$codebase,
$stmt,
$method_id,
$args,
$template_result,
$self_fq_class_name,
$statements_analyzer,
$args
$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);
Expand Down Expand Up @@ -544,4 +447,139 @@ function (Assertion $assertion) use ($generic_params) : Assertion {
}
}
}

/**
* @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;
}
}

0 comments on commit 7958ef6

Please sign in to comment.