/** * @param array $input * @param array $expected * * @dataProvider evaluateDataProvider */ public function testEvaluate(array $input, array $expected) { $this->_itemInterpreter->expects($this->any())->method('evaluate')->will($this->returnCallback(function ($input) { return '-' . $input['value'] . '-'; })); $actual = $this->_model->evaluate($input); $this->assertSame($expected, $actual); }
public static function decideType(Type $type, Type $phpDocType = null) : Type { if ($phpDocType !== null) { if ($type instanceof IterableType && $phpDocType instanceof ArrayType) { if ($type instanceof IterableIterableType) { $phpDocType = new IterableIterableType($phpDocType->getItemType(), $type->isNullable() || $phpDocType->isNullable()); } elseif ($type instanceof ArrayType) { $type = new ArrayType($phpDocType->getItemType(), $type->isNullable() || $phpDocType->isNullable()); } } if ($type->accepts($phpDocType)) { return $phpDocType; } } return $type; }
public static function decideType(\ReflectionType $reflectionType = null, Type $phpDocType = null, string $selfClass = null, bool $isVariadic = false) : Type { if ($reflectionType === null) { return $phpDocType !== null ? $phpDocType : new MixedType(true); } $reflectionTypeString = (string) $reflectionType; if ($isVariadic) { $reflectionTypeString .= '[]'; } $type = self::getTypeObjectFromTypehint($reflectionTypeString, $reflectionType->allowsNull(), $selfClass); if ($phpDocType !== null) { if ($type instanceof ArrayType && $phpDocType instanceof ArrayType) { $type = new ArrayType($phpDocType->getItemType(), $type->isNullable() || $phpDocType->isNullable()); } if ($type->accepts($phpDocType)) { return $phpDocType; } } return $type; }
public static function init() { self::$CLASS_TO_VALUE_READER = new IdentityHashMap(); self::$CLASS_TO_VECTOR_READER = new IdentityHashMap(); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Boolean::typeClass()), new SSSR_VectorReader_Boolean()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Byte::typeClass()), new SSSR_VectorReader_Byte()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Character::typeClass()), new SSSR_VectorReader_Char()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Double::typeClass()), new SSSR_VectorReader_Double()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Float::typeClass()), new SSSR_VectorReader_Float()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Integer::typeClass()), new SSSR_VectorReader_Int()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Long::typeClass()), new SSSR_VectorReader_Long()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Object::clazz()), new SSSR_VectorReader_Object()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(Short::typeClass()), new SSSR_VectorReader_Short()); self::$CLASS_TO_VECTOR_READER->put(ArrayType::clazz(String::clazz()), new SSSR_VectorReader_String()); self::$CLASS_TO_VALUE_READER->put(Boolean::typeClass(), new SSSR_ValueReader_Boolean()); self::$CLASS_TO_VALUE_READER->put(Byte::typeClass(), new SSSR_ValueReader_Byte()); self::$CLASS_TO_VALUE_READER->put(Character::typeClass(), new SSSR_ValueReader_Char()); self::$CLASS_TO_VALUE_READER->put(Double::typeClass(), new SSSR_ValueReader_Double()); self::$CLASS_TO_VALUE_READER->put(Float::typeClass(), new SSSR_ValueReader_Float()); self::$CLASS_TO_VALUE_READER->put(Integer::typeClass(), new SSSR_ValueReader_Int()); self::$CLASS_TO_VALUE_READER->put(Long::typeClass(), new SSSR_ValueReader_Long()); self::$CLASS_TO_VALUE_READER->put(Object::clazz(), new SSSR_ValueReader_Object()); self::$CLASS_TO_VALUE_READER->put(Short::typeClass(), new SSSR_ValueReader_Short()); self::$CLASS_TO_VALUE_READER->put(String::clazz(), new SSSR_ValueReader_String()); }
public function cast_raises_exceptions_for_non_arrays($value) { ArrayType::forName('var[]')->cast($value); }
public function stringArrayDeprecatedSyntax() { $this->assertEquals(ArrayType::forName('string[]'), Type::forName('array<string>')); }
/** * @param Node $node * A node to check types on * * @return UnionType * The resulting type(s) of the binary operation */ public function visitBinaryAdd(Node $node) : UnionType { $left = UnionType::fromNode($this->context, $this->code_base, $node->children['left']); $right = UnionType::fromNode($this->context, $this->code_base, $node->children['right']); // fast-track common cases if ($left->isType(IntType::instance()) && $right->isType(IntType::instance())) { return IntType::instance()->asUnionType(); } if (($left->isType(IntType::instance()) || $left->isType(FloatType::instance())) && ($right->isType(IntType::instance()) || $right->isType(FloatType::instance()))) { return FloatType::instance()->asUnionType(); } $left_is_array = !empty($left->genericArrayElementTypes()) && empty($left->nonGenericArrayTypes()); $right_is_array = !empty($right->genericArrayElementTypes()) && empty($right->nonGenericArrayTypes()); if ($left_is_array && !$right->canCastToUnionType(ArrayType::instance()->asUnionType())) { Log::err(Log::ETYPE, "invalid operator: left operand is array and right is not", $this->context->getFile(), $node->lineno); return new UnionType(); } else { if ($right_is_array && !$left->canCastToUnionType(ArrayType::instance()->asUnionType())) { Log::err(Log::ETYPE, "invalid operator: right operand is array and left is not", $this->context->getFile(), $node->lineno); return new UnionType(); } else { if ($left_is_array || $right_is_array) { // If it is a '+' and we know one side is an array // and the other is unknown, assume array return ArrayType::instance()->asUnionType(); } } } return new UnionType([IntType::instance(), FloatType::instance()]); }
/** * Takes "a|b[]|c|d[]|e" and returns "b|d" * * @return UnionType * The subset of types in this */ public function genericArrayElementTypes() : UnionType { // If array is in there, then it can be any type // Same for mixed if ($this->hasType(ArrayType::instance()) || $this->hasType(MixedType::instance())) { return MixedType::instance()->asUnionType(); } if ($this->hasType(ArrayType::instance())) { return NullType::instance()->asUnionType(); } return new UnionType(array_filter(array_map(function (Type $type) { if (!$type->isGenericArray()) { return null; } return $type->genericArrayElementType(); }, $this->getTypeList()))); }
public function arrayOfString() { $this->assertEquals(ArrayType::forName('string[]'), Type::forName('string[]')); }
/** * Visit a node with kind `\ast\AST_CAST` * * @param Node $node * A node of the type indicated by the method name that we'd * like to figure out the type that it produces. * * @return UnionType * The set of types that are possibly produced by the * given node */ public function visitCast(Node $node) : UnionType { switch ($node->flags) { case \ast\flags\TYPE_NULL: return NullType::instance()->asUnionType(); case \ast\flags\TYPE_BOOL: return BoolType::instance()->asUnionType(); case \ast\flags\TYPE_LONG: return IntType::instance()->asUnionType(); case \ast\flags\TYPE_DOUBLE: return FloatType::instance()->asUnionType(); case \ast\flags\TYPE_STRING: return StringType::instance()->asUnionType(); case \ast\flags\TYPE_ARRAY: return ArrayType::instance()->asUnionType(); case \ast\flags\TYPE_OBJECT: return ObjectType::instance()->asUnionType(); default: Log::err(Log::EFATAL, "Unknown type (" . $node->flags . ") in cast"); } }
public static function classOfValue($value) { $className = ''; $type = gettype($value); if ($type == 'boolean') { $className = 'boolean'; } else { if ($type == 'integer') { $className = 'int'; } else { if ($type == 'double') { $className = 'double'; } else { if ($type == 'string') { $className = 'String'; } else { if ($type == 'array') { return ArrayType::autoClass($value); } else { if ($type == 'object') { if ($value instanceof Magic) { return new MagicClazz(get_class($value), $value); } else { $className = get_class($value); } } else { if ($type == 'resource') { throw new ClassNotFoundException('Resource have no class'); } else { if ($type == 'NULL') { $className = 'Void'; } else { throw new ClassNotFoundException('Type of value is unknown'); } } } } } } } } return self::classOf($className); }
public function visitArray(ArrayValueCommand $x, Context $ctx) { if ($this->maybePushBackRef($x)) { $values = $x->getComponentValues(); $array = ArrayType::newInstance(null, count($values)); $size = count($values); for ($i = 0; $i < $size; $i++) { $this->accept($values[$i]); $array[$i] = array_pop($this->values); } $this->push($x, $array); } return false; }
public function varArgsArrayType() { $this->assertEquals(ArrayType::forName('string[]'), $this->methodParameter('printf', 1)->getType()); }
function typeof($arg) { if ($arg instanceof Generic) { return $arg->getClass(); } else { if (NULL === $arg) { return Type::$VOID; } else { if (is_array($arg)) { return 0 === key($arg) ? ArrayType::forName('var[]') : MapType::forName('[:var]'); } else { return Type::forName(gettype($arg)); } } } }
private function makeArray(Clazz $type, array &$value) { $toReturn = new ArrayValueCommand($type->getComponentType()); $this->identityMap->put($value, $toReturn); for ($i = 0, $j = ArrayType::getLength($value); $i < $j; $i++) { $arrayValue = ArrayType::get($value, $i); if (is_null($arrayValue)) { $toReturn->add(NullValueCommand::INSTANCE()); } else { $valueType = $type->getComponentType()->isPrimitive() ? $type->getComponentType() : Classes::classOfValue($arrayValue); $toReturn->add($this->makeValue($valueType, $arrayValue)); } } return $toReturn; }
/** * Check to see if the given Clazz is a duplicate * * @param Method $method * The method we're analyzing arguments for * * @param Node $node * The node holding the method call we're looking at * * @param Context $context * The context in which we see the call * * @param CodeBase $code_base * * @return null * * @see \Phan\Deprecated\Pass2::arg_check * Formerly `function arg_check` */ private static function analyzeInternalArgumentType(Method $method, Node $node, Context $context, CodeBase $code_base) { $arglist = $node->children['args']; $argcount = count($arglist->children); switch ($method->getName()) { case 'join': case 'implode': // (string glue, array pieces), // (array pieces, string glue) or // (array pieces) if ($argcount == 1) { self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#1(pieces) is %s but {$method->getFQSEN()}() takes array when passed only 1 arg"); return; } else { if ($argcount == 2) { $arg1_type = UnionType::fromNode($context, $code_base, $arglist->children[0]); $arg2_type = UnionType::fromNode($context, $code_base, $arglist->children[1]); if ((string) $arg1_type == 'array') { if (!$arg1_type->canCastToUnionType(StringType::instance()->asUnionType())) { Log::err(Log::EPARAM, "arg#2(glue) is {$arg2_type} but {$method->getFQSEN()}() takes string when arg#1 is array", $context->getFile(), $context->getLineNumberStart()); } } else { if ((string) $arg1_type == 'string') { if (!$arg2_type->canCastToUnionType(ArrayType::instance()->asUnionType())) { Log::err(Log::EPARAM, "arg#2(pieces) is {$arg2_type} but {$method->getFQSEN()}() takes array when arg#1 is string", $context->getFile(), $context->getLineNumberStart()); } } } return; } } // Any other arg counts we will let the regular // checks handle break; case 'array_udiff': case 'array_diff_uassoc': case 'array_uintersect_assoc': case 'array_intersect_ukey': if ($argcount < 3) { Log::err(Log::EPARAM, "call with {$argcount} arg(s) to {$method->getFQSEN()}() which requires {$method->getNumberOfRequiredParameters()} arg(s)", $context->getFile(), $context->getLineNumberStart()); return; } self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 1], $context, $code_base, CallableType::instance()->asUnionType(), "The last argument to {$method->getFQSEN()} must be a callable"); for ($i = 0; $i < $argcount - 1; $i++) { self::analyzeNodeUnionTypeCast($arglist->children[$i], $context, $code_base, CallableType::instance()->asUnionType(), "arg#" . ($i + 1) . " is %s but {$method->getFQSEN()}() takes array"); } return; case 'array_diff_uassoc': case 'array_uintersect_uassoc': if ($argcount < 4) { Log::err(Log::EPARAM, "call with {$argcount} arg(s) to {$method->getFQSEN()}() which requires {$method->getNumberOfRequiredParameters()} arg(s)", $context->getFile(), $context->getLineNumberStart()); return; } // The last 2 arguments must be a callable and there // can be a variable number of arrays before it self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 1], $context, $code_base, CallableType::instance()->asUnionType(), "The last argument to {$method->getFQSEN()} must be a callable"); self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 2], $context, $code_base, CallableType::instance()->asUnionType(), "The second last argument to {$method->getFQSEN()} must be a callable"); for ($i = 0; $i < $argcount - 2; $i++) { self::analyzeNodeUnionTypeCast($arglist->children[$i], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#" . ($i + 1) . " is %s but {$method->getFQSEN()}() takes array"); } return; case 'strtok': // (string str, string token) or (string token) if ($argcount == 1) { // If we have just one arg it must be a string token self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#1(token) is %s but {$method->getFQSEN()}() takes string when passed only one arg"); } // The arginfo check will handle the other case break; case 'min': case 'max': if ($argcount == 1) { // If we have just one arg it must be an array if (!self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#1(values) is %s but {$method->getFQSEN()}() takes array when passed only one arg")) { return; } } // The arginfo check will handle the other case break; default: break; } }
public function arrayComponentType() { $this->assertEquals(ArrayType::forName('int[]'), MapType::forName('[:int[]]')->componentType()); }
/** * @return Type * Get a new type which is the generic array version of * this type. For instance, 'int' will produce 'int[]'. */ public function asGenericArrayType() : Type { if ($this->name == 'array' || $this->name == 'mixed' || strpos($this->name, '[]') !== false) { return ArrayType::instance(); } return new \Phan\Language\Type\GenericArrayType($this); }
public function intArray() { $this->assertEquals(ArrayType::forName('var[]'), typeof(array(1, 2, 3))); }
public function array_of_issues() { $issue1 = new net·xp_framework·unittest·webservices·rest·IssueWithField(1, 'test1'); $issue2 = new net·xp_framework·unittest·webservices·rest·IssueWithField(2, 'test2'); $this->assertEquals(array($issue1, $issue2), $this->fixture->convert(ArrayType::forName($issue1->getClassName() . '[]'), array(array('issue_id' => 1, 'title' => 'test1'), array('issue_id' => 2, 'title' => 'test2')))); }
private function constructorFunctionArray(ArrayValueCommand $x) { $targetClass = ArrayType::clazz($x->getComponentType()); $functionName = $this->constructorFunctions->get($targetClass); if (!is_null($functionName)) { return $functionName; } $initValuesId = $this->clientOracle->getMethodIdByClassName('com.google.gwt.lang.Array', 'initValues', array('Ljava/lang/Class;', 'Lcom/google/gwt/core/client/JavaScriptObject;', 'I', 'Lcom/google/gwt/lang/Array;')); assert(!is_null($initValuesId)); $classLitId = $this->clientOracle->getFieldIdByClassName('com.google.gwt.lang.ClassLiteralHolder', $this->getJavahSignatureName($x->getComponentType()) . '_classLit'); assert(!is_null($classLitId)); $functionName = $this->clientOracle->createUnusedIdent($classLitId); $this->constructorFunctions->put($targetClass, $functionName); $castableTypeData = $this->clientOracle->getCastableTypeData($targetClass); if (is_null($castableTypeData)) { $castableTypeData = $this->clientOracle->getCastableTypeData(Classes::classOf('Object[]')); } $queryId = $this->clientOracle->getQueryId($x->getComponentType()); if ($queryId == 0) { $queryId = $this->clientOracle->getQueryId(Classes::classOf('Object')); } $ident = '_0'; // function foo(_0) {return initValues(classLid, castableTypeData, queryId, _0)} $this->_function(); $this->push($functionName); $this->lparen(); $this->push($ident); $this->rparen(); $this->lbrace(); $this->_return(); $this->push($initValuesId); $this->lparen(); $this->push($classLitId); $this->comma(); $this->push($castableTypeData->toJs()); $this->comma(); $this->push(String::valueOf($queryId)); $this->comma(); $this->push($ident); $this->rparen(); $this->rbrace(); $this->flush($x); return $functionName; }
public function varArrayAssignableFromIntArray() { $this->assertFalse(ArrayType::forName('var[]')->isAssignableFrom('int[]')); }
private function findClass($token) { if (isset($this->classCache[$token])) { return $this->classCache[$token]; } $className = $this->clientOracle->getTypeName($token); if ($className == null) { $className = $token; } if (strstr($className, '[]') !== false) { $firstIndex = -1; $j = -1; $dims = 0; while (($j = strpos($className, '[')) !== false) { if ($dims++ == 0) { $firstIndex = $j; } } $componentType = $this->findClass(substr($className, 0, $firstIndex)); assert($componentType != null); $clazz = ArrayType::clazz($componentType, $dims); } else { $clazz = Classes::classOf($className); } $this->classCache[$token] = $clazz; return $clazz; }
/** * @param Node $node * A node to check types on * * @return UnionType * The resulting type(s) of the binary operation */ public function visitBinaryAdd(Node $node) : UnionType { $left = UnionType::fromNode($this->context, $this->code_base, $node->children['left']); $right = UnionType::fromNode($this->context, $this->code_base, $node->children['right']); // fast-track common cases if ($left->isType(IntType::instance()) && $right->isType(IntType::instance())) { return IntType::instance()->asUnionType(); } // If both left and right are arrays, then this is array // concatenation. if ($left->isGenericArray() && $right->isGenericArray()) { if ($left->isEqualTo($right)) { return $left; } return ArrayType::instance()->asUnionType(); } if (($left->isType(IntType::instance()) || $left->isType(FloatType::instance())) && ($right->isType(IntType::instance()) || $right->isType(FloatType::instance()))) { return FloatType::instance()->asUnionType(); } $left_is_array = !empty($left->genericArrayElementTypes()) && empty($left->nonGenericArrayTypes()) || $left->isType(ArrayType::instance()); $right_is_array = !empty($right->genericArrayElementTypes()) && empty($right->nonGenericArrayTypes()) || $right->isType(ArrayType::instance()); if ($left_is_array && !$right->canCastToUnionType(ArrayType::instance()->asUnionType())) { Issue::maybeEmit($this->code_base, $this->context, Issue::TypeInvalidRightOperand, $node->lineno ?? 0); return new UnionType(); } elseif ($right_is_array && !$left->canCastToUnionType(ArrayType::instance()->asUnionType())) { Issue::maybeEmit($this->code_base, $this->context, Issue::TypeInvalidLeftOperand, $node->lineno ?? 0); return new UnionType(); } elseif ($left_is_array || $right_is_array) { // If it is a '+' and we know one side is an array // and the other is unknown, assume array return ArrayType::instance()->asUnionType(); } return new UnionType([IntType::instance(), FloatType::instance()]); }
/** * Gets a type for a given name * * Checks for: * <ul> * <li>Primitive types (string, integer, double, boolean, array)</li> * <li>Array notations (string[] or string*)</li> * <li>Resources</li> * <li>Any type (var or *)</li> * <li>Generic notations (util.collections.HashTable<lang.types.String, lang.Generic>)</li> * <li>Anything else will be passed to XPClass::forName()</li> * </ul> * * @param string name * @return lang.Type */ public static function forName($name) { static $deprecated = array('char' => 'string', 'integer' => 'int', 'boolean' => 'bool', 'float' => 'double', 'mixed' => 'var', '*' => 'var', 'array' => 'var[]', 'resource' => 'var'); static $primitives = array('string' => TRUE, 'int' => TRUE, 'double' => TRUE, 'bool' => TRUE); // Map deprecated type names $type = isset($deprecated[$name]) ? $deprecated[$name] : $name; // Map well-known primitives, var and void, handle rest syntactically: // * T[] is an array // * [:T] is a map // * T* is a vararg // * T<K, V> is a generic // * Anything else is a qualified or unqualified class name if (isset($primitives[$type])) { return Primitive::forName($type); } else { if ('var' === $type) { return self::$VAR; } else { if ('void' === $type) { return self::$VOID; return $type; } else { if ('[]' === substr($type, -2)) { return ArrayType::forName($type); } else { if ('[:' === substr($type, 0, 2)) { return MapType::forName($type); } else { if ('*' === substr($type, -1)) { return ArrayType::forName(substr($type, 0, -1) . '[]'); } else { if (FALSE === ($p = strpos($type, '<'))) { return strstr($type, '.') ? XPClass::forName($type) : new XPClass($type); } } } } } } } // Generics // * D<K, V> is a generic type definition D with K and V componenty // * Deprecated: array<T> is T[], array<K, V> is [:T] $base = substr($type, 0, $p); $components = self::forNames(substr($type, $p + 1, -1)); if ('array' !== $base) { return cast(self::forName($base), 'lang.XPClass')->newGenericType($components); } $s = sizeof($components); if (2 === $s) { return MapType::forName('[:' . $components[1]->name . ']'); } else { if (1 === $s) { return ArrayType::forName($components[0]->name . '[]'); } } throw new IllegalArgumentException('Unparseable name ' . $name); }