Example #1
0
 /**
  * @param Node $node
  * A node to parse
  *
  * @return void
  */
 public function visitClosure(Decl $node)
 {
     try {
         $method = (new ContextNode($this->code_base, $this->context->withLineNumberStart($node->lineno ?? 0), $node))->getClosure();
         $method->addReference($this->context);
     } catch (\Exception $exception) {
         // Swallow it
     }
 }
Example #2
0
 /**
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitAssign(Node $node) : Context
 {
     // Get the type of the right side of the
     // assignment
     $right_type = UnionType::fromNode($this->context, $this->code_base, $node->children['expr']);
     assert($node->children['var'] instanceof Node, "Expected left side of assignment to be a var in {$this->context}");
     // Handle the assignment based on the type of the
     // right side of the equation and the kind of item
     // on the left
     $context = (new AssignmentVisitor($this->code_base, $this->context, $node, $right_type))($node->children['var']);
     // Analyze the assignment for compatibility with some
     // breaking changes betweeen PHP5 and PHP7.
     (new ContextNode($this->code_base, $this->context, $node))->analyzeBackwardCompatibility();
     if ($node->children['expr'] instanceof Node && $node->children['expr']->kind == \ast\AST_CLOSURE) {
         $closure_node = $node->children['expr'];
         $method = (new ContextNode($this->code_base, $this->context->withLineNumberStart($closure_node->lineno ?? 0), $closure_node))->getClosure();
         $method->addReference($this->context);
     }
     return $context;
 }
Example #3
0
 /**
  * @param CodeBase $code_base
  * A code base needs to be passed in because we require
  * it to be initialized before any classes or files are
  * loaded.
  *
  * @param Context $context
  * The context in which this node exists
  *
  * @param Node $node
  * A node to parse and scan for errors
  *
  * @return Context
  * The context from within the node is returned
  */
 public static function analyzeNodeInContext(CodeBase $code_base, Context $context, Node $node, Node $parent_node = null, int $depth = 0) : Context
 {
     // 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
     $node_context = (new PreOrderAnalysisVisitor($code_base, $context->withLineNumberStart($node->lineno ?? 0)))($node);
     assert(!empty($context), 'Context cannot be null');
     // We collect all child context so that the
     // PostOrderAnalysisVisitor can optionally operate on
     // them
     $child_context_list = [];
     $child_context = $node_context;
     // 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.
         if (!$child_node instanceof Node) {
             continue;
         }
         if (!self::shouldVisit($child_node)) {
             $child_context->withLineNumberStart($child_node->lineno ?? 0);
             continue;
         }
         // All nodes but conditionals pass context to
         // their siblings. Child nodes of conditionals
         // operate in a context independent of eachother
         switch ($child_node->kind) {
             case \ast\AST_IF_ELEM:
                 $child_context = $node_context;
                 break;
         }
         // Step into each child node and get an
         // updated context for the node
         $child_context = self::analyzeNodeInContext($code_base, $child_context->withLineNumberStart($child_node->lineno ?? 0), $child_node, $node, $depth + 1);
         $child_context_list[] = $child_context;
     }
     // For if statements, we need to merge the contexts
     // of all child context into a single scope based
     // on any possible branching structure
     $node_context = (new ContextMergeVisitor($code_base, $node_context, $child_context_list))($node);
     // Now that we know all about our context (like what
     // 'self' means), we can analyze statements like
     // assignments and method calls.
     $node_context = (new PostOrderAnalysisVisitor($code_base, $node_context->withLineNumberStart($node->lineno ?? 0), $parent_node))($node);
     // When coming out of a scoped element, we pop the
     // context to be the incoming context. Otherwise,
     // we pass our new context up to our parent
     switch ($node->kind) {
         case \ast\AST_CLASS:
         case \ast\AST_METHOD:
         case \ast\AST_FUNC_DECL:
         case \ast\AST_CLOSURE:
             return $context;
         default:
             return $node_context;
     }
 }
Example #4
0
 /**
  * @param Node $node
  * A node to parse and scan for errors
  *
  * @param Context $context
  * The context in which this node exists
  *
  * @return Context
  * The context from within the node is returned
  */
 public function analyzeNodeInContext(Node $node, Context $context, CodeBase $code_base, Node $parent_node = null, int $depth = 0) : Context
 {
     // 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
     $child_context = (new Element($node))->acceptKindVisitor(new DepthFirstVisitor($context->withLineNumberStart($node->lineno ?? 0)->withLineNumberEnd($node->endLineno ?? 0), $code_base));
     assert(!empty($context), 'Context cannot be null');
     // Go depth first on that first set of analyses
     foreach ($node->children ?? [] as $child_node) {
         // Skip any non Node children.
         if (!$child_node instanceof Node) {
             continue;
         }
         // Step into each child node and get an
         // updated context for the node
         $child_context = $this->analyzeNodeInContext($child_node, $child_context->withLineNumberStart($child_node->lineno ?? 0)->withLineNumberEnd($child_node->endLineno ?? 0), $code_base, $node, $depth + 1);
     }
     $context = (new Element($node))->acceptKindVisitor(new BreadthFirstVisitor($context->withLineNumberStart($node->lineno ?? 0)->withLineNumberEnd($node->endLineno ?? 0), $code_base, $parent_node));
     // Pass the context back up to our parent
     return $context;
 }