예제 #1
0
 public function advance($parser)
 {
     if ($this->pos >= 0) {
         $type = $this->tokens[$this->pos][0];
         switch ($type) {
             case T_FOR:
             case T_FOREACH:
                 $this->start_loop();
                 break;
             case T_DO:
                 $this->ignoreNextWhile = true;
                 $this->start_loop();
                 break;
             case T_WHILE:
                 if (!$this->ignoreNextWhile) {
                     $this->start_loop();
                 }
                 $this->ignoreNextWhile = false;
                 break;
             case T_SWITCH:
             case T_TRY:
                 $this->start_cond();
                 break;
             case T_IF:
                 if (!$this->lastWasElse) {
                     $this->start_cond();
                 } else {
                     // count the number of "T_ELSE T_IF" because for each of those we get another call
                     // to end_cond()
                     $this->vars->set_elseif();
                 }
                 break;
             case T_ELSEIF:
                 $this->start_cond(true, false);
                 break;
             case T_ELSE:
                 $this->start_cond(true, true);
                 break;
         }
         $this->lastWasElse = $type == T_ELSE;
     }
     $res = parent::advance($parser);
     if ($this->lastComment && $this->lastComment != $this->lastCheckComment) {
         // it was a comment, so lets see if it contains a "@var $<name> <type>" that gives us a
         // hint what type a variable has.
         $matches = array();
         if (preg_match('/\\@var\\s+\\$([a-z0-9_]+)\\s+(\\S+)/i', $this->lastComment, $matches)) {
             // do we know that variable?
             $scopename = $this->scope->get_name();
             if ($this->vars->exists($scopename, $matches[1])) {
                 // ok, determine type and set it
                 $type = PC_Obj_MultiType::get_type_by_name($matches[2]);
                 $var = $this->vars->get($scopename, $matches[1]);
                 $var->set_type($type);
             }
         }
         $this->lastCheckComment = $this->lastComment;
     }
     return $res;
 }
예제 #2
0
 public function test_oop()
 {
     list(, $classes, $vars, $calls, $errors) = $this->analyze(self::$code);
     self::assert_equals(0, count($errors));
     $a = $classes['a'];
     /* @var $a PC_Obj_Class */
     self::assert_equals(false, $a->is_abstract());
     self::assert_equals(false, $a->is_interface());
     self::assert_equals(false, $a->is_final());
     self::assert_equals(null, $a->get_super_class());
     self::assert_equals(array(), $a->get_interfaces());
     self::assert_equals((string) PC_Obj_MultiType::create_int(0), (string) $a->get_constant('c')->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_int(4), (string) $a->get_constant('ME')->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_string('str'), (string) $a->get_constant('YOU')->get_type());
     self::assert_equals((string) new PC_Obj_Field('', 0, 'f', PC_Obj_MultiType::create_string('abc'), PC_Obj_Field::V_PRIVATE), (string) $a->get_field('f'));
     self::assert_equals((string) new PC_Obj_Field('', 0, 'foo', PC_Obj_MultiType::get_type_by_name('int|string'), PC_Obj_Field::V_PRIVATE), (string) $a->get_field('foo'));
     self::assert_equals((string) new PC_Obj_Field('', 0, 'bar', PC_Obj_MultiType::get_type_by_name('int|string'), PC_Obj_Field::V_PRIVATE), (string) $a->get_field('bar'));
     self::assert_equals((string) new PC_Obj_Field('', 0, 'a', PC_Obj_MultiType::create_string(), PC_Obj_Field::V_PRIVATE), (string) $a->get_field('a'));
     self::assert_equals((string) new PC_Obj_Field('', 0, 'b', PC_Obj_MultiType::create_string('a'), PC_Obj_Field::V_PRIVATE), (string) $a->get_field('b'));
     $array = PC_Obj_MultiType::create_array(array());
     $array->get_first()->set_array_type(0, PC_Obj_MultiType::create_int(1));
     $array->get_first()->set_array_type(1, PC_Obj_MultiType::create_int(2));
     $array->get_first()->set_array_type(2, PC_Obj_MultiType::create_int(3));
     self::assert_equals((string) new PC_Obj_Field('', 0, 'p', $array, PC_Obj_Field::V_PROTECTED), (string) $a->get_field('p'));
     self::assert_equals('public function __construct()', (string) $a->get_method('__construct'));
     self::assert_equals('protected function test(): void', (string) $a->get_method('test'));
     self::assert_equals('public function test2(a): a', (string) $a->get_method('test2'));
     $b = $classes['b'];
     /* @var $b PC_Obj_Class */
     self::assert_equals(true, $b->is_abstract());
     self::assert_equals(false, $b->is_interface());
     self::assert_equals(false, $b->is_final());
     self::assert_equals('a', $b->get_super_class());
     self::assert_equals(array('i', 'j'), $b->get_interfaces());
     self::assert_equals((string) PC_Obj_MultiType::create_int(0), (string) $b->get_constant('c')->get_type());
     self::assert_equals(null, $b->get_field('f'));
     self::assert_equals((string) new PC_Obj_Field('', 0, 'p', $array, PC_Obj_Field::V_PROTECTED), (string) $b->get_field('p'));
     $i = $classes['i'];
     /* @var $i PC_Obj_Class */
     self::assert_equals(true, $i->is_abstract());
     self::assert_equals(true, $i->is_interface());
     self::assert_equals(false, $i->is_final());
     self::assert_equals(array('i1', 'i2'), $i->get_interfaces());
     self::assert_equals('public abstract function doSomething(): string', (string) $i->get_method('doSomething'));
     $x = $classes['x'];
     /* @var $x PC_Obj_Class */
     self::assert_equals(false, $x->is_abstract());
     self::assert_equals(false, $x->is_interface());
     self::assert_equals(true, $x->is_final());
     self::assert_equals('b', $x->get_super_class());
     self::assert_equals(array('i'), $x->get_interfaces());
     self::assert_equals('public function doSomething(): string', (string) $x->get_method('doSomething'));
     self::assert_equals('public function test2(b): b', (string) $x->get_method('test2'));
     self::assert_equals('public static function mystatic(): void', (string) $x->get_method('mystatic'));
     $field = new PC_Obj_Field('', 0, 'var', PC_Obj_MultiType::create_int(4), PC_Obj_Field::V_PRIVATE);
     $field->set_static(true);
     self::assert_equals((string) $field, (string) $x->get_field('var'));
     $global = $vars[PC_Obj_Variable::SCOPE_GLOBAL];
     self::assert_equals((string) PC_Obj_MultiType::create_int(0), (string) $global['a']->get_type());
     self::assert_equals('a', (string) $global['b']->get_type());
     self::assert_equals('a', (string) $global['c']->get_type());
     self::assert_equals('x', (string) $global['d']->get_type());
     self::assert_equals('b', (string) $global['e']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_int(4), (string) $global['f']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_int(1), (string) $global['g']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_int(4), (string) $global['h']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_object('b'), (string) $global['i']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_int(), (string) $global['j']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_string(), (string) $global['n']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_int(95), (string) $global['o']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_object('a'), (string) $global['q']->get_type());
     self::assert_equals((string) PC_Obj_MultiType::create_object('b'), (string) $global['r']->get_type());
     // check calls
     $i = 0;
     self::assert_equals((string) $calls[$i++], 'strstr(integer=4, string=str)');
     self::assert_call($calls[$i++], 'b', 'get42', true);
     self::assert_call($calls[$i++], 'a', 'test', false);
     self::assert_equals((string) $calls[$i++], 'dummy(integer=2)');
     self::assert_equals((string) $calls[$i++], 'dummy(integer=3)');
     self::assert_equals((string) $calls[$i++], 'dummy(integer=6)');
     self::assert_equals((string) $calls[$i++], 'dummy(unknown)');
     self::assert_equals((string) $calls[$i++], 'dummy(unknown)');
     self::assert_call($calls[$i++], 'a', '__construct', false);
     self::assert_call($calls[$i++], 'a', 'test2', false);
     self::assert_call($calls[$i++], 'x', '__construct', false);
     self::assert_call($calls[$i++], 'x', 'test2', false);
     self::assert_call($calls[$i++], 'x', 'test2', false);
     self::assert_call($calls[$i++], 'b', 'test2', false);
     self::assert_call($calls[$i++], 'b', 'sdf', true);
     self::assert_call($calls[$i++], 'x', 'partest', false);
     self::assert_call($calls[$i++], 'a', '__construct', false);
     self::assert_call($calls[$i++], 'x', '__construct', false);
     self::assert_call($calls[$i++], 'a', 'test2', false);
     self::assert_call($calls[$i++], 'x', 'test2', false);
 }
예제 #3
0
 /**
  * Parses the given method-phpdoc
  *
  * @param PC_Obj_Method $func the method to which the phpdoc belongs
  */
 public function parse_method_doc($func)
 {
     if (isset($this->funcComments[$func->get_name()])) {
         $doc = $this->funcComments[$func->get_name()];
         // look for params
         $matches = array();
         preg_match_all('/\\@param\\s+([^\\s]+)\\s+(&)?\\s*([^\\s]+)/', $doc, $matches);
         foreach ($matches[1] as $k => $match) {
             $param = substr($matches[3][$k], 1);
             // does the param exist?
             if (($fp = $func->get_param($param)) !== null) {
                 $mtype = PC_Obj_MultiType::get_type_by_name($match);
                 $fptype = $fp->get_mtype();
                 $isref = $matches[2][$k] != '';
                 // don't report that if we only know the type from the default value
                 if ($fp->is_reference() != $isref || !$fp->is_mtype_default() && !$fptype->is_unknown() && !$fptype->equals($mtype)) {
                     $docstr = ($isref ? '&' : '') . $mtype;
                     $this->report_error('PHPDoc (' . $docstr . ') does not match the parameter $' . $param . ' (' . $fp . ')', PC_Obj_Error::E_T_PARAM_DIFFERS_FROM_DOC, $func->get_line());
                 }
                 $fp->set_mtype($mtype);
                 $fp->set_has_doc(true);
             } else {
                 $this->report_error('Found PHPDoc for parameter "' . $param . '" (' . $match . '),' . ' but the parameter does not exist', PC_Obj_Error::E_T_DOC_WITHOUT_PARAM, $func->get_line());
             }
         }
         // look for throws
         preg_match_all('/\\@throws\\s+([^\\s]+)/', $doc, $matches);
         foreach ($matches[1] as $k => $match) {
             $func->add_throw($match, PC_Obj_Method::THROW_SELF);
         }
         // look for return-type
         if (preg_match('/\\@return\\s+&?\\s*([^\\s]+)/', $doc, $matches)) {
             $mtype = PC_Obj_MultiType::get_type_by_name($matches[1]);
             if ($mtype !== null) {
                 $rettype = $func->get_return_type();
                 if ($rettype && !$rettype->is_unknown() && !$rettype->equals($mtype)) {
                     $this->report_error('PHPDoc (' . $mtype . ') does not match the return type (' . $rettype . ')', PC_Obj_Error::E_T_RETURN_DIFFERS_FROM_DOC, $func->get_line());
                 }
                 if (!$rettype || $rettype->is_unknown()) {
                     $func->set_return_type($mtype);
                 }
                 $func->set_has_return_doc(true);
             }
         }
         unset($this->funcComments[$func->get_name()]);
     }
 }
예제 #4
0
 /**
  * Determines the multi-type from given type-name and default-value
  * 
  * @param string $type the type-name
  * @param string $default the default-value
  * @return PC_Obj_MultiType the multitype
  */
 private static function get_param_type($type, $default = null)
 {
     $type = trim($type);
     // "callback" is a pseudo-type that may be an array (with classname and funcname) or
     // a string (the funcname)
     if (strcasecmp($type, 'callback') == 0) {
         return new PC_Obj_MultiType(array(new PC_Obj_Type(PC_Obj_Type::TARRAY), new PC_Obj_Type(PC_Obj_Type::STRING)));
     }
     $otype = PC_Obj_MultiType::get_type_by_name(trim($type));
     if (!$otype->is_unknown() && !$otype->is_multiple() && $default !== null && strcasecmp($default, 'null') != 0) {
         if ($default == 'array()') {
             $otype->get_first()->set_value(array());
         } else {
             $otype->get_first()->set_value($default);
         }
     }
     return $otype;
 }