diff --git a/completion/context.cpp b/completion/context.cpp --- a/completion/context.cpp +++ b/completion/context.cpp @@ -608,7 +608,6 @@ 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: @@ -639,7 +638,6 @@ 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: @@ -651,11 +649,9 @@ 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: @@ -666,7 +662,6 @@ 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/declarationbuilder.h b/duchain/builders/declarationbuilder.h --- a/duchain/builders/declarationbuilder.h +++ b/duchain/builders/declarationbuilder.h @@ -73,6 +73,7 @@ void visitParameterList(ParameterListAst *node) override; void visitParameter(ParameterAst *node) override; void visitFunctionDeclarationStatement(FunctionDeclarationStatementAst *node) override; + void visitReturnType(ReturnTypeAst *node) override; void visitClassVariable(ClassVariableAst *node) override; void visitConstantDeclaration(ConstantDeclarationAst *node) override; void visitClassConstantDeclaration(ClassConstantDeclarationAst *node) override; @@ -237,6 +238,8 @@ * Sets encountered and updates the comment when we are recompiling. */ void encounter(KDevelop::Declaration* dec); + + bool isReservedClassName(QString className); }; } diff --git a/duchain/builders/declarationbuilder.cpp b/duchain/builders/declarationbuilder.cpp --- a/duchain/builders/declarationbuilder.cpp +++ b/duchain/builders/declarationbuilder.cpp @@ -191,6 +191,12 @@ closeType(); closeDeclaration(); m_upcomingClassVariables.clear(); + + QString className = classDec->prettyName().str(); + + if (isReservedClassName(className)) { + reportError(i18n("Cannot use '%1' as class name as it is reserved", className), node->className); + } } void DeclarationBuilder::visitInterfaceDeclarationStatement(InterfaceDeclarationStatementAst *node) @@ -200,6 +206,12 @@ DeclarationBuilderBase::visitInterfaceDeclarationStatement(node); closeType(); closeDeclaration(); + + QString interfaceName = interfaceDec->prettyName().str(); + + if (isReservedClassName(interfaceName)) { + reportError(i18n("Cannot use '%1' as class name as it is reserved", interfaceName), node->interfaceName); + } } void DeclarationBuilder::visitTraitDeclarationStatement(TraitDeclarationStatementAst * node) @@ -210,6 +222,12 @@ closeType(); closeDeclaration(); m_upcomingClassVariables.clear(); + + QString traitName = traitDec->prettyName().str(); + + if (isReservedClassName(traitName)) { + reportError(i18n("Cannot use '%1' as class name as it is reserved", traitName), node->traitName); + } } ClassDeclaration* DeclarationBuilder::openTypeDeclaration(IdentifierAst* name, ClassDeclarationData::ClassType type) @@ -691,7 +709,6 @@ } lock.unlock(); - DeclarationBuilderBase::visitTraitAliasStatement(node); } @@ -816,7 +833,8 @@ 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 ) { + } else if (node->parameterType && node->parameterType->typehint && isClassTypehint(node->parameterType->typehint, m_editor) + && 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 { @@ -833,6 +851,16 @@ DeclarationBuilderBase::visitParameter(node); + if (node->parameterType && node->parameterType->typehint && isClassTypehint(node->parameterType->typehint, m_editor)) { + NamespacedIdentifierAst* typehintNode = node->parameterType->typehint->genericType; + const KDevPG::ListNode< IdentifierAst* >* it = typehintNode->namespaceNameSequence->back(); + QString className = m_editor->parseSession()->symbol(it->element); + + if (isReservedClassName(className)) { + reportError(i18n("Cannot use '%1' as class name as it is reserved", className), typehintNode); + } + } + if (m_functionDeclarationPreviousArgument && m_functionDeclarationPreviousArgument->isVariadic != -1) { reportError(i18n("Only the last parameter can be variadic."), m_functionDeclarationPreviousArgument); } @@ -860,6 +888,19 @@ closeType(); closeDeclaration(); } + +void DeclarationBuilder::visitReturnType(ReturnTypeAst* node) { + if (node->typehint && isClassTypehint(node->typehint, m_editor)) { + NamespacedIdentifierAst* typehintNode = node->typehint->genericType; + const KDevPG::ListNode< IdentifierAst* >* it = typehintNode->namespaceNameSequence->back(); + QString className = m_editor->parseSession()->symbol(it->element); + + if (isReservedClassName(className)) { + reportError(i18n("Cannot use '%1' as class name as it is reserved", className), typehintNode); + } + } +} + void DeclarationBuilder::visitClosure(ClosureAst* node) { setComment(formatComment(node, editor())); @@ -1521,6 +1562,14 @@ decl->setKind(Declaration::NamespaceAlias); } closeDeclaration(); + + if (node->aliasIdentifier) { + QString aliasName = m_editor->parseSession()->symbol(node->aliasIdentifier); + + if (isReservedClassName(aliasName)) { + reportError(i18n("Cannot use %1 as %2 because '%2' is a special class name", qid.toString(), aliasName), node->aliasIdentifier); + } + } } void DeclarationBuilder::updateCurrentType() @@ -1561,4 +1610,17 @@ } } +bool DeclarationBuilder::isReservedClassName(QString className) +{ + return className.compare(QLatin1String("string"), Qt::CaseInsensitive) == 0 + || className.compare(QLatin1String("bool"), Qt::CaseInsensitive) == 0 + || className.compare(QLatin1String("int"), Qt::CaseInsensitive) == 0 + || className.compare(QLatin1String("float"), Qt::CaseInsensitive) == 0 + || className.compare(QLatin1String("iterable"), Qt::CaseInsensitive) == 0 + || className.compare(QLatin1String("null"), Qt::CaseInsensitive) == 0 + || className.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0 + || className.compare(QLatin1String("false"), Qt::CaseInsensitive) == 0; +} + + } 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 && node->parameterType->objectType) { - buildNamespaceUses(node->parameterType->objectType); + if (node->parameterType && node->parameterType->typehint && isClassTypehint(node->parameterType->typehint, m_editor)) { + buildNamespaceUses(node->parameterType->typehint->genericType); } if (node->defaultValue) { visitNodeWithExprVisitor(node->defaultValue); @@ -276,8 +276,8 @@ } void UseBuilder::visitReturnType(ReturnTypeAst* node) { - if (node->objectType) { - buildNamespaceUses(node->objectType); + if (node->typehint && isClassTypehint(node->typehint, m_editor)) { + buildNamespaceUses(node->typehint->genericType); } } diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -220,8 +220,8 @@ if (node->functionBody) { visitInnerStatementList(node->functionBody); } - if (node->returnType && node->returnType->objectType) { - NamespacedIdentifierAst* objectType = node->returnType->objectType; + if (node->returnType && node->returnType->typehint && isClassTypehint(node->returnType->typehint, m_editor)) { + NamespacedIdentifierAst* objectType = node->returnType->typehint->genericType; QualifiedIdentifier id = identifierForNamespace(objectType, m_editor); DeclarationPointer dec = findDeclarationImport(ClassDeclarationType, id); @@ -243,8 +243,9 @@ AbstractType::Ptr type = parameterType(it->element, {}, m_editor, m_currentContext); closureType->addArgument(type); - if (it->element->parameterType && it->element->parameterType->objectType) { - NamespacedIdentifierAst* objectType = it->element->parameterType->objectType; + if (it->element->parameterType && it->element->parameterType->typehint + && isClassTypehint(it->element->parameterType->typehint, m_editor)) { + NamespacedIdentifierAst* objectType = it->element->parameterType->typehint->genericType; QualifiedIdentifier id = identifierForNamespace(objectType, m_editor); DeclarationPointer dec = findDeclarationImport(ClassDeclarationType, id); diff --git a/duchain/helper.h b/duchain/helper.h --- a/duchain/helper.h +++ b/duchain/helper.h @@ -39,6 +39,7 @@ struct CommonScalarAst; struct NamespacedIdentifierAst; struct ParameterAst; +struct GenericTypeHintAst; struct ReturnTypeAst; class EditorIntegrator; @@ -52,6 +53,8 @@ KDEVPHPDUCHAIN_EXPORT bool isMatch(KDevelop::Declaration* declaration, DeclarationType declarationType); +KDEVPHPDUCHAIN_EXPORT bool isClassTypehint(GenericTypeHintAst* parameterType, EditorIntegrator *editor); + KDEVPHPDUCHAIN_EXPORT KDevelop::DeclarationPointer findDeclarationImportHelper(KDevelop::DUContext* currentContext, const KDevelop::QualifiedIdentifier& id, DeclarationType declarationType); diff --git a/duchain/helper.cpp b/duchain/helper.cpp --- a/duchain/helper.cpp +++ b/duchain/helper.cpp @@ -86,6 +86,37 @@ return false; } +bool isClassTypehint(GenericTypeHintAst* genericType, EditorIntegrator *editor) +{ + Q_ASSERT(genericType); + + if (genericType->callableType != -1) { + return false; + } else if (genericType->arrayType != -1) { + return false; + } else if (genericType->genericType) { + NamespacedIdentifierAst* node = genericType->genericType; + const KDevPG::ListNode< IdentifierAst* >* it = node->namespaceNameSequence->front(); + QString typehint = editor->parseSession()->symbol(it->element); + + if (typehint.compare(QLatin1String("bool"), Qt::CaseInsensitive) == 0) { + return false; + } else if (typehint.compare(QLatin1String("float"), Qt::CaseInsensitive) == 0) { + return false; + } else if (typehint.compare(QLatin1String("int"), Qt::CaseInsensitive) == 0) { + return false; + } else if (typehint.compare(QLatin1String("string"), Qt::CaseInsensitive) == 0) { + return false; + } else if (typehint.compare(QLatin1String("iterable"), Qt::CaseInsensitive) == 0) { + return false; + } else { + return true; + } + } else { + return false; + } +} + DeclarationPointer findDeclarationImportHelper(DUContext* currentContext, const QualifiedIdentifier& id, DeclarationType declarationType) { @@ -425,44 +456,52 @@ } template -AbstractType::Ptr determineTypehint(const T* parameterType, EditorIntegrator *editor, DUContext* currentContext) +AbstractType::Ptr determineTypehint(const T* genericType, EditorIntegrator *editor, DUContext* currentContext) { - Q_ASSERT(parameterType); + Q_ASSERT(genericType); AbstractType::Ptr type; - if (parameterType->objectType) { - //don't use openTypeFromName as it uses cursor for findDeclarations - DeclarationPointer decl = findDeclarationImportHelper(currentContext, - identifierForNamespace(parameterType->objectType, editor), ClassDeclarationType); - 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 (parameterType->callableType != -1) { - type = AbstractType::Ptr(new IntegralTypeExtended(IntegralTypeExtended::TypeCallable)); - } 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 (genericType->typehint) { + if (genericType->typehint->callableType != -1) { + type = AbstractType::Ptr(new IntegralTypeExtended(IntegralTypeExtended::TypeCallable)); + } else if (genericType->typehint->arrayType != -1) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); + } else if (genericType->typehint->genericType) { + NamespacedIdentifierAst* node = genericType->typehint->genericType; + const KDevPG::ListNode< IdentifierAst* >* it = node->namespaceNameSequence->front(); + QString typehint = editor->parseSession()->symbol(it->element); + + if (typehint.compare(QLatin1String("bool"), Qt::CaseInsensitive) == 0) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeBoolean)); + } else if (typehint.compare(QLatin1String("float"), Qt::CaseInsensitive) == 0) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeFloat)); + } else if (typehint.compare(QLatin1String("int"), Qt::CaseInsensitive) == 0) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeInt)); + } else if (typehint.compare(QLatin1String("string"), Qt::CaseInsensitive) == 0) { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeString)); + } else if (typehint.compare(QLatin1String("iterable"), Qt::CaseInsensitive) == 0) { + 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); + } + } else { + //don't use openTypeFromName as it uses cursor for findDeclarations + DeclarationPointer decl = findDeclarationImportHelper(currentContext, + identifierForNamespace(genericType->typehint->genericType, editor), ClassDeclarationType); + if (decl) { + type = decl->abstractType(); + } + } } } - if (type && parameterType->isNullable != -1) { + if (type && genericType->isNullable != -1) { AbstractType::Ptr nullType = AbstractType::Ptr(new IntegralType(IntegralType::TypeNull)); if (type.cast()) { UnsureType::Ptr unsure = type.cast(); diff --git a/duchain/tests/duchain.h b/duchain/tests/duchain.h --- a/duchain/tests/duchain.h +++ b/duchain/tests/duchain.h @@ -32,11 +32,14 @@ private slots: void declareFunction(); + void declareBaseTypeFunction(); void declareSemiReservedFunction(); void declareVar(); void varTypehint(); void declareClass(); + void declareBaseTypeClass(); void declareClassWithSemiReservedMethod(); + void declareClassWithBaseTypeMethod(); void classMemberVar(); void declareTypehintFunction(); void declareVariadicFunction(); @@ -149,7 +152,10 @@ void upcommingClassInString(); void namespaces(); void namespacesNoCurly(); + void namespacesBaseType(); void useNamespace(); + void useBaseTypeNamespace(); + void useNamespaceBaseTypeAlias(); void namespaceStaticVar(); void namespacedCatch(); void errorRecovery_data(); diff --git a/duchain/tests/duchain.cpp b/duchain/tests/duchain.cpp --- a/duchain/tests/duchain.cpp +++ b/duchain/tests/duchain.cpp @@ -86,6 +86,35 @@ QCOMPARE(top->childContexts().at(1)->type(), DUContext::Other); } +void TestDUChain::declareBaseTypeFunction() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + QByteArray method("childContexts().count(), 2); + QCOMPARE(top->localDeclarations().count(), 1); + + Declaration* dec = top->localDeclarations().at(0); + QVERIFY(dec); + QCOMPARE(dec->context(), top); + QCOMPARE(dec->internalContext(), top->childContexts().at(1)); + + // no return means void as return type + FunctionType::Ptr ftype = FunctionType::Ptr::dynamicCast(dec->abstractType()); + QVERIFY(ftype); + IntegralType::Ptr itype = IntegralType::Ptr::dynamicCast(ftype->returnType()); + QVERIFY(itype->dataType() == IntegralType::TypeVoid); + + + QCOMPARE(top->childContexts().at(0)->type(), DUContext::Function); + QCOMPARE(top->childContexts().at(1)->type(), DUContext::Other); +} + void TestDUChain::declareSemiReservedFunction() { // 0 1 2 3 4 5 6 7 @@ -250,6 +279,20 @@ QCOMPARE(funDec->accessPolicy(), Declaration::Public); } +void TestDUChain::declareBaseTypeClass() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + QByteArray method("problems().count(), 1); +} + void TestDUChain::declareClassWithSemiReservedMethod() { // 0 1 2 3 4 5 6 7 @@ -311,6 +354,67 @@ QCOMPARE(funDec->isStatic(), true); } +void TestDUChain::declareClassWithBaseTypeMethod() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + QByteArray method("parentContext()); + QCOMPARE(top->childContexts().count(), 1); + + DUContext* contextClassA = top->childContexts().first(); + + QCOMPARE(top->localDeclarations().count(), 1); + Declaration* dec = top->localDeclarations().first(); + QCOMPARE(dec->kind(), Declaration::Type); + QCOMPARE(dec->toString(), QString("class A")); + QCOMPARE(dec->qualifiedIdentifier(), QualifiedIdentifier("a")); + QCOMPARE(dec->isDefinition(), true); + QCOMPARE(dec->logicalInternalContext(top), contextClassA); + + qDebug() << contextClassA->localScopeIdentifier().toString(); + QCOMPARE(contextClassA->localScopeIdentifier(), QualifiedIdentifier("a")); + QCOMPARE(contextClassA->childContexts().count(), 4); + QCOMPARE(contextClassA->childContexts().first()->localScopeIdentifier(), QualifiedIdentifier("string")); + + DUContext* contextMethodBodyFoo = contextClassA->childContexts().at(1); + QCOMPARE(contextMethodBodyFoo->localScopeIdentifier(), QualifiedIdentifier("string")); + QCOMPARE(contextMethodBodyFoo->importedParentContexts().count(), 1); + QCOMPARE(contextMethodBodyFoo->childContexts().count(), 0); + QVERIFY(contextMethodBodyFoo->importedParentContexts().first().context(top) == + contextClassA->childContexts().first()); + + //string() + dec = contextClassA->localDeclarations().at(0); + ClassFunctionDeclaration* funDec = dynamic_cast(dec); + QVERIFY(funDec); + QCOMPARE(funDec->kind(), Declaration::Type); + QCOMPARE(funDec->identifier(), Identifier("string")); + QCOMPARE(funDec->accessPolicy(), Declaration::Public); + QCOMPARE(funDec->isStatic(), false); + + { + // no return means void as return type + FunctionType::Ptr ftype = FunctionType::Ptr::dynamicCast(dec->abstractType()); + QVERIFY(ftype); + IntegralType::Ptr itype = IntegralType::Ptr::dynamicCast(ftype->returnType()); + QVERIFY(itype->dataType() == IntegralType::TypeVoid); + } + + //iterable() + dec = contextClassA->localDeclarations().at(1); + funDec = dynamic_cast(dec); + QVERIFY(funDec); + QCOMPARE(funDec->identifier(), Identifier("iterable")); + QCOMPARE(funDec->accessPolicy(), Declaration::Protected); + QCOMPARE(funDec->isStatic(), true); +} + void TestDUChain::classMemberVar() { // 0 1 2 3 4 5 6 7 @@ -1380,7 +1484,7 @@ { // 0 1 2 3 4 5 6 7 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 - QByteArray method("findDeclarations(QualifiedIdentifier("a::PUBLIC")).count(), 1); QCOMPARE(top->findDeclarations(QualifiedIdentifier("a::PUBLIC")).first()->context(), top->childContexts().last()); + + QCOMPARE(top->findDeclarations(QualifiedIdentifier("a::STRING")).count(), 1); + QCOMPARE(top->findDeclarations(QualifiedIdentifier("a::STRING")).first()->context(), top->childContexts().last()); } void TestDUChain::fileConst_data() @@ -3008,6 +3115,31 @@ QCOMPARE(top->localDeclarations().at(1)->kind(), Declaration::Namespace); } +void TestDUChain::namespacesBaseType() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + TopDUContext* top = parse("problems().count(), 0); + foreach(ProblemPointer p, top->problems()) { + qDebug() << p->description() << p->explanation() << p->finalLocation(); + } + QCOMPARE(top->childContexts().size(), 1); + QCOMPARE(top->childContexts().at(0)->localScopeIdentifier().toString(), QString("string")); + + QCOMPARE(top->localDeclarations().size(), 1); + QCOMPARE(top->localDeclarations().at(0)->kind(), Declaration::Namespace); +} + void TestDUChain::useNamespace() { // 0 1 2 3 4 5 6 7 @@ -3049,6 +3181,66 @@ QVERIFY(!dynamic_cast(dec)->importIdentifier().explicitlyGlobal()); } +void TestDUChain::useBaseTypeNamespace() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + TopDUContext* top = parse("localDeclarations().count(), 4); + + Declaration* dec = top->localDeclarations().at(2); + QCOMPARE(dec->qualifiedIdentifier().toString(), QString("string")); + QVERIFY(dynamic_cast(dec)); + + dec = top->localDeclarations().at(3); + QCOMPARE(dec->qualifiedIdentifier().toString(), QString("iterable")); + QVERIFY(dynamic_cast(dec)); +} + +void TestDUChain::useNamespaceBaseTypeAlias() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + TopDUContext* top = parse("problems().count(), 2); +} + void TestDUChain::namespaceStaticVar() { // 0 1 2 3 4 5 6 7 diff --git a/parser/php.g b/parser/php.g --- a/parser/php.g +++ b/parser/php.g @@ -237,7 +237,6 @@ 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"), - ITERABLE ("iterable"), BOOL ("bool"), FLOAT ("float"), INT ("int"), STRING_TYPE ("string"), VOID ("void"), DIR ("__DIR__"), TRAIT_C ("__TRAIT__"), YIELD ("yield") ;; -- casts: @@ -896,27 +895,16 @@ (isVariadic=ELLIPSIS | 0) variable=variableIdentifier (ASSIGN defaultValue=expr | 0) -> parameter ;; - (isNullable=QUESTION | 0) ( - objectType=namespacedIdentifier - | arrayType=ARRAY - | callableType=CALLABLE - | iterableType=ITERABLE - | boolType=BOOL - | floatType=FLOAT - | intType=INT - | stringType=STRING_TYPE - ) + genericType=namespacedIdentifier + | arrayType=ARRAY + | callableType=CALLABLE +-> genericTypeHint ;; + + (isNullable=QUESTION | 0) typehint=genericTypeHint -> parameterType ;; (isNullable=QUESTION | 0) ( - objectType=namespacedIdentifier - | arrayType=ARRAY - | callableType=CALLABLE - | iterableType=ITERABLE - | boolType=BOOL - | floatType=FLOAT - | intType=INT - | stringType=STRING_TYPE + typehint=genericTypeHint | voidType=VOID ) -> returnType ;; diff --git a/parser/phplexer.cpp b/parser/phplexer.cpp --- a/parser/phplexer.cpp +++ b/parser/phplexer.cpp @@ -798,16 +798,6 @@ 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 if (name.compare(QLatin1String("void"), Qt::CaseInsensitive) == 0) { token = Parser::Token_VOID; } else if (name.compare(QLatin1String("yield"), Qt::CaseInsensitive) == 0) { diff --git a/parser/test/lexertest.cpp b/parser/test/lexertest.cpp --- a/parser/test/lexertest.cpp +++ b/parser/test/lexertest.cpp @@ -471,7 +471,7 @@ COMPARE_TOKEN(ts, 5, Parser::Token_RPAREN, 1, 11, 1, 11); COMPARE_TOKEN(ts, 6, Parser::Token_COLON, 1, 12, 1, 12); COMPARE_TOKEN(ts, 7, Parser::Token_WHITESPACE, 1, 13, 1, 13); - COMPARE_TOKEN(ts, 8, Parser::Token_STRING_TYPE, 1, 14, 1, 19); + COMPARE_TOKEN(ts, 8, Parser::Token_STRING, 1, 14, 1, 19); COMPARE_TOKEN(ts, 9, Parser::Token_WHITESPACE, 1, 20, 1, 20); COMPARE_TOKEN(ts, 10, Parser::Token_LBRACE, 1, 21, 1, 21); COMPARE_TOKEN(ts, 11, Parser::Token_RBRACE, 1, 22, 1, 22);