Phan\Analysis\PostOrderAnalysisVisitor::visitStaticCall PHP Method

visitStaticCall() public method

public visitStaticCall ( ast\Node $node ) : Context
$node ast\Node A node to parse
return Phan\Language\Context A new or an unchanged context resulting from parsing the node
    public function visitStaticCall(Node $node) : Context
    {
        // Get the name of the method being called
        $method_name = $node->children['method'];
        // Give up on things like Class::$var
        if (!is_string($method_name)) {
            return $this->context;
        }
        // Get the name of the static class being referenced
        $static_class = '';
        if ($node->children['class']->kind == \ast\AST_NAME) {
            $static_class = $node->children['class']->children['name'];
        }
        // Short circuit on a constructor being called statically
        // on something other than 'parent'
        if ($method_name === '__construct') {
            if ($static_class !== 'parent') {
                $this->emitIssue(Issue::UndeclaredStaticMethod, $node->lineno ?? 0, "{$static_class}::{$method_name}()");
            }
        }
        try {
            // Get a reference to the method being called
            $method = (new ContextNode($this->code_base, $this->context, $node))->getMethod($method_name, true);
            // Get the method thats calling the static method
            $calling_method = null;
            if ($this->context->isInMethodScope()) {
                $calling_function_like = $this->context->getFunctionLikeInScope($this->code_base);
                if ($calling_function_like instanceof Method) {
                    $calling_method = $calling_function_like;
                }
            }
            // If the method being called isn't actually static and it's
            // not a call to parent::f from f, we may be in trouble.
            if (!$method->isStatic() && !(('parent' === $static_class || 'self' === $static_class || 'static' === $static_class) && $this->context->isInMethodScope() && ($this->context->getFunctionLikeFQSEN()->getName() == $method->getFQSEN()->getName() || $calling_method && !$calling_method->isStatic())) && !($this->context->isInClassScope() && $this->context->isInFunctionLikeScope() && ($calling_method && !$calling_method->isStatic())) && !($this->context->isInClassScope() && $this->context->isInFunctionLikeScope() && $this->context->getFunctionLikeFQSEN()->isClosure())) {
                $class_list = (new ContextNode($this->code_base, $this->context, $node->children['class']))->getClassList();
                if (!empty($class_list)) {
                    $class = array_values($class_list)[0];
                    $this->emitIssue(Issue::StaticCallToNonStatic, $node->lineno ?? 0, "{$class->getFQSEN()}::{$method_name}()", $method->getFileRef()->getFile(), (string) $method->getFileRef()->getLineNumberStart());
                }
            }
            // Make sure the parameters look good
            $this->analyzeCallToMethod($this->code_base, $method, $node);
        } catch (IssueException $exception) {
            Issue::maybeEmitInstance($this->code_base, $this->context, $exception->getIssueInstance());
        } catch (\Exception $exception) {
            // If we can't figure out the class for this method
            // call, cry YOLO and mark every method with that
            // name with a reference.
            if (Config::get()->dead_code_detection && Config::get()->dead_code_detection_prefer_false_negative) {
                foreach ($this->code_base->getMethodSetByName($method_name) as $method) {
                    $method->addReference($this->context);
                }
            }
            // If we can't figure out what kind of a call
            // this is, don't worry about it
            return $this->context;
        }
        return $this->context;
    }