diff --git a/duchain/builders/declarationbuilder.h b/duchain/builders/declarationbuilder.h --- a/duchain/builders/declarationbuilder.h +++ b/duchain/builders/declarationbuilder.h @@ -155,6 +155,7 @@ QHash m_functions; QHash m_namespaces; QList m_upcomingClassVariables; + unsigned int m_nonOptionalParametersLeft; /// handles common stuff for both interfaces and classes ClassDeclaration* openTypeDeclaration(IdentifierAst *name, KDevelop::ClassDeclarationData::ClassType type); diff --git a/duchain/builders/declarationbuilder.cpp b/duchain/builders/declarationbuilder.cpp --- a/duchain/builders/declarationbuilder.cpp +++ b/duchain/builders/declarationbuilder.cpp @@ -745,6 +745,32 @@ { PushValue push(m_functionDeclarationPreviousArgument, 0); + if (node->parametersSequence) { + //Find the correct number of optional parameters, since PHP allows default parameters even before non-optional arguments + //This messes up the DUChain, which is not built to handle such situations + unsigned int defaultParametersCount = 0; + auto it = node->parametersSequence->front(); + forever { + if (it->element->defaultValue) { + //If it's a optional parameter, so increase the count + ++defaultParametersCount; + } else { + //Earlier optional parameters do not matter since this parameter is non-optional. Reset the count + defaultParametersCount = 0; + } + + if (it->hasNext()) { + it = it->next; + } else { + break; + } + } + + //Store the number of non-optional parameters + m_nonOptionalParametersLeft = node->parametersSequence->count() - defaultParametersCount; + } else { + m_nonOptionalParametersLeft = 0; + } DeclarationBuilderBase::visitParameterList(node); } @@ -755,14 +781,16 @@ if (node->defaultValue) { QString symbol = m_editor->parseSession()->symbol(node->defaultValue); - funDec->addDefaultParameter(IndexedString(symbol)); if (node->isVariadic != -1) { reportError(i18n("Variadic parameter cannot have a default value"), node->defaultValue); } else if ( node->parameterType && node->parameterType->objectType && symbol.compare(QLatin1String("null"), Qt::CaseInsensitive) != 0 ) { reportError(i18n("Default value for parameters with a class type hint can only be NULL."), node->defaultValue); } - } else if ( !node->defaultValue && funDec->defaultParametersSize() ) { - reportError(i18n("Following parameters must have a default value assigned."), node); + + //Only add the default value if there are no non-optional parameters still coming + if (!m_nonOptionalParametersLeft) { + funDec->addDefaultParameter(IndexedString(symbol)); + } } { // create variable declaration for argument @@ -782,6 +810,9 @@ closeDeclaration(); m_functionDeclarationPreviousArgument = node; + if (m_nonOptionalParametersLeft) { + --m_nonOptionalParametersLeft; + } } void DeclarationBuilder::visitFunctionDeclarationStatement(FunctionDeclarationStatementAst* node) diff --git a/duchain/tests/duchain.h b/duchain/tests/duchain.h --- a/duchain/tests/duchain.h +++ b/duchain/tests/duchain.h @@ -127,6 +127,7 @@ void referencedArgument(); void unsureReferencedArgument(); void defaultArgument(); + void defaultArgumentBeforeNonDefault(); void declareMemberOutOfClass(); void declareMemberOutOfClass2(); void declareMemberInClassMethod(); diff --git a/duchain/tests/duchain.cpp b/duchain/tests/duchain.cpp --- a/duchain/tests/duchain.cpp +++ b/duchain/tests/duchain.cpp @@ -2349,6 +2349,18 @@ QCOMPARE(dec->type()->dataType(), (uint)IntegralType::TypeInt); } +void TestDUChain::defaultArgumentBeforeNonDefault() +{ + QByteArray code("(top->localDeclarations().at(0)); + QVERIFY(dec); + QCOMPARE(dec->defaultParametersSize(), 0u); +} + void TestDUChain::declareMemberOutOfClass() { // 0 1 2 3 4 5 6 7