diff --git a/duchain/builders/declarationbuilder.h b/duchain/builders/declarationbuilder.h --- a/duchain/builders/declarationbuilder.h +++ b/duchain/builders/declarationbuilder.h @@ -96,7 +96,8 @@ void openNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier, const KDevelop::RangeInRevision& range) override; void closeNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier) override; void visitUseStatement(UseStatementAst* node) override; - void visitUseNamespace(UseNamespaceAst* node) override; + void visitUseNamespaceOrUseGroupedNamespace(UseNamespaceOrUseGroupedNamespaceAst* node) override; + void visitNonGroupedUseNamespace(UseNamespaceOrUseGroupedNamespaceAst* node); void visitClosure(ClosureAst* node) override; void visitLexicalVar(LexicalVarAst* node) override; void visitVarExpression(VarExpressionAst* node) override; diff --git a/duchain/builders/declarationbuilder.cpp b/duchain/builders/declarationbuilder.cpp --- a/duchain/builders/declarationbuilder.cpp +++ b/duchain/builders/declarationbuilder.cpp @@ -1642,7 +1642,14 @@ DeclarationBuilderBase::visitUseStatement(node); } -void DeclarationBuilder::visitUseNamespace(UseNamespaceAst* node) +void DeclarationBuilder::visitUseNamespaceOrUseGroupedNamespace(UseNamespaceOrUseGroupedNamespaceAst* node) +{ + if (!node->compoundNamespace) { + visitNonGroupedUseNamespace(node); + } +} + +void DeclarationBuilder::visitNonGroupedUseNamespace(UseNamespaceOrUseGroupedNamespaceAst* node) { DUChainWriteLocker lock; bool isConstIdentifier = ( m_useNamespaceType == ConstantDeclarationType ); diff --git a/duchain/builders/typebuilder.cpp b/duchain/builders/typebuilder.cpp --- a/duchain/builders/typebuilder.cpp +++ b/duchain/builders/typebuilder.cpp @@ -348,6 +348,7 @@ } } else { //member-variable + m_gotTypeFromTypeHint = false; parseDocComment(node, QStringLiteral("var")); TypeBuilderBase::visitClassStatement(node); if (m_gotTypeFromDocComment) { diff --git a/duchain/builders/usebuilder.h b/duchain/builders/usebuilder.h --- a/duchain/builders/usebuilder.h +++ b/duchain/builders/usebuilder.h @@ -67,13 +67,22 @@ void visitCatchItem(CatchItemAst* node) override; void visitUnaryExpression( UnaryExpressionAst* node ) override; void visitUseStatement(UseStatementAst* node) override; - void visitUseNamespace(UseNamespaceAst* node) override; + void visitUseNamespaceOrUseGroupedNamespace(UseNamespaceOrUseGroupedNamespaceAst* node) override; void openNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier, const KDevelop::RangeInRevision& range) override; void visitPropertyType(PropertyTypeAst* node) override; void visitReturnType(ReturnTypeAst* node) override; private: - void buildNamespaceUses(Php::NamespacedIdentifierAst* node, Php::DeclarationType lastType = Php::ClassDeclarationType); + void buildNamespaceUses( + Php::NamespacedIdentifierAst* node, + Php::DeclarationType lastType = Php::ClassDeclarationType); + void buildNamespaceUses( + Php::NamespacedIdentifierBeforeGroupedNamespaceAst* node, + Php::DeclarationType lastType = Php::ClassDeclarationType); + void buildNamespaceUses( + KDevelop::QualifiedIdentifier identifier, + const KDevPG::ListNode* namespaceNameSequence, + Php::DeclarationType lastType); void visitNodeWithExprVisitor(AstNode* node); diff --git a/duchain/builders/usebuilder.cpp b/duchain/builders/usebuilder.cpp --- a/duchain/builders/usebuilder.cpp +++ b/duchain/builders/usebuilder.cpp @@ -244,15 +244,30 @@ UseBuilderBase::visitUseStatement(node); } -void UseBuilder::visitUseNamespace(UseNamespaceAst* node) +void UseBuilder::visitUseNamespaceOrUseGroupedNamespace(UseNamespaceOrUseGroupedNamespaceAst* node) { - buildNamespaceUses(node->identifier, m_useNamespaceType); + if (!node->compoundNamespace) { + buildNamespaceUses(node->identifier, m_useNamespaceType); + } +} + +void UseBuilder::buildNamespaceUses(NamespacedIdentifierBeforeGroupedNamespaceAst* node, DeclarationType lastType) +{ + QualifiedIdentifier identifier = identifierForNamespace(node, m_editor, lastType == ConstantDeclarationType); + buildNamespaceUses(identifier, node->namespaceNameSequence, lastType); } void UseBuilder::buildNamespaceUses(NamespacedIdentifierAst* node, DeclarationType lastType) { QualifiedIdentifier identifier = identifierForNamespace(node, m_editor, lastType == ConstantDeclarationType); + buildNamespaceUses(identifier, node->namespaceNameSequence, lastType); +} +void UseBuilder::buildNamespaceUses( + KDevelop::QualifiedIdentifier identifier, + const KDevPG::ListNode* namespaceNameSequence, + Php::DeclarationType lastType) +{ QualifiedIdentifier curId; // check if we need to resolve the namespaced identifier globally or locally @@ -278,16 +293,16 @@ } curId.setExplicitlyGlobal(identifier.explicitlyGlobal()); - Q_ASSERT(identifier.count() == node->namespaceNameSequence->count()); + Q_ASSERT(identifier.count() == namespaceNameSequence->count()); for ( int i = 0; i < identifier.count() - 1; ++i ) { curId.push(identifier.at(i)); - AstNode* n = node->namespaceNameSequence->at(i)->element; + AstNode* n = namespaceNameSequence->at(i)->element; DeclarationPointer dec = findDeclarationImport(NamespaceDeclarationType, curId); if (!dec || dec->range() != editorFindRange(n, n)) { newCheckedUse(n, dec, true); } } - newCheckedUse(node->namespaceNameSequence->back()->element, + newCheckedUse(namespaceNameSequence->back()->element, findDeclarationImport(lastType, identifier), lastType == ClassDeclarationType || lastType == ConstantDeclarationType || lastType == FunctionDeclarationType || lastType == NamespaceDeclarationType); diff --git a/duchain/helper.h b/duchain/helper.h --- a/duchain/helper.h +++ b/duchain/helper.h @@ -38,6 +38,7 @@ struct AstNode; struct CommonScalarAst; struct NamespacedIdentifierAst; +struct NamespacedIdentifierBeforeGroupedNamespaceAst; struct ParameterAst; struct GenericTypeHintAst; struct ReturnTypeAst; @@ -96,6 +97,10 @@ */ KDEVPHPDUCHAIN_EXPORT KDevelop::QualifiedIdentifier identifierForNamespace(NamespacedIdentifierAst* node, EditorIntegrator* editor, bool lastIsConstIdentifier = false); +KDEVPHPDUCHAIN_EXPORT KDevelop::QualifiedIdentifier identifierForNamespace( + NamespacedIdentifierBeforeGroupedNamespaceAst* node, + EditorIntegrator* editor, + bool lastIsConstIdentifier = false); /** * Get proper QualifiedIdentifier for a basic identifier. diff --git a/duchain/helper.cpp b/duchain/helper.cpp --- a/duchain/helper.cpp +++ b/duchain/helper.cpp @@ -456,6 +456,23 @@ return id; } +QualifiedIdentifier identifierForNamespace(NamespacedIdentifierBeforeGroupedNamespaceAst* node, EditorIntegrator* editor, bool lastIsConstIdentifier) +{ + QualifiedIdentifier id; + if (node->isGlobal != -1) { + id.setExplicitlyGlobal(true); + } + const KDevPG::ListNode< IdentifierAst* >* it = node->namespaceNameSequence->front(); + do { + if (lastIsConstIdentifier && !it->hasNext()) { + id.push(Identifier(editor->parseSession()->symbol(it->element))); + } else { + id.push(Identifier(editor->parseSession()->symbol(it->element).toLower())); + } + } while (it->hasNext() && (it = it->next)); + return id; +} + QualifiedIdentifier identifierWithNamespace(const QualifiedIdentifier& base, DUContext* context) { DUChainReadLocker lock; diff --git a/parser/php.g b/parser/php.g --- a/parser/php.g +++ b/parser/php.g @@ -728,11 +728,23 @@ | gotoTarget=STRING COLON -> statement ;; - ( useFunction=FUNCTION | useConst=CONST | 0 ) #useNamespace=useNamespace @ COMMA SEMICOLON + ( useFunction=FUNCTION | useConst=CONST | 0 ) #useNamespace=useNamespaceOrUseGroupedNamespace @ COMMA SEMICOLON -> useStatement ;; - identifier=namespacedIdentifier (AS aliasIdentifier=identifier | 0) --> useNamespace ;; + identifier=namespacedIdentifierBeforeGroupedNamespace + (AS aliasIdentifier=identifier | compoundNamespace=compoundNamespace | 0) +-> useNamespaceOrUseGroupedNamespace ;; + + LBRACE + ( ( useFunction=FUNCTION | useConst=CONST | 0 ) #useNamespace=innerUseNamespace ) + -- break because "use Foo\{bar1,}" is allowed (solves FIRST/FOLLOW conflict) + @ (COMMA [: if (yytoken == Token_RBRACE) { break; } :] ) + RBRACE +-> compoundNamespace;; + + #namespaceName=identifier+ @ BACKSLASH + (AS aliasIdentifier=identifier | 0) +-> innerUseNamespace;; identifier=identifier ASSIGN scalar=expr -> constantDeclaration ;; @@ -939,6 +951,10 @@ #namespaceName=identifier+ @ BACKSLASH -> namespacedIdentifier ;; + (isGlobal=BACKSLASH | 0) + #namespaceName=identifier+ @ ( BACKSLASH [: if (yytoken == Token_LBRACE) { break; } :] ) +-> namespacedIdentifierBeforeGroupedNamespace ;; + string=STRING -> identifier ;;