diff --git a/duchain/builders/typebuilder.cpp b/duchain/builders/typebuilder.cpp --- a/duchain/builders/typebuilder.cpp +++ b/duchain/builders/typebuilder.cpp @@ -445,11 +445,18 @@ type = rType->baseType(); } if (ft->returnType() && !ft->returnType()->equals(type.data())) { + bool existingTypeIsCallable = ft->returnType().cast() && + ft->returnType().cast()->dataType() == IntegralTypeExtended::TypeCallable; + bool newTypeIsCallable = type.cast() && + type.cast()->dataType() == IntegralTypeExtended::TypeCallable; if (ft->returnType().cast() && ft->returnType().cast()->dataType() == IntegralType::TypeMixed) { //don't add TypeMixed to the list, just ignore ft->setReturnType(type); + } else if ((existingTypeIsCallable && type.cast()) || (newTypeIsCallable && ft->returnType().cast())) { + //If one type is "callable" and the other a real function, the result is just a "callable". + ft->setReturnType(AbstractType::Ptr(new IntegralTypeExtended(IntegralTypeExtended::TypeCallable))); } else { UnsureType::Ptr retT; if (ft->returnType().cast()) { diff --git a/duchain/helper.cpp b/duchain/helper.cpp --- a/duchain/helper.cpp +++ b/duchain/helper.cpp @@ -447,6 +447,8 @@ type = AbstractType::Ptr(new IntegralType(IntegralType::TypeInt)); } else if (parameterType->stringType != -1) { type = AbstractType::Ptr(new IntegralType(IntegralType::TypeString)); + } else if (parameterType->callableType != -1) { + type = AbstractType::Ptr(new IntegralTypeExtended(IntegralTypeExtended::TypeCallable)); } else if (parameterType->iterableType != -1) { DeclarationPointer traversableDecl = findDeclarationImportHelper(currentContext, QualifiedIdentifier("traversable"), ClassDeclarationType); diff --git a/duchain/tests/duchain.h b/duchain/tests/duchain.h --- a/duchain/tests/duchain.h +++ b/duchain/tests/duchain.h @@ -41,13 +41,14 @@ void declareTypehintVariadicFunction(); void declareTypehintArrayFunction(); void declareTypehintCallableFunction(); + void functionWithCallableAndFunctionReturn(); void declareTypehintIterableFunction(); void declareTypehintBoolFunction(); void declareTypehintFloatFunction(); void declareTypehintIntFunction(); void declareTypehintStringFunction(); void declareNullableTypehintArrayFunction(); - void declareNullableTypehintCallableFunction(); + void declareNullableTypehintMixedFunction(); void declareTypehintNullableIterableFunction(); void declareTypehintWithPhpdocFunction(); void returnTypeClass(); diff --git a/duchain/tests/duchain.cpp b/duchain/tests/duchain.cpp --- a/duchain/tests/duchain.cpp +++ b/duchain/tests/duchain.cpp @@ -738,12 +738,32 @@ FunctionType::Ptr fun = top->localDeclarations().first()->type(); QVERIFY(fun); QCOMPARE(fun->arguments().count(), 1); - QVERIFY(IntegralType::Ptr::dynamicCast(fun->arguments().first())); - QVERIFY(IntegralType::Ptr::dynamicCast(fun->arguments().first())->dataType() == IntegralType::TypeMixed); + QVERIFY(IntegralTypeExtended::Ptr::dynamicCast(fun->arguments().first())); + QVERIFY(IntegralTypeExtended::Ptr::dynamicCast(fun->arguments().first())->dataType() == IntegralTypeExtended::TypeCallable); - IntegralType::Ptr type = top->childContexts().first()->localDeclarations().first()->type(); + IntegralTypeExtended::Ptr type = top->childContexts().first()->localDeclarations().first()->type(); QVERIFY(type); - QVERIFY(type->dataType() == IntegralType::TypeMixed); + QVERIFY(type->dataType() == IntegralTypeExtended::TypeCallable); +} + +void Php::TestDUChain::functionWithCallableAndFunctionReturn() +{ + QByteArray method("localDeclarations().first()->type(); + QVERIFY(fun); + QCOMPARE(fun->arguments().count(), 1); + QVERIFY(IntegralTypeExtended::Ptr::dynamicCast(fun->arguments().first())); + QVERIFY(IntegralTypeExtended::Ptr::dynamicCast(fun->arguments().first())->dataType() == IntegralTypeExtended::TypeCallable); + + IntegralTypeExtended::Ptr retType = IntegralTypeExtended::Ptr::dynamicCast(fun->returnType()); + QVERIFY(retType); + QVERIFY(retType->dataType() == IntegralTypeExtended::TypeCallable); } void TestDUChain::declareTypehintIterableFunction() @@ -914,11 +934,11 @@ QVERIFY(type->dataType() == IntegralType::TypeInt); } -void TestDUChain::declareNullableTypehintCallableFunction() +void TestDUChain::declareNullableTypehintMixedFunction() { // 0 1 2 3 // 0123456789012345678901234567890123 - QByteArray method(" Ptr; enum PHPIntegralTypes { - TypeResource = KDevelop::IntegralType::TypeLanguageSpecific + TypeResource = KDevelop::IntegralType::TypeLanguageSpecific, + TypeCallable }; /// Default constructor diff --git a/duchain/types/integraltypeextended.cpp b/duchain/types/integraltypeextended.cpp --- a/duchain/types/integraltypeextended.cpp +++ b/duchain/types/integraltypeextended.cpp @@ -51,6 +51,8 @@ { if ( d_func()->m_dataType == TypeResource ) { return QStringLiteral("resource"); + } else if (d_func()->m_dataType == TypeCallable) { + return QStringLiteral("callable"); } return KDevelop::IntegralType::toString(); }