Example #1
0
 /**
  * Analyzes the return-types of the current function and reports errors, if necessary
  *
  * @param PC_Engine_Scope $scope the current scope
  */
 public function analyze($scope)
 {
     $funcname = $scope->get_name_of(T_FUNC_C);
     $classname = $scope->get_name_of(T_CLASS_C);
     $func = $this->env->get_types()->get_method_or_func($classname, $funcname);
     if ($func && !$func->is_abstract()) {
         $hasnull = false;
         $hasother = false;
         foreach ($this->allrettypes as $t) {
             if ($t === null) {
                 $hasnull = true;
             } else {
                 $hasother = true;
             }
         }
         if (count($this->allrettypes) == 0) {
             $mtype = PC_Obj_MultiType::create_void();
         } else {
             $mtype = new PC_Obj_MultiType();
             foreach ($this->allrettypes as $t) {
                 if ($t !== null) {
                     $mtype->merge($t, false);
                 } else {
                     $mtype->merge(PC_Obj_MultiType::create_void(), false);
                 }
             }
         }
         if ($func->is_constructor()) {
             if ($hasother) {
                 $this->report($func, 'The constructor of "' . $classname . '" has a return-statement with expression', PC_Obj_Error::E_S_CONSTR_RETURN);
             }
         } else {
             $name = ($classname ? '#' . $classname . '#::' : '') . $funcname;
             // empty return-expression and non-empty?
             if ($hasnull && $hasother) {
                 $this->report($func, 'The function/method "' . $name . '" has return-' . 'statements without expression and return-statements with expression', PC_Obj_Error::E_S_MIXED_RET_AND_NO_RET);
             }
             $void = new PC_Obj_Type(PC_Obj_Type::VOID);
             $docreturn = $func->has_return_doc() && !$func->get_return_type()->contains($void);
             if ($docreturn && !$hasother) {
                 $this->report($func, 'The function/method "' . $name . '" has a return-specification in PHPDoc' . ', but does not return a value', PC_Obj_Error::E_S_RET_SPEC_BUT_NO_RET);
             } else {
                 if (!$docreturn && !$func->is_anonymous() && $hasother) {
                     $this->report($func, 'The function/method "' . $name . '" has no return-specification in PHPDoc' . ', but does return a value', PC_Obj_Error::E_S_RET_BUT_NO_RET_SPEC);
                 } else {
                     if ($this->has_forbidden($this->allrettypes, $func->get_return_type())) {
                         $this->report($func, 'The return-specification (PHPDoc) of function/method "' . $name . '" does not match with ' . 'the returned values (spec="' . $func->get_return_type() . '", returns="' . $mtype . '")', PC_Obj_Error::E_S_RETURNS_DIFFER_FROM_SPEC);
                     }
                 }
             }
         }
         if ($func->get_return_type()->is_unknown()) {
             $func->set_return_type($mtype);
         }
     }
     $this->allrettypes = array();
 }