Пример #1
0
 /**
  * Perform some backwards compatibility checks on a node
  *
  * @param Context $context
  * The context in which the node appears
  *
  * @param Node $node
  * The node we'd like to check
  *
  * @return null
  *
  * @see \Phan\Deprecated::bc_check
  * Formerly `function bc_check`
  */
 public static function backwardCompatibilityCheck(Context $context, Node $node)
 {
     if (empty($node->children['expr'])) {
         return;
     }
     if ($node->kind !== \ast\AST_DIM) {
         if (!$node->children['expr'] instanceof Node) {
             return;
         }
         if ($node->children['expr']->kind !== \ast\AST_DIM) {
             AST::backwardCompatibilityCheck($context, $node->children['expr']);
             return;
         }
         $temp = $node->children['expr']->children['expr'];
         $lnode = $temp;
     } else {
         $temp = $node->children['expr'];
         $lnode = $temp;
     }
     if (!($temp->kind == \ast\AST_PROP || $temp->kind == \ast\AST_STATIC_PROP)) {
         return;
     }
     while ($temp instanceof Node && ($temp->kind == \ast\AST_PROP || $temp->kind == \ast\AST_STATIC_PROP)) {
         $lnode = $temp;
         // Lets just hope the 0th is the expression
         // we want
         $temp = array_values($temp->children)[0];
     }
     if (!$temp instanceof Node) {
         return;
     }
     // Foo::$bar['baz'](); is a problem
     // Foo::$bar['baz'] is not
     if ($lnode->kind === \ast\AST_STATIC_PROP && $node->kind !== \ast\AST_CALL) {
         return;
     }
     if (($lnode->children['prop'] instanceof Node && $lnode->children['prop']->kind == \ast\AST_VAR || !empty($lnode->children['class']) && $lnode->children['class'] instanceof Node && ($lnode->children['class']->kind == \ast\AST_VAR || $lnode->children['class']->kind == \ast\AST_NAME)) && ($temp->kind == \ast\AST_VAR || $temp->kind == \ast\AST_NAME)) {
         $ftemp = new \SplFileObject($context->getFile());
         $ftemp->seek($node->lineno - 1);
         $line = $ftemp->current();
         unset($ftemp);
         if (strpos($line, '}[') === false || strpos($line, ']}') === false || strpos($line, '>{') === false) {
             Log::err(Log::ECOMPAT, "expression may not be PHP 7 compatible", $context->getFile(), $node->lineno ?? 0);
         }
     }
 }
Пример #2
0
 /**
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitCall(Node $node) : Context
 {
     $expression = $node->children['expr'];
     if (Config::get()->backward_compatibility_checks) {
         AST::backwardCompatibilityCheck($this->context, $node);
         foreach ($node->children['args']->children as $arg_node) {
             if ($arg_node instanceof Node) {
                 AST::backwardCompatibilityCheck($this->context, $arg_node);
             }
         }
     }
     if ($expression->kind == \ast\AST_NAME) {
         try {
             $method = AST::functionFromNameInContext($expression->children['name'], $this->context, $this->code_base);
         } catch (CodeBaseException $exception) {
             Log::err(Log::EUNDEF, $exception->getMessage(), $this->context->getFile(), $node->lineno);
             return $this->context;
         }
         // Check the call for paraemter and argument types
         $this->analyzeCallToMethod($this->code_base, $method, $node);
     } else {
         if ($expression->kind == \ast\AST_VAR) {
             $variable_name = AST::variableName($expression);
             if (empty($variable_name)) {
                 return $this->context;
             }
             // $var() - hopefully a closure, otherwise we don't know
             if ($this->context->getScope()->hasVariableWithName($variable_name)) {
                 $variable = $this->context->getScope()->getVariableWithName($variable_name);
                 $union_type = $variable->getUnionType();
                 if ($union_type->isEmpty()) {
                     return $this->context;
                 }
                 $type = $union_type->head();
                 if (!$type instanceof CallableType) {
                     return $this->context;
                 }
                 $closure_fqsen = FullyQualifiedFunctionName::fromFullyQualifiedString((string) $type->asFQSEN());
                 if ($this->code_base->hasMethod($closure_fqsen)) {
                     // Get the closure
                     $method = $this->code_base->getMethod($closure_fqsen);
                     // Check the call for paraemter and argument types
                     $this->analyzeCallToMethod($this->code_base, $method, $node);
                 }
             }
         }
     }
     return $this->context;
 }
Пример #3
0
 /**
  * Visit a node with kind `\ast\AST_RETURN`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitReturn(Node $node) : Context
 {
     if (Config::get()->backward_compatibility_checks) {
         AST::backwardCompatibilityCheck($this->context, $node);
     }
     return $this->context;
 }