Esempio n. 1
0
 /**
  * Analyzes the given method call
  *
  * @param PC_Obj_Call $call the call
  */
 private function analyze_method_call($call)
 {
     $name = $call->get_function();
     $classname = $call->get_class();
     $c = $this->env->get_types()->get_class($classname);
     if ($c !== null) {
         if (!$c->contains_method($name)) {
             // no obj-creation here because the constructor can be named '__construct' or
             // '<classname>'. the call uses always '__construct'.
             if (!$call->is_object_creation() && !$this->is_method_of_sub($c, $name)) {
                 $this->report($call, 'The method "' . $name . '" does not exist in the class "#' . $classname . '#"!', PC_Obj_Error::E_S_METHOD_MISSING);
             }
         } else {
             if ($call->is_object_creation() && $c->is_abstract()) {
                 $this->report($call, 'You can\'t instantiate the abstract class "#' . $c->get_name() . '#"!', PC_Obj_Error::E_S_ABSTRACT_CLASS_INSTANTIATION);
             } else {
                 // check for static / not static
                 $m = $c->get_method($name);
                 if ($call->is_static() && !$m->is_static()) {
                     $this->report($call, 'Your call "' . $this->get_call_link($call) . '" calls "' . $m->get_name() . '" statically, but the method is not static!', PC_Obj_Error::E_S_STATIC_CALL);
                 } else {
                     if (!$call->is_static() && $m->is_static()) {
                         $this->report($call, 'Your call "' . $this->get_call_link($call) . '" calls "' . $m->get_name() . '" not statically, but the method is static!', PC_Obj_Error::E_S_NONSTATIC_CALL);
                     }
                 }
                 $this->check_params($call, $m);
             }
         }
     } else {
         $this->report($call, 'The class "#' . $classname . '#" does not exist!', PC_Obj_Error::E_S_CLASS_MISSING);
     }
 }
Esempio n. 2
0
 /**
  * Adds a function-call
  * 
  * @param PC_Obj_MultiType $class the class-name (or null)
  * @param PC_Obj_MultiType $func the function-name
  * @param array $args the function-arguments
  * @param bool $static whether its a static call
  * @return PC_Obj_MultiType the result
  */
 public function add_call($class, $func, $args, $static = false)
 {
     if ($class !== null && !$class instanceof PC_Obj_MultiType) {
         return $this->handle_error('$class is invalid');
     }
     if (!$func instanceof PC_Obj_MultiType) {
         return $this->handle_error('$func is invalid');
     }
     if (!is_array($args)) {
         return $this->handle_error('$args is invalid');
     }
     // if we don't know the function- or class-name, we can't do anything here
     $cname = $class !== null ? $class->get_string() : null;
     $fname = $func->get_string();
     if ($fname === null || $class !== null && $cname === null) {
         return $this->create_unknown();
     }
     // create call
     $call = new PC_Obj_Call($this->get_file(), $this->get_line());
     // determine class- and function-name
     $call->set_function($fname);
     // do it manually here because we might not know the method
     $call->set_object_creation(strcasecmp($fname, '__construct') == 0 || strcasecmp($fname, $cname) == 0);
     if ($class !== null) {
         // support for php4 constructors
         if (strcasecmp($cname, $fname) == 0) {
             $call->set_object_creation(true);
         } else {
             if (strcasecmp($cname, 'parent') == 0) {
                 // in this case its no object-creation for us because it would lead to reports like
                 // instantiation of abstract classes when calling the constructor of an abstract
                 // parent-class
                 $call->set_object_creation(false);
                 $cname = $this->scope->get_name_of(T_CLASS_C);
                 $classobj = $this->env->get_types()->get_class($cname);
                 if ($classobj === null || $classobj->get_super_class() == '') {
                     return $this->create_unknown();
                 }
                 $cname = $classobj->get_super_class();
                 // if we're in a static method, the call is always static
                 $curfname = $this->scope->get_name_of(T_FUNC_C);
                 $curfunc = $classobj->get_method($curfname);
                 if ($curfunc === null || $curfunc->is_static()) {
                     $static = true;
                 } else {
                     // if we're in a non-static method, its a static-call if the method we're calling is
                     // static, and not if its not. i.e. we basically don't detect errors here
                     $func = null;
                     $super = $this->env->get_types()->get_class($cname);
                     if ($super !== null) {
                         $func = $super->get_method($fname);
                     }
                     $static = $func !== null && $func->is_static();
                 }
             } else {
                 if (strcasecmp($cname, 'self') == 0) {
                     $cname = $this->scope->get_name_of(T_CLASS_C);
                     // self is static if its not a constructor-call
                     $static = !$call->is_object_creation();
                 }
             }
         }
         $call->set_class($cname);
     }
     // clone because it might be a variable
     foreach ($args as $arg) {
         if (!$arg instanceof PC_Obj_MultiType) {
             $this->handle_error('$arg is invalid');
             continue;
         }
         $call->add_argument(clone $arg);
     }
     $call->set_static($static);
     $this->env->get_types()->add_call($call);
     $funcobj = $this->env->get_types()->get_method_or_func($cname, $fname);
     $this->calls_analyzer->analyze($call);
     $this->modifiers_analyzer->analyze($this->scope, $call, $funcobj);
     if ($funcobj === null) {
         // if it's a constructor, we still know the type
         if ($call->is_object_creation()) {
             return PC_Obj_MultiType::create_object($cname);
         }
         return $this->create_unknown();
     }
     // reference parameters implicitly create variables
     $i = 0;
     foreach ($funcobj->get_params() as $param) {
         if ($i >= count($args)) {
             break;
         }
         // this is a hack: we store the variable name for missing variable names when the variable
         // appears. when detecting calls, we check whether there are reference parameters and then
         // use the name to implicitly create the variable
         if ($param->is_reference() && $args[$i]->get_missing_varname() !== null) {
             $var = new PC_Obj_Variable($this->get_file(), $this->get_line(), $args[$i]->get_missing_varname(), clone $param->get_mtype());
             $this->vars->set($this->scope->get_name(), $var);
             $args[$i]->set_missing_varname(null);
         }
         $i++;
     }
     $this->req_analyzer->analyze($call, $funcobj->get_version()->get_min(), $funcobj->get_version()->get_max());
     // add the throws of the method to our throws
     foreach (array_keys($funcobj->get_throws()) as $tclass) {
         $this->throws_analyzer->add(PC_Obj_Method::THROW_FUNC, PC_Obj_MultiType::create_object($tclass));
     }
     // if its a constructor we know the type directly
     if ($call->is_object_creation()) {
         return PC_Obj_MultiType::create_object($cname);
     }
     return clone $funcobj->get_return_type();
 }
Esempio n. 3
0
 /**
  * Builds the fields to insert for the given call and project
  * 
  * @param PC_Obj_Call $call the call
  * @param PC_Project $project the project
  * @return array an associative array with the fields
  */
 private function build_fields($call, $project)
 {
     $args = serialize($call->get_arguments());
     if (strlen($args) > self::MAX_ARGS_LEN) {
         $arglist = array();
         foreach ($call->get_arguments() as $arg) {
             $arg->clear_values();
             $arglist[] = $arg;
         }
         $args = serialize($arglist);
     }
     return array('project_id' => $project !== null ? $project->get_id() : 0, 'file' => $call->get_file(), 'line' => $call->get_line(), 'function' => $call->get_function(), 'class' => $call->get_class() === null ? null : $call->get_class(), 'static' => $call->is_static() ? 1 : 0, 'objcreation' => $call->is_object_creation() ? 1 : 0, 'arguments' => $args);
 }