public function visit(Node $node) : Context
{
$context = $this->context->withLineNumberStart($node->lineno ?? 0);
// Visit the given node populating the code base
// with anything we learn and get a new context
// indicating the state of the world within the
// given node
$context = (new PreOrderAnalysisVisitor($this->code_base, $context))($node);
assert(!empty($context), 'Context cannot be null');
// With a context that is inside of the node passed
// to this method, we analyze all children of the
// node.
foreach ($node->children ?? [] as $child_node) {
// Skip any non Node children or boring nodes
// that are too deep.
if (!$child_node instanceof Node || !Analysis::shouldVisit($child_node)) {
$context->withLineNumberStart($child_node->lineno ?? 0);
continue;
}
// Step into each child node and get an
// updated context for the node
$context = (new BlockAnalysisVisitor($this->code_base, $context, $node, $this->depth + 1))($child_node);
}
// Now that we know all about our context (like what
// 'self' means), we can analyze statements like
// assignments and method calls.
$context = (new PostOrderAnalysisVisitor($this->code_base, $context->withLineNumberStart($node->lineno ?? 0), $this->parent_node))($node);
// Let any configured plugins analyze the node
ConfigPluginSet::instance()->analyzeNode($this->code_base, $context, $node, $this->parent_node);
return $context;
}