/**
* @param Node $node
* A node of the type indicated by the method name that we'd
* like to figure out the type that it produces.
*
* @return string
* The class name represented by the given call
*/
public function visitProp(Node $node) : string
{
if (!($node->children['expr']->kind == \ast\AST_VAR && !$node->children['expr']->children['name'] instanceof Node)) {
return '';
}
// $var->prop->method()
$var = $node->children['expr'];
$class = null;
if ($var->children['name'] == 'this') {
// If we're not in a class scope, 'this' won't work
if (!$this->context->isInClassScope()) {
Log::err(Log::ESTATIC, 'Using $this when not in object context', $this->context->getFile(), $node->lineno);
return '';
}
// $this->$node->method()
if ($node->children['prop'] instanceof Node) {
// Too hard. Giving up.
return '';
}
$class = $this->context->getClassInScope($this->code_base);
} else {
// Get the list of viable class types for the
// variable
$union_type = AST::varUnionType($this->context, $var)->nonNativeTypes()->nonGenericArrayTypes();
if ($union_type->isEmpty()) {
return '';
}
$class_fqsen = $union_type->head()->asFQSEN();
if (!$this->code_base->hasClassWithFQSEN($class_fqsen)) {
return '';
}
$class = $this->code_base->getClassByFQSEN($class_fqsen);
}
$property_name = $node->children['prop'];
if (!$class->hasPropertyWithName($this->code_base, $property_name)) {
// If we can't find the property, there's
// no type. Thie issue should be caught
// elsewhere.
return '';
}
try {
$property = $class->getPropertyByNameInContext($this->code_base, $property_name, $this->context);
} catch (AccessException $exception) {
Log::err(Log::EACCESS, $exception->getMessage(), $this->context->getFile(), $node->lineno);
return '';
}
$union_type = $property->getUnionType()->nonNativeTypes();
if ($union_type->isEmpty()) {
// If we don't have a type on the property we
// can't figure out the class type.
return '';
} else {
// Return the first type on the property
// that could be a reference to a class
return (string) $union_type->head()->asFQSEN();
}
// No such property was found, or none were classes
// that could be found
return '';
}