Пример #1
0
 public function __ToString()
 {
     $str = $this->visibility . ' ' . ($this->static ? 'static ' : '') . $this->get_name();
     if (!$this->type->is_unknown()) {
         $str .= '[' . $this->type . ']';
     }
     return $str;
 }
Пример #2
0
 function yy_r446()
 {
     $this->_retvalue = PC_Obj_MultiType::create_array(array());
     $this->_retvalue->get_first()->set_array_type($this->yystack[$this->yyidx + 0]->minor['key'], $this->yystack[$this->yyidx + 0]->minor['val'], $this->yystack[$this->yyidx + 0]->minor['append']);
 }
Пример #3
0
 /**
  * Determines the article for the given type ('a' or 'an'), depending on the first char
  * 
  * @param PC_Obj_MultiType $type the type
  * @return string the article
  */
 private function get_article($type)
 {
     $str = $type === null ? 'x' : $type->__ToString();
     return isset($str[0]) && in_array(strtolower($str[0]), array('i', 'a', 'o', 'u', 'e')) ? 'an' : 'a';
 }
Пример #4
0
    public function test_special()
    {
        $code = '<?php
$u = `foo`;

// we can even say the type/value of variable variables if we can figure out the variable name ^^
$v = "u";
$w = ${$v};
$x = ${"unknown var"};
$y = ${123};

// array-union works when all values are known
$z = array("a" => 1,"c" => 123,"d" => 5) + array("a" => 2,"b" => 4);
$aa = array(array($_,1)) + array(2);
// comparison is just bool
$ab = array(1) === array(1);
$ac = array(1,"2") == array(1,2);
$ad = array(1) <> array($_);

$ba = 1 ? 0 : 2;
$bb = 4 ? "bla" : "blub";
$bc = $_ ? 1 : 2;
$bd = $_ ? "foo" : 1;
$be = (1) ? ((2) ? "a" : "b") : "c";
$bf = 1 ?: -1;
$bg = "f" ?: "g";
?>';
        list(, , $vars, , $errors) = $this->analyze($code);
        self::assert_equals(0, count($errors));
        $global = $vars[PC_Obj_Variable::SCOPE_GLOBAL];
        self::assert_equals((string) PC_Obj_MultiType::create_string(), (string) $global['u']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_string(), (string) $global['w']->get_type());
        self::assert_equals((string) new PC_Obj_MultiType(), (string) $global['x']->get_type());
        self::assert_equals((string) new PC_Obj_MultiType(), (string) $global['y']->get_type());
        self::assert_equals((string) PC_Obj_Type::get_type_by_value(array("a" => 1, "c" => 123, "d" => 5, "b" => 4)), (string) $global['z']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $global['aa']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $global['ab']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $global['ac']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $global['ad']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(0), (string) $global['ba']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_string("bla"), (string) $global['bb']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(), (string) $global['bc']->get_type());
        self::assert_equals((string) new PC_Obj_MultiType(array(new PC_Obj_Type(PC_Obj_Type::STRING, "foo"), new PC_Obj_Type(PC_Obj_Type::INT, 1))), (string) $global['bd']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_string("a"), (string) $global['be']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(1), (string) $global['bf']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(-1), (string) $global['bg']->get_type());
    }
Пример #5
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()]);
     }
 }
Пример #6
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;
 }
Пример #7
0
    public function test_arrays()
    {
        $code = '<?php
/** @param mixed $a */
function func($a) {}

class a {
	/** @param int $x */
	function a($x) {}
}

$x = array();
$x[] = 4;
$x[] = 5;
$y = $x;
$x = array();
$z = clone $y;
$z[] = 6;
$c = array(1,2,3,array(array(\'abc\',2)));
func($c[0]);
func($c[1]);
func($c[2]);
func($c[3][0]);
func($c[3][0][0]);
func($c[3][0][1]);
func($c[4]);
func($c[3][0][1][0]);
$a = array();
$a[] = new a(1);
$a[] = 4;
$a[] = 5;
$a["Abc"] = "me";
$d = array(0,array(1),2,3);
$d[1][0] = 2;
$e = array();
$e{1} = 4;
$e{"foo"} = 5;

class foo {
	public function bar() {
		$a = array(
			0 => 4,
			self::R_TYPESCANNER => array(),
		);
	}
}

/** @return array */
function f() {
	return $_;
}

$g = f();
$g[] = 1;
?>';
        list(, , $vars, $calls, $errors) = $this->analyze($code);
        self::assert_equals(0, count($errors));
        $args = $calls[0]->get_arguments();
        self::assert_equals((string) PC_Obj_MultiType::create_int(1), (string) $args[0]);
        $args = $calls[1]->get_arguments();
        self::assert_equals((string) PC_Obj_MultiType::create_int(2), (string) $args[0]);
        $args = $calls[2]->get_arguments();
        self::assert_equals((string) PC_Obj_MultiType::create_int(3), (string) $args[0]);
        $args = $calls[3]->get_arguments();
        $type = PC_Obj_MultiType::create_array(array());
        $type->get_first()->set_array_type(0, PC_Obj_MultiType::create_string('abc'));
        $type->get_first()->set_array_type(1, PC_Obj_MultiType::create_int(2));
        self::assert_equals((string) $type, (string) $args[0]);
        $args = $calls[4]->get_arguments();
        self::assert_equals((string) PC_Obj_MultiType::create_string('abc'), (string) $args[0]);
        $args = $calls[5]->get_arguments();
        self::assert_equals((string) PC_Obj_MultiType::create_int(2), (string) $args[0]);
        $args = $calls[6]->get_arguments();
        self::assert_equals((string) new PC_Obj_MultiType(), (string) $args[0]);
        $args = $calls[7]->get_arguments();
        self::assert_equals((string) new PC_Obj_MultiType(), (string) $args[0]);
        $global = $vars[PC_Obj_Variable::SCOPE_GLOBAL];
        self::assert_equals((string) PC_Obj_Type::get_type_by_value(array()), (string) $global['x']->get_type());
        self::assert_equals((string) PC_Obj_Type::get_type_by_value(array(4, 5)), (string) $global['y']->get_type());
        self::assert_equals((string) PC_Obj_Type::get_type_by_value(array(4, 5, 6)), (string) $global['z']->get_type());
        $type = PC_Obj_MultiType::create_array(array());
        $type->get_first()->set_array_type(0, PC_Obj_MultiType::create_object('a'));
        $type->get_first()->set_array_type(1, PC_Obj_MultiType::create_int(4));
        $type->get_first()->set_array_type(2, PC_Obj_MultiType::create_int(5));
        $type->get_first()->set_array_type('Abc', PC_Obj_MultiType::create_string('me'));
        self::assert_equals((string) $type, (string) $global['a']->get_type());
        $type = PC_Obj_MultiType::create_array(array());
        $type->get_first()->set_array_type(0, PC_Obj_MultiType::create_int(0));
        $subtype = PC_Obj_MultiType::create_array(array());
        $subtype->get_first()->set_array_type(0, PC_Obj_MultiType::create_int(2));
        $type->get_first()->set_array_type(1, $subtype);
        $type->get_first()->set_array_type(2, PC_Obj_MultiType::create_int(2));
        $type->get_first()->set_array_type(3, PC_Obj_MultiType::create_int(3));
        self::assert_equals((string) $type, (string) $global['d']->get_type());
        $bar = $vars['foo::bar'];
        self::assert_equals('array', (string) $bar['a']->get_type());
        $type = PC_Obj_MultiType::create_array(array());
        $type->get_first()->set_array_type(1, PC_Obj_MultiType::create_int(4));
        $type->get_first()->set_array_type("foo", PC_Obj_MultiType::create_int(5));
        self::assert_equals((string) $type, (string) $global['e']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $global['g']->get_type());
    }
Пример #8
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;
 }
Пример #9
0
 /**
  * Checks if the given method is "magic". If so it adds automatically parameter-types (if not
  * already set).
  * 
  * @param string $classname the class-name
  * @param PC_Obj_Method $method the method
  * @return bool true if handled
  */
 private function handle_magic($classname, $method)
 {
     // the magic-methods:
     // public void __set ( string $name , mixed $value )
     // public mixed __get ( string $name )
     // public bool __isset ( string $name )
     // public void __unset ( string $name )
     // public mixed __call ( string $name , array $arguments )
     // public mixed __callStatic ( string $name , array $arguments )
     // * array __sleep( void )
     // * void__wakeup( void )
     // public string __toString( void )
     // public void __invoke( ... )
     // public static object __set_state( array $props )
     // * void __clone( void )
     $ismagic = true;
     $visibility = PC_Obj_Visible::V_PUBLIC;
     $static = false;
     $expected = null;
     switch (strtolower($method->get_name())) {
         case '__set':
             $expected = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string()), new PC_Obj_Parameter('value', new PC_Obj_MultiType()));
             break;
         case '__isset':
         case '__unset':
         case '__get':
             $expected = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string()));
             break;
         case '__call':
         case '__callstatic':
             $expected = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string()), new PC_Obj_Parameter('arguments', PC_Obj_MultiType::create_array()));
             break;
         case '__tostring':
             $expected = array();
             break;
         case '__sleep':
         case '__wakeup':
         case '__clone':
             $visibility = null;
             // may be private or protected
             $expected = array();
             break;
         case '__invoke':
             $static = true;
             break;
         case '__set_state':
             $expected = array(new PC_Obj_Parameter('props', PC_Obj_MultiType::create_array()));
             break;
         default:
             $ismagic = false;
             break;
     }
     if (!$ismagic) {
         return false;
     }
     if ($visibility !== null && $method->get_visibility() != $visibility) {
         $this->report($method, 'The magic method "#' . $classname . '#::' . $method->get_name() . '" should be public', PC_Obj_Error::E_T_MAGIC_NOT_PUBLIC);
     }
     if ($static && !$method->is_static()) {
         $this->report($method, 'The magic method "#' . $classname . '#::' . $method->get_name() . '" should be static', PC_Obj_Error::E_T_MAGIC_NOT_STATIC);
     } else {
         if (!$static && $method->is_static()) {
             $this->report($method, 'The magic method "#' . $classname . '#::' . $method->get_name() . '" should not be static', PC_Obj_Error::E_T_MAGIC_IS_STATIC);
         }
     }
     if ($expected !== null) {
         $changed = false;
         if ($this->check_params($classname, $method, $expected, $method->get_params())) {
             // set parameter-descriptions
             $i = 0;
             foreach ($method->get_params() as $param) {
                 $param->set_mtype($expected[$i++]->get_mtype());
                 $param->set_has_doc(true);
                 $changed = true;
             }
         }
         $return = new PC_Obj_MultiType();
         switch (strtolower($method->get_name())) {
             case '__set':
             case '__unset':
             case '__wakeup':
             case '__clone':
                 $return = PC_Obj_MultiType::create_void();
                 break;
             case '__set_state':
                 $return = PC_Obj_MultiType::create_object();
                 break;
             case '__isset':
                 $return = PC_Obj_MultiType::create_bool();
                 break;
             case '__sleep':
                 $return = PC_Obj_MultiType::create_array();
                 break;
             case '__tostring':
                 $return = PC_Obj_MultiType::create_string();
                 break;
         }
         if ($method->has_return_doc() && !$this->env->get_types()->is_type_conforming($method->get_return_type(), $return)) {
             // its ok to specify a more specific return-value if the expected one is "mixed"
             if (!$return->is_unknown()) {
                 $this->report($method, 'The return-type of the magic-method "#' . $classname . '#::' . $method->get_name() . '" is invalid ' . '(expected="' . $return . '", found="' . $method->get_return_type() . '")', PC_Obj_Error::E_T_MAGIC_METHOD_RET_INVALID);
             }
         }
         if ($return !== null && !$method->has_return_doc()) {
             $method->set_return_type($return);
             $method->set_has_return_doc(true);
             $changed = true;
         }
         if ($changed) {
             $this->env->get_storage()->update_function($method, $method->get_class());
         }
     }
     return true;
 }
Пример #10
0
 /**
  * Determines the next array-key to use
  * 
  * @return PC_Obj_MultiType the key
  */
 public function get_next_array_key()
 {
     if ($this->_type != self::TARRAY || $this->_value === null) {
         return PC_Obj_MultiType::create_int(0);
     }
     $max = -1;
     foreach (array_keys($this->_value) as $k) {
         if (FWS_Helper::is_integer($k) && $k > $max) {
             $max = $k;
         }
     }
     return PC_Obj_MultiType::create_int($max + 1);
 }
Пример #11
0
 /**
  * Returns a variable pointing to the array-element with given key. If it does not exist, it
  * will be created as soon as the type is assigned.
  *
  * @param PC_Obj_MultiType $key the key (null = append)
  * @return PC_Obj_Variable the type of the element
  */
 public function array_offset($key)
 {
     assert(!$this->type->is_multiple() && !$this->type->is_unknown());
     $first = $this->type->get_first();
     assert($first->get_type() == PC_Obj_Type::TARRAY);
     // fetch element or create it
     $akey = $key;
     if ($key === null) {
         $akey = $key = $first->get_next_array_key();
     } else {
         if (!$key->is_unknown()) {
             $akey = $key;
             $key = $first->get_array_type($key->get_first()->get_value());
         }
     }
     $var = new self($this->get_file(), $this->get_line(), '', $key);
     // connect the var to us
     $var->arrayref = $this;
     $var->arrayoff = $akey;
     return $var;
 }
Пример #12
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);
 }
Пример #13
0
    public function test_vars()
    {
        $code = '<?php
define("MYCONST",123);
$i1 = +1;
$i2 = -412;
$i3 = MYCONST;
$i4 = (int)"abc";
$f1 = 0.5;
$f2 = 0.123;
$f3 = 1.0;
$f4 = (float)(string)2;
$s1="my\'str";
$s2
= \'str2\';
$s3 = "ab $b c\'a\\\\\\""."bla";
$s4 = "ab c\'a\\\\\\""."bla";
$b1 = true;
$b2 = false;
$a1 = array();
$a2 = array(1);
$a3 = ARRAY(1,2,3);
$a4 = array(1 => 2,3 => 4,5 => 6);
$a5 = array(\'a\' => 1,2,3,\'4\');
$a6 = array(array(array(1,2,3),4),5);
$a7 = (array)1;
$a8 = 4;
unset($a8);
$a9 = "foo";
$a10 = 123;
unset($a9,$a10);

/**
 * @param array $a
 * @param MyClass $b
 * @return int
 */
function x($a,MyClass $b) {
	global $b1;
	$i1 = $a;
	$i2 = $i1;
	return 1;
}
?>';
        $options = new PC_Engine_Options();
        $options->add_project(PC_Project::PHPREF_ID);
        $options->add_min_req('PHP', '5');
        list(, , $vars, , $errors) = $this->analyze($code, $options);
        self::assert_equals(0, count($errors));
        $global = $vars[PC_Obj_Variable::SCOPE_GLOBAL];
        self::assert_equals((string) PC_Obj_MultiType::create_int(1), (string) $global['i1']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(-412), (string) $global['i2']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(123), (string) $global['i3']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(0), (string) $global['i4']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_float(0.5), (string) $global['f1']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_float(0.123), (string) $global['f2']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_float(1.0), (string) $global['f3']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_float(2.0), (string) $global['f4']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_string('my\'str'), (string) $global['s1']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_string('str2'), (string) $global['s2']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_string(), (string) $global['s3']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_string('ab c\'a\\\\\\"bla'), (string) $global['s4']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_bool(true), (string) $global['b1']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_bool(false), (string) $global['b2']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_array(array()), (string) $global['a1']->get_type());
        $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(1)));
        self::assert_equals((string) $array, (string) $global['a2']->get_type());
        $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(1, 2, 3)));
        self::assert_equals((string) $array, (string) $global['a3']->get_type());
        $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(1 => 2, 3 => 4, 5 => 6)));
        self::assert_equals((string) $array, (string) $global['a4']->get_type());
        $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array('a' => 1, 2, 3, '4')));
        self::assert_equals((string) $array, (string) $global['a5']->get_type());
        $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value(array(array(array(1, 2, 3), 4), 5)));
        self::assert_equals((string) $array, (string) $global['a6']->get_type());
        $array = new PC_Obj_MultiType(PC_Obj_Type::get_type_by_value((array) 1));
        self::assert_equals((string) $array, (string) $global['a7']->get_type());
        self::assert_equals(false, isset($global['a8']));
        self::assert_equals(false, isset($global['a9']));
        self::assert_equals(false, isset($global['a10']));
        $x = $vars['x'];
        self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $x['a']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_object('MyClass'), (string) $x['b']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $x['i1']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_array(), (string) $x['i2']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_bool(true), (string) $x['b1']->get_type());
    }
Пример #14
0
 /**
  * Merges all types in the given multitype into this one. Clones the types in it.
  * 
  * @param PC_Obj_MultiType $mtype the type to merge with
  * @param bool $set_unknown whether to set the types to unknown when $this or $mtype is unknown
  */
 public function merge($mtype, $set_unknown = true)
 {
     // if one is unknown, the merged type is unknown as well
     if ($set_unknown && ($this->is_unknown() || $mtype->is_unknown())) {
         $this->types = array();
         return;
     }
     if (!isset($mtype->types)) {
         return;
     }
     foreach ($mtype->types as $type) {
         $found = false;
         foreach ($this->types as $ttype) {
             if ($ttype->equals($type)) {
                 $found = true;
                 break;
             }
         }
         // if we already have this type, check if the values are different
         if ($found) {
             // if so simply unset the value, because we don't know it anymore
             if ($ttype->get_value() !== $type->get_value()) {
                 $ttype->set_value(null);
             }
         } else {
             $this->types[] = clone $type;
         }
     }
 }
Пример #15
0
 function yy_r473()
 {
     $this->_retvalue = PC_Obj_MultiType::create_bool();
 }
Пример #16
0
    public function test_nesting()
    {
        $code = '<?php
/** @param int $a */
function f1(int $a) {}
/** @param int $a */
function f2(int $a) {}
/** @param int $a */
function f3(int $a) {}

class A {
	function a() {
		$a = 1;
		function b() {
			$b = 2;
			function c() {
				$c = 3;
				function d() {
					$d = 4;
				}
				f3($c);
			}
			f2($b);
		}
		f1($a);
	}
}

function e() {
	$e = 5;
	function f() {
		$f = 6;
		class B {
			function g() {
				static $h = 4;
				$g = 7;
			}
		}
	}
}
?>';
        list(, , $vars, $calls, $errors) = $this->analyze($code);
        self::assert_equals(0, count($errors));
        self::assert_equals('f3(integer=3)', (string) $calls[0]);
        self::assert_equals('f2(integer=2)', (string) $calls[1]);
        self::assert_equals('f1(integer=1)', (string) $calls[2]);
        self::assert_equals((string) PC_Obj_MultiType::create_int(1), (string) $vars['A::a']['a']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(2), (string) $vars['b']['b']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(3), (string) $vars['c']['c']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(4), (string) $vars['d']['d']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(5), (string) $vars['e']['e']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(6), (string) $vars['f']['f']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(7), (string) $vars['B::g']['g']->get_type());
        self::assert_equals((string) PC_Obj_MultiType::create_int(4), (string) $vars['B::g']['h']->get_type());
    }
Пример #17
0
    public function test_nesting()
    {
        $code = '<?php
/** @param mixed $a */
function func($a) {}

$a = 0;
while(true)
{
	if($_)
		$a++;
	else
		$a--;
}
// now we know that its still an integer, but dont know the value

foreach($_ as $_)
{
	while(true)
	{
		do {
			$b = 4;
		}
		while(true);
	}
}
// $b is unknown since we didnt know it before

$c = "str";
foreach($_ as $_)
{
	while(true)
	{
		do {
			$c = 1;
		}
		while(true);
	}
}
// $c is an int or string since we knew it before

$d = 1;
if($_)
{
	if($_)
	{
		if($_)
		{
			if($_)
			{
				$d = "str";
			}
		}
	}
}
// $d is an int or string since we knew it before

$e = 1;
if($_)
{
	$e = 2;
	if($_)
	{
		$e = 12.3;
		if($_)
		{
			$e = "str";
			if($_)
			{
				$e = true;
				func($e);
			}
			func($e);
		}
		func($e);
	}
	func($e);
}
func($e);
// $e is an int, string, float or bool. note that we even know the value except for the int

if($_)
{
	$f = 0;
	if($_)
	{
		if($_)
			$f = 2;
		else
			$f = 4;
		// here we know that f is an int
		func($f);
	}
	// here we still know that because $f was assigned in this block before
	func($f);
}
// here we dont know that anymore since it didnt exist before
?>';
        list(, , $vars, $calls, $errors) = $this->analyze($code);
        self::assert_equals(0, count($errors));
        $global = $vars[PC_Obj_Variable::SCOPE_GLOBAL];
        self::assert_equals((string) PC_Obj_MultiType::create_int(), (string) $global['a']->get_type());
        self::assert_equals((string) new PC_Obj_MultiType(), (string) $global['b']->get_type());
        $type = new PC_Obj_MultiType(array(new PC_Obj_Type(PC_Obj_Type::INT, 1), new PC_Obj_Type(PC_Obj_Type::STRING, "str")));
        self::assert_equals((string) $type, (string) $global['c']->get_type());
        $type = new PC_Obj_MultiType(array(new PC_Obj_Type(PC_Obj_Type::STRING, "str"), new PC_Obj_Type(PC_Obj_Type::INT, 1)));
        self::assert_equals((string) $type, (string) $global['d']->get_type());
        $type = new PC_Obj_MultiType(array(new PC_Obj_Type(PC_Obj_Type::BOOL, true), new PC_Obj_Type(PC_Obj_Type::STRING, "str"), new PC_Obj_Type(PC_Obj_Type::FLOAT, 12.3), new PC_Obj_Type(PC_Obj_Type::INT)));
        self::assert_equals((string) $type, (string) $global['e']->get_type());
        self::assert_equals((string) new PC_Obj_MultiType(), (string) $global['f']->get_type());
        self::assert_equals('func(bool=1)', (string) $calls[0]);
        self::assert_equals('func(bool=1 or string=str)', (string) $calls[1]);
        self::assert_equals('func(bool=1 or string=str or float=12.3)', (string) $calls[2]);
        self::assert_equals('func(bool=1 or string=str or float=12.3 or integer=2)', (string) $calls[3]);
        self::assert_equals('func(bool=1 or string=str or float=12.3 or integer)', (string) $calls[4]);
        self::assert_equals('func(integer)', (string) $calls[5]);
        self::assert_equals('func(integer)', (string) $calls[6]);
    }
Пример #18
0
    public function test__set_state()
    {
        // public static object __set_state( array $props )
        $code = '<?php
class A {
	public function __set_state($arr);
}
class B {
	public static function __set_state($arr);
}
?>';
        list(, $classes, , , $errors) = $this->analyze($code);
        $params = array(new PC_Obj_Parameter('props', PC_Obj_MultiType::create_array()));
        $m = $classes['a']->get_method('__set_state');
        self::assertParamsEqual($params, $m->get_params());
        self::assert_equals((string) PC_Obj_MultiType::create_object(), (string) $m->get_return_type());
        $m = $classes['b']->get_method('__set_state');
        self::assertParamsEqual($params, $m->get_params());
        self::assert_equals((string) PC_Obj_MultiType::create_object(), (string) $m->get_return_type());
        self::assert_equals(3, count($errors));
        $error = $errors[0];
        self::assert_equals(PC_Obj_Error::E_S_RET_SPEC_BUT_NO_RET, $error->get_type());
        self::assert_regex('/The function\\/method "#A#::__set_state" has a return-specification in PHPDoc, but does not return a value/', $error->get_msg());
        $error = $errors[1];
        self::assert_equals(PC_Obj_Error::E_T_MAGIC_IS_STATIC, $error->get_type());
        self::assert_regex('/The magic method "#B#::__set_state" should not be static/', $error->get_msg());
        $error = $errors[2];
        self::assert_equals(PC_Obj_Error::E_S_RET_SPEC_BUT_NO_RET, $error->get_type());
        self::assert_regex('/The function\\/method "#B#::__set_state" has a return-specification in PHPDoc, but does not return a value/', $error->get_msg());
    }
Пример #19
0
 /**
  * Checks whether $actual is okay for $spec.
  *
  * @param PC_Obj_MultiType $actual the actual type
  * @param PC_Obj_MultiType $spec the specified type, i.e., the one to check against
  * @return bool true if ok
  */
 public function is_type_conforming($actual, $spec)
 {
     if ($actual->is_unknown() || $spec->is_unknown()) {
         return true;
     }
     // every actual type has to be contained in at least one of the specified types
     $count = 0;
     foreach ($actual->get_types() as $atype) {
         $ok = false;
         foreach ($spec->get_types() as $stype) {
             if ($atype->equals($stype)) {
                 $ok = true;
                 break;
             }
             // floats can accept ints
             if ($atype->get_type() == PC_Obj_Type::INT && $stype->get_type() == PC_Obj_Type::FLOAT) {
                 $ok = true;
                 break;
             }
             // if both are objects, check if the actual is the same or a subclass of the spec
             $objs = $atype->get_type() == PC_Obj_Type::OBJECT && $stype->get_type() == PC_Obj_Type::OBJECT;
             if ($objs && ($stype->get_class() == '' || (strcasecmp($atype->get_class(), $stype->get_class()) || $this->is_subclass_of($atype->get_class(), $stype->get_class())))) {
                 $ok = true;
                 break;
             }
         }
         // early exit?
         if (!$ok && $this->options->get_report_argret_strictly()) {
             return false;
         }
         if ($ok && !$this->options->get_report_argret_strictly()) {
             return true;
         }
         if ($ok) {
             $count++;
         }
     }
     return $count > 0;
 }
Пример #20
0
 /**
  * Determines the type for the given type name, which is used, e.g., for return specifications.
  *
  * @param string $name the name
  * @return PC_Obj_MultiType the type
  */
 public function get_type_by_name($name)
 {
     switch ($name) {
         case 'array':
             return PC_Obj_MultiType::create_array();
         case 'callable':
             return PC_Obj_MultiType::create_callable();
         case 'bool':
             return PC_Obj_MultiType::create_bool();
         case 'float':
             return PC_Obj_MultiType::create_float();
         case 'int':
             return PC_Obj_MultiType::create_int();
         case 'string':
             return PC_Obj_MultiType::create_string();
         case 'self':
             // TODO get class name
             return PC_Obj_MultiType::create_object();
         default:
             return PC_Obj_MultiType::create_object($name);
     }
 }
Пример #21
0
 /**
  * Checks whether $types contains a type, that is not contained in $mtype.
  * 
  * @param array $types the types
  * @param PC_Obj_MultiType $mtype the multitype
  * @return bool true if so
  */
 private function has_forbidden($types, $mtype)
 {
     // if the type is unknown (mixed), its always ok
     if ($mtype->is_unknown()) {
         return false;
     }
     foreach ($types as $t) {
         if ($t !== null && !$this->env->get_types()->is_type_conforming($t, $mtype)) {
             return true;
         }
     }
     return false;
 }