public function visitMethodCall(Node $node) : UnionType
{
$method_name = $node->children['method'] ?? '';
// Give up on any complicated nonsense where the
// method name is a variable such as in
// `$variable->$function_name()`.
if ($method_name instanceof Node) {
return new UnionType();
}
// Method names can some times turn up being
// other method calls.
assert(is_string($method_name), "Method name must be a string. Something else given.");
try {
$class_fqsen = null;
foreach ($this->classListFromNode($node->children['class'] ?? $node->children['expr']) as $i => $class) {
$class_fqsen = $class->getFQSEN();
if (!$class->hasMethodWithName($this->code_base, $method_name)) {
continue;
}
try {
$method = $class->getMethodByNameInContext($this->code_base, $method_name, $this->context);
$union_type = $method->getUnionType();
// Map template types to concrete types
if ($union_type->hasTemplateType()) {
// Get the type of the object calling the property
$expression_type = UnionType::fromNode($this->context, $this->code_base, $node->children['expr']);
// Map template types to concrete types
$union_type = $union_type->withTemplateParameterTypeMap($expression_type->getTemplateParameterTypeMap($this->code_base));
}
// Remove any references to \static or \static[]
// once we're talking about the method's return
// type outside of its class
if ($union_type->hasStaticType()) {
$union_type = clone $union_type;
$union_type->removeType(\Phan\Language\Type\StaticType::instance());
}
if ($union_type->genericArrayElementTypes()->hasStaticType()) {
$union_type = clone $union_type;
// Find the static type on the list
$static_type = $union_type->getTypeSet()->find(function (Type $type) : bool {
return $type->isGenericArray() && $type->genericArrayElementType()->isStaticType();
});
// Remove it from the list
$union_type->removeType($static_type);
}
return $union_type;
} catch (IssueException $exception) {
return new UnionType();
}
}
} catch (IssueException $exception) {
// Swallow it
} catch (CodeBaseException $exception) {
$this->emitIssue(Issue::UndeclaredClassMethod, $node->lineno ?? 0, $method_name, (string) $exception->getFQSEN());
}
return new UnionType();
}