diff --git a/duchain/helper.cpp b/duchain/helper.cpp --- a/duchain/helper.cpp +++ b/duchain/helper.cpp @@ -482,11 +482,35 @@ AbstractType::Ptr type; if (node->parameterType) { type = determineTypehint(node->parameterType, editor, currentContext); - } else if (node->defaultValue) { + } + if (node->defaultValue) { ExpressionVisitor v(editor); node->defaultValue->ducontext = currentContext; v.visitNode(node->defaultValue); - type = v.result().type(); + AbstractType::Ptr defaultValueType = v.result().type(); + + /* + * If a typehint is already set, default values can only be the same type or `null` in PHP + * If it's the same type, the type is already correctly set, + * so we can ignore this case. + * If it's null (which cannot be a typehint), add it as UnsureType + */ + if (type && defaultValueType.cast() && defaultValueType.cast()->dataType() == IntegralType::TypeNull) { + if (type.cast()) { + UnsureType::Ptr unsure = type.cast(); + AbstractType::Ptr nullType = AbstractType::Ptr(new IntegralType(IntegralType::TypeNull)); + unsure->addType(defaultValueType->indexed()); + } else { + UnsureType::Ptr unsure(new UnsureType()); + unsure->addType(type->indexed()); + unsure->addType(defaultValueType->indexed()); + + type = AbstractType::Ptr(unsure); + } + } else { + //Otherwise, let the default value dictate the parameter type + type = defaultValueType; + } } if (!type) { if (phpDocTypehint) { diff --git a/duchain/tests/duchain.h b/duchain/tests/duchain.h --- a/duchain/tests/duchain.h +++ b/duchain/tests/duchain.h @@ -77,6 +77,8 @@ void fileConst_data(); void define(); void defaultFunctionParam(); + void defaultFunctionParamWithTypehint(); + void nullDefaultFunctionParamWithTypehint(); void globalFunction(); void globalVariableFromInternalFunctions(); void newObjectFromOtherFile(); diff --git a/duchain/tests/duchain.cpp b/duchain/tests/duchain.cpp --- a/duchain/tests/duchain.cpp +++ b/duchain/tests/duchain.cpp @@ -1359,6 +1359,47 @@ QCOMPARE(fun->defaultParameters()[1].str(), QString("null")); } +void TestDUChain::defaultFunctionParamWithTypehint() { + QByteArray method("localDeclarations().first()->type(); + QVERIFY(fun); + QCOMPARE(fun->arguments().count(), 1); + + IntegralType::Ptr argType = IntegralType::Ptr::dynamicCast(fun->arguments().first()); + QVERIFY(argType); + QVERIFY(argType->dataType() == IntegralType::TypeArray); +} + +void TestDUChain::nullDefaultFunctionParamWithTypehint() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + QByteArray method("localDeclarations().first()->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()); + QVERIFY(argType->types()[1].abstractType().cast()->dataType() == IntegralType::TypeNull); +} + void TestDUChain::globalFunction() { // 0 1 2 3 4 5 6 7