예제 #1
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);
     }
 }
예제 #2
0
 /**
  * Handles the instanceof-operator
  * 
  * @param PC_Obj_MultiType $e the expression
  * @param PC_Obj_MultiType $name the name of the class
  * @return PC_Obj_MultiType the result
  */
 public function handle_instanceof($e, $name)
 {
     if (!$e instanceof PC_Obj_MultiType) {
         return $this->handle_error('$e is invalid');
     }
     $cname = $name->get_string();
     // if we're in a loop or the name is not a string, give up
     if ($this->vars->is_in_loop() || $cname === null) {
         return PC_Obj_MultiType::create_bool();
     }
     // if we don't know the type or its class we can't say wether its a superclass
     $classname = $e->get_classname();
     if ($classname === null) {
         return PC_Obj_MultiType::create_bool();
     }
     // class-name equal?
     if (strcasecmp($classname, $cname) == 0) {
         return PC_Obj_MultiType::create_bool(true);
     }
     // if the class is unknown we can't say more
     $class = $this->env->get_types()->get_class($classname);
     if ($class === null) {
         return PC_Obj_MultiType::create_bool();
     }
     // check super-classes
     $super = $class->get_super_class();
     while ($super != '') {
         if (strcasecmp($super, $cname) == 0) {
             return PC_Obj_MultiType::create_bool(true);
         }
         $superobj = $this->env->get_types()->get_class($super);
         if ($superobj === null) {
             break;
         }
         $super = $superobj->get_super_class();
     }
     // check interfaces
     if ($this->is_instof_interface($class->get_interfaces(), $cname)) {
         return PC_Obj_MultiType::create_bool(true);
     }
     return PC_Obj_MultiType::create_bool(false);
 }
예제 #3
0
    public function test__isset()
    {
        // public bool __isset ( string $name )
        $code = '<?php
class A {
	public function __isset($name);
}
class B {
	/**
	 * @return int
	 */
	public function __isset($name);
}
?>';
        list(, $classes, , , $errors) = $this->analyze($code);
        $params = array(new PC_Obj_Parameter('name', PC_Obj_MultiType::create_string()));
        $m = $classes['a']->get_method('__isset');
        self::assertParamsEqual($params, $m->get_params());
        self::assert_equals((string) PC_Obj_MultiType::create_bool(), (string) $m->get_return_type());
        $m = $classes['b']->get_method('__isset');
        self::assertParamsEqual($params, $m->get_params());
        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#::__isset" 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_METHOD_RET_INVALID, $error->get_type());
        self::assert_regex('/The return-type of the magic-method "#B#::__isset" is invalid \\(expected="bool", found="integer"\\)/', $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#::__isset" has a return-specification in PHPDoc, but does not return a value/', $error->get_msg());
    }
예제 #4
0
 function yy_r473()
 {
     $this->_retvalue = PC_Obj_MultiType::create_bool();
 }
예제 #5
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());
    }
예제 #6
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;
 }
예제 #7
0
 /**
  * Creates a multitype with type BOOL and given value
  * 
  * @param string $file the file of the def
  * @param int $line the line of the def
  * @param bool $value the value
  * @param string $varname optionally, the variable-name
  * @return PC_Obj_Variable the variable
  */
 public static function create_bool($file, $line, $value = null, $varname = '')
 {
     return new self($file, $line, $varname, PC_Obj_MultiType::create_bool($value));
 }
예제 #8
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());
    }