/** * @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 visitNew(Node $node) : string { // Things of the form `new $class_name();` if ($node->children['class']->kind == \ast\AST_VAR) { return ''; } // Anonymous class // $v = new class { ... } if ($node->children['class']->kind == \ast\AST_CLASS && $node->children['class']->flags & \ast\flags\CLASS_ANONYMOUS) { return AST::unqualifiedNameForAnonymousClassNode($node->children['class'], $this->context); } // Things of the form `new $method->name()` if ($node->children['class']->kind !== \ast\AST_NAME) { return ''; } $class_name = $node->children['class']->children['name']; if (!in_array($class_name, ['self', 'static', 'parent'])) { return (string) UnionTypeVisitor::unionTypeFromClassNode($this->code_base, $this->context, $node->children['class']); } if (!$this->context->isInClassScope()) { Log::err(Log::ESTATIC, "Cannot access {$class_name}:: when no class scope is active", $this->context->getFile(), $node->lineno); return ''; } if ($class_name == 'static') { return (string) $this->context->getClassFQSEN(); } if ($class_name == 'self') { if ($this->context->isGlobalScope()) { assert(false, "Unimplemented branch is required for {$this->context}"); } else { return (string) $this->context->getClassFQSEN(); } } if ($class_name == 'parent') { $clazz = $this->context->getClassInScope($this->code_base); if (!$clazz->hasParentClassFQSEN()) { return ''; } return (string) $clazz->getParentClassFQSEN(); } return ''; }