diff --git a/duchain/helper.cpp b/duchain/helper.cpp --- a/duchain/helper.cpp +++ b/duchain/helper.cpp @@ -446,6 +446,17 @@ type = AbstractType::Ptr(new IntegralType(IntegralType::TypeInt)); } else if (parameterType->stringType != -1) { type = AbstractType::Ptr(new IntegralType(IntegralType::TypeString)); + } else if (parameterType->iterableType != -1) { + DeclarationPointer traversableDecl = findDeclarationImportHelper(currentContext, QualifiedIdentifier("traversable"), ClassDeclarationType); + + if (traversableDecl) { + UnsureType::Ptr unsure(new UnsureType()); + AbstractType::Ptr arrayType = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); + unsure->addType(arrayType->indexed()); + unsure->addType(traversableDecl->abstractType()->indexed()); + + type = AbstractType::Ptr(unsure); + } } if (type && parameterType->isNullable != -1) { diff --git a/duchain/tests/duchain.h b/duchain/tests/duchain.h --- a/duchain/tests/duchain.h +++ b/duchain/tests/duchain.h @@ -41,12 +41,14 @@ void declareTypehintVariadicFunction(); void declareTypehintArrayFunction(); void declareTypehintCallableFunction(); + void declareTypehintIterableFunction(); void declareTypehintBoolFunction(); void declareTypehintFloatFunction(); void declareTypehintIntFunction(); void declareTypehintStringFunction(); void declareNullableTypehintArrayFunction(); void declareNullableTypehintCallableFunction(); + void declareTypehintNullableIterableFunction(); void declareTypehintWithPhpdocFunction(); void returnTypeClass(); void declarationReturnType(); diff --git a/duchain/tests/duchain.cpp b/duchain/tests/duchain.cpp --- a/duchain/tests/duchain.cpp +++ b/duchain/tests/duchain.cpp @@ -706,6 +706,32 @@ QVERIFY(type->dataType() == IntegralType::TypeMixed); } +void TestDUChain::declareTypehintIterableFunction() +{ + //Note: in practice, Traversable is defined by php, but this interface is not loaded in this test, so define it ourselves + // 0 1 2 3 + // 0123456789012345678901234567890123 + QByteArray method("localDeclarations().count(), 2); + FunctionType::Ptr fun = top->localDeclarations().at(1)->type(); + QVERIFY(fun); + QCOMPARE(fun->arguments().count(), 1); + + UnsureType::Ptr argType = UnsureType::Ptr::dynamicCast(fun->arguments().first()); + QVERIFY(argType); + QCOMPARE(argType->typesSize(), 2u); + QVERIFY(argType->types()[0].abstractType().cast()); + QVERIFY(argType->types()[0].abstractType().cast()->dataType() == IntegralType::TypeArray); + QVERIFY(argType->types()[1].abstractType().cast()); + QCOMPARE(argType->types()[1].abstractType().cast()->qualifiedIdentifier(), QualifiedIdentifier("traversable")); +} + void TestDUChain::declareTypehintBoolFunction() { // 0 1 2 3 @@ -870,6 +896,34 @@ QVERIFY(type->dataType() == IntegralType::TypeMixed); } +void TestDUChain::declareTypehintNullableIterableFunction() +{ + //Note: in practice, Traversable is defined by php, but this interface is not loaded in this test, so define it ourselves + // 0 1 2 3 + // 0123456789012345678901234567890123 + QByteArray method("localDeclarations().count(), 2); + FunctionType::Ptr fun = top->localDeclarations().at(1)->type(); + QVERIFY(fun); + QCOMPARE(fun->arguments().count(), 1); + + UnsureType::Ptr argType = UnsureType::Ptr::dynamicCast(fun->arguments().first()); + QVERIFY(argType); + QCOMPARE(argType->typesSize(), 3u); + QVERIFY(argType->types()[0].abstractType().cast()); + QVERIFY(argType->types()[0].abstractType().cast()->dataType() == IntegralType::TypeArray); + QVERIFY(argType->types()[1].abstractType().cast()); + QCOMPARE(argType->types()[1].abstractType().cast()->qualifiedIdentifier(), QualifiedIdentifier("traversable")); + QVERIFY(argType->types()[2].abstractType().cast()); + QVERIFY(argType->types()[2].abstractType().cast()->dataType() == IntegralType::TypeNull); +} + void TestDUChain::classImplementsInterface() { // 0 1 2 3 4 5 6 7