diff --git a/completion/context.cpp b/completion/context.cpp --- a/completion/context.cpp +++ b/completion/context.cpp @@ -598,6 +598,7 @@ case Parser::Token_ARRAY: case Parser::Token_AS: case Parser::Token_BACKTICK: + case Parser::Token_BOOL: case Parser::Token_BREAK: case Parser::Token_CALLABLE: case Parser::Token_CASE: @@ -627,6 +628,7 @@ case Parser::Token_EVAL: case Parser::Token_FILE: case Parser::Token_FINALLY: + case Parser::Token_FLOAT: case Parser::Token_FOR: case Parser::Token_FOREACH: case Parser::Token_FUNCTION: @@ -638,9 +640,11 @@ case Parser::Token_INCLUDE_ONCE: case Parser::Token_INLINE_HTML: case Parser::Token_INSTEADOF: + case Parser::Token_INT: case Parser::Token_INTERFACE: case Parser::Token_INVALID: case Parser::Token_ISSET: + case Parser::Token_ITERABLE: case Parser::Token_LINE: case Parser::Token_LIST: case Parser::Token_LNUMBER: @@ -651,6 +655,7 @@ case Parser::Token_REQUIRE_ONCE: case Parser::Token_RBRACKET: case Parser::Token_RPAREN: + case Parser::Token_STRING_TYPE: case Parser::Token_STRING_VARNAME: case Parser::Token_SWITCH: case Parser::Token_TRAIT: diff --git a/duchain/builders/typebuilder.cpp b/duchain/builders/typebuilder.cpp --- a/duchain/builders/typebuilder.cpp +++ b/duchain/builders/typebuilder.cpp @@ -358,30 +358,25 @@ void TypeBuilder::visitParameter(ParameterAst *node) { AbstractType::Ptr type; - if (node->isVariadic != -1) { - if (node->parameterType) { + if (node->parameterType) { + if (node->parameterType->objectType) { //don't use openTypeFromName as it uses cursor for findDeclarations DeclarationPointer decl = findDeclarationImport(ClassDeclarationType, - identifierForNamespace(node->parameterType, editor())); + identifierForNamespace(node->parameterType->objectType, editor())); if (decl) { - IndexedContainer *container = new IndexedContainer(); - const IndexedString *containerType = new IndexedString("array"); - container->addEntry(decl->abstractType()); - container->setPrettyName(*containerType); - type = AbstractType::Ptr(container); + type = decl->abstractType(); } - } else { + } else if (node->parameterType->arrayType != -1) { type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); + } else if (node->parameterType->boolType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean)); + } else if (node->parameterType->floatType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeFloat)); + } else if (node->parameterType->intType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeInt)); + } else if (node->parameterType->stringType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeString)); } - } else if (node->parameterType) { - //don't use openTypeFromName as it uses cursor for findDeclarations - DeclarationPointer decl = findDeclarationImport(ClassDeclarationType, - identifierForNamespace(node->parameterType, editor())); - if (decl) { - type = decl->abstractType(); - } - } else if (node->arrayType != -1) { - type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); } else if (node->defaultValue) { ExpressionVisitor v(editor()); node->defaultValue->ducontext = currentContext(); @@ -403,6 +398,14 @@ type = p.cast(); } + if (node->isVariadic != -1) { + IndexedContainer *container = new IndexedContainer(); + const IndexedString *containerType = new IndexedString("array"); + container->addEntry(type); + container->setPrettyName(*containerType); + type = AbstractType::Ptr(container); + } + openAbstractType(type); TypeBuilderBase::visitParameter(node); closeType(); diff --git a/duchain/builders/usebuilder.cpp b/duchain/builders/usebuilder.cpp --- a/duchain/builders/usebuilder.cpp +++ b/duchain/builders/usebuilder.cpp @@ -64,8 +64,8 @@ void UseBuilder::visitParameter(ParameterAst *node) { - if (node->parameterType) { - buildNamespaceUses(node->parameterType); + if (node->parameterType && node->parameterType->objectType) { + buildNamespaceUses(node->parameterType->objectType); } } diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -226,16 +226,25 @@ forever { AbstractType::Ptr type; if (it->element->parameterType) { - //don't use openTypeFromName as it uses cursor for findDeclarations - DeclarationPointer decl = findDeclarationImport(ClassDeclarationType, - identifierForNamespace(it->element->parameterType, m_editor)); - if (decl) { - type = decl->abstractType(); + auto parameterType = it->element->parameterType; + if (parameterType->objectType) { + //don't use openTypeFromName as it uses cursor for findDeclarations + DeclarationPointer decl = findDeclarationImport(ClassDeclarationType, + identifierForNamespace(parameterType->objectType, m_editor)); + if (decl) { + type = decl->abstractType(); + } + } else if (parameterType->arrayType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); + } else if (parameterType->boolType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean)); + } else if (parameterType->floatType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeFloat)); + } else if (parameterType->intType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeInt)); + } else if (parameterType->stringType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeString)); } - } else if (it->element->arrayType != -1) { - type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); - } else if (it->element->callableType != -1) { - type = AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed)); } else if (it->element->defaultValue) { ExpressionVisitor v(m_editor); it->element->defaultValue->ducontext = m_currentContext; diff --git a/duchain/tests/duchain.cpp b/duchain/tests/duchain.cpp --- a/duchain/tests/duchain.cpp +++ b/duchain/tests/duchain.cpp @@ -623,12 +623,17 @@ 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::TypeArray); - IntegralType::Ptr type = top->childContexts().first()->localDeclarations().first()->type(); - QVERIFY(type); - QVERIFY(type->dataType() == IntegralType::TypeArray); + AbstractType::Ptr arg = fun->arguments().first(); + QVERIFY(arg); + QVERIFY(arg.cast()); + QCOMPARE(arg.cast()->typesCount(), 1); + QCOMPARE(arg.cast()->prettyName().str(), QStringLiteral("array")); + + AbstractType::Ptr typehint = arg.cast()->typeAt(0).abstractType(); + QVERIFY(typehint); + QVERIFY(IntegralType::Ptr::dynamicCast(typehint)); + QVERIFY(IntegralType::Ptr::dynamicCast(typehint)->dataType() == IntegralType::TypeMixed); } void TestDUChain::declareTypehintVariadicFunction() diff --git a/parser/php.g b/parser/php.g --- a/parser/php.g +++ b/parser/php.g @@ -236,7 +236,8 @@ FILE ("__FILE__"), COMMENT ("comment"), DOC_COMMENT ("doc comment"), PAAMAYIM_NEKUDOTAYIM ("::"), INCLUDE ("include"), INCLUDE_ONCE ("include_once"), EVAL ("eval"), REQUIRE ("require"), REQUIRE_ONCE ("require_once"), NAMESPACE ("namespace"), NAMESPACE_C("__NAMESPACE__"), USE("use"), - GOTO ("goto"), TRAIT ("trait"), INSTEADOF ("insteadof"), CALLABLE ("callable") ;; + GOTO ("goto"), TRAIT ("trait"), INSTEADOF ("insteadof"), CALLABLE ("callable"), + ITERABLE ("iterable"), BOOL ("bool"), FLOAT ("float"), INT ("int"), STRING_TYPE ("string") ;; -- casts: %token INT_CAST ("int cast"), DOUBLE_CAST ("double cast"), STRING_CAST ("string cast"), @@ -879,10 +880,22 @@ (#parameters=parameter @ COMMA) | 0 -> parameterList ;; -(parameterType=namespacedIdentifier | arrayType=ARRAY | callableType=CALLABLE | 0) (isRef=BIT_AND | 0) +(parameterType=parameterType | 0) (isRef=BIT_AND | 0) (isVariadic=ELLIPSIS | 0) variable=variableIdentifier (ASSIGN defaultValue=staticScalar | 0) -> parameter ;; + (isOptional=QUESTION | 0) ( + objectType=namespacedIdentifier + | arrayType=ARRAY + | callableType=CALLABLE + | iterableType=ITERABLE + | boolType=BOOL + | floatType=FLOAT + | intType=INT + | stringType=STRING_TYPE + ) +-> parameterType ;; + value=commonScalar | constantOrClassConst=constantOrClassConst | PLUS plusValue=staticScalar diff --git a/parser/phplexer.cpp b/parser/phplexer.cpp --- a/parser/phplexer.cpp +++ b/parser/phplexer.cpp @@ -786,6 +786,16 @@ token = Parser::Token_NAMESPACE_C; } else if (name.compare(QLatin1String("callable"), Qt::CaseInsensitive) == 0) { token = Parser::Token_CALLABLE; + } else if (name.compare(QLatin1String("iterable"), Qt::CaseInsensitive) == 0) { + token = Parser::Token_ITERABLE; + } else if (name.compare(QLatin1String("bool"), Qt::CaseInsensitive) == 0) { + token = Parser::Token_BOOL; + } else if (name.compare(QLatin1String("float"), Qt::CaseInsensitive) == 0) { + token = Parser::Token_FLOAT; + } else if (name.compare(QLatin1String("int"), Qt::CaseInsensitive) == 0) { + token = Parser::Token_INT; + } else if (name.compare(QLatin1String("string"), Qt::CaseInsensitive) == 0) { + token = Parser::Token_STRING_TYPE; } else { token = Parser::Token_STRING; }