diff --git a/duchain/builders/contextbuilder.h b/duchain/builders/contextbuilder.h --- a/duchain/builders/contextbuilder.h +++ b/duchain/builders/contextbuilder.h @@ -69,7 +69,7 @@ KDevelop::QualifiedIdentifier identifierForNode(IdentifierAst* id) override; KDevelop::QualifiedIdentifier identifierForNode(SemiReservedIdentifierAst* id); KDevelop::QualifiedIdentifier identifierForNode(VariableIdentifierAst* id); - IdentifierPair identifierPairForNode(IdentifierAst* id); + IdentifierPair identifierPairForNode(IdentifierAst* id, bool isConstIdentifier = false); IdentifierPair identifierPairForNode(SemiReservedIdentifierAst* id); IdentifierPair identifierPairForNode(ReservedNonModifierIdentifierAst* id); QString stringForNode(IdentifierAst* node) const; diff --git a/duchain/builders/contextbuilder.cpp b/duchain/builders/contextbuilder.cpp --- a/duchain/builders/contextbuilder.cpp +++ b/duchain/builders/contextbuilder.cpp @@ -201,14 +201,18 @@ return QualifiedIdentifier(ret); } -IdentifierPair ContextBuilder::identifierPairForNode(IdentifierAst* id ) +IdentifierPair ContextBuilder::identifierPairForNode(IdentifierAst* id, bool isConstIdentifier) { if (!id) { return qMakePair(IndexedString(), QualifiedIdentifier()); } const QString ret = stringForNode(id); - return qMakePair(IndexedString(ret), QualifiedIdentifier(ret.toLower())); + if ( isConstIdentifier ) { + return qMakePair(IndexedString(ret), QualifiedIdentifier(ret)); + } else { + return qMakePair(IndexedString(ret), QualifiedIdentifier(ret.toLower())); + } } IdentifierPair ContextBuilder::identifierPairForNode(SemiReservedIdentifierAst* id ) diff --git a/duchain/builders/declarationbuilder.h b/duchain/builders/declarationbuilder.h --- a/duchain/builders/declarationbuilder.h +++ b/duchain/builders/declarationbuilder.h @@ -55,6 +55,7 @@ { m_editor = editor; m_findVariable.find = false; + m_useNamespaceType = ClassDeclarationType; } KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url, AstNode* node, const KDevelop::ReferencedTopDUContext& updateContext @@ -94,6 +95,7 @@ void visitAssignmentListElement(AssignmentListElementAst* node) override; 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 visitClosure(ClosureAst* node) override; void visitLexicalVar(LexicalVarAst* node) override; @@ -150,6 +152,8 @@ ParameterAst *m_functionDeclarationPreviousArgument = nullptr; /// The AstNode of the previous function call argument FunctionCallParameterListElementAst *m_functionCallPreviousArgument = nullptr; + /// Type of use + DeclarationType m_useNamespaceType; unsigned int m_currentModifers; QString m_lastTopStatementComment; diff --git a/duchain/builders/declarationbuilder.cpp b/duchain/builders/declarationbuilder.cpp --- a/duchain/builders/declarationbuilder.cpp +++ b/duchain/builders/declarationbuilder.cpp @@ -1625,9 +1625,27 @@ closeDeclaration(); } +void DeclarationBuilder::visitUseStatement(UseStatementAst* node) +{ + if ( node->useFunction != -1 ) + { + m_useNamespaceType = FunctionDeclarationType; + } + else if ( node->useConst != -1 ) + { + m_useNamespaceType = ConstantDeclarationType; + } + else + { + m_useNamespaceType = ClassDeclarationType; + } + DeclarationBuilderBase::visitUseStatement(node); +} + void DeclarationBuilder::visitUseNamespace(UseNamespaceAst* node) { DUChainWriteLocker lock; + bool isConstIdentifier = ( m_useNamespaceType == ConstantDeclarationType ); if ( currentContext()->type() != DUContext::Namespace && !node->aliasIdentifier && node->identifier->namespaceNameSequence->count() == 1 ) { @@ -1637,23 +1655,22 @@ return; } IdentifierAst* idNode = node->aliasIdentifier ? node->aliasIdentifier : node->identifier->namespaceNameSequence->back()->element; - IdentifierPair id = identifierPairForNode(idNode); + IdentifierPair id = identifierPairForNode(idNode, isConstIdentifier); ///TODO: case insensitive! - QualifiedIdentifier qid = identifierForNamespace(node->identifier, m_editor); - - DeclarationPointer dec = findDeclarationImport(ClassDeclarationType, qid); + QualifiedIdentifier qid = identifierForNamespace(node->identifier, m_editor, isConstIdentifier); + DeclarationPointer dec = findDeclarationImport(m_useNamespaceType, qid); if (!dec && !qid.explicitlyGlobal()) { QualifiedIdentifier globalQid = qid; globalQid.setExplicitlyGlobal(true); - dec = findDeclarationImport(ClassDeclarationType, globalQid); + dec = findDeclarationImport(m_useNamespaceType, globalQid); } if (dec) { // Check for a name conflict - DeclarationPointer dec2 = findDeclarationImport(ClassDeclarationType, id.second); + DeclarationPointer dec2 = findDeclarationImport(m_useNamespaceType, id.second); if (dec2 && dec2->context()->scopeIdentifier() == currentContext()->scopeIdentifier() && dec2->context()->topContext() == currentContext()->topContext() && diff --git a/duchain/builders/usebuilder.h b/duchain/builders/usebuilder.h --- a/duchain/builders/usebuilder.h +++ b/duchain/builders/usebuilder.h @@ -66,6 +66,7 @@ void visitStatement(StatementAst* node) override; void visitCatchItem(CatchItemAst* node) override; void visitUnaryExpression( UnaryExpressionAst* node ) override; + void visitUseStatement(UseStatementAst* node) override; void visitUseNamespace(UseNamespaceAst* node) override; void openNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier, const KDevelop::RangeInRevision& range) override; void visitReturnType(ReturnTypeAst* node) override; @@ -74,6 +75,9 @@ void buildNamespaceUses(Php::NamespacedIdentifierAst* node, Php::DeclarationType lastType = Php::ClassDeclarationType); void visitNodeWithExprVisitor(AstNode* node); + + /// Type of use + DeclarationType m_useNamespaceType; }; } diff --git a/duchain/builders/usebuilder.cpp b/duchain/builders/usebuilder.cpp --- a/duchain/builders/usebuilder.cpp +++ b/duchain/builders/usebuilder.cpp @@ -227,19 +227,36 @@ } } +void UseBuilder::visitUseStatement(UseStatementAst* node) +{ + if ( node->useFunction != -1 ) + { + m_useNamespaceType = FunctionDeclarationType; + } + else if ( node->useConst != -1 ) + { + m_useNamespaceType = ConstantDeclarationType; + } + else + { + m_useNamespaceType = NamespaceDeclarationType; + } + UseBuilderBase::visitUseStatement(node); +} + void UseBuilder::visitUseNamespace(UseNamespaceAst* node) { - buildNamespaceUses(node->identifier, NamespaceDeclarationType); + buildNamespaceUses(node->identifier, m_useNamespaceType); } void UseBuilder::buildNamespaceUses(NamespacedIdentifierAst* node, DeclarationType lastType) { - QualifiedIdentifier identifier = identifierForNamespace(node, m_editor); + QualifiedIdentifier identifier = identifierForNamespace(node, m_editor, lastType == ConstantDeclarationType); QualifiedIdentifier curId; // check if we need to resolve the namespaced identifier globally or locally - DeclarationPointer tempDec = findDeclarationImport(ClassDeclarationType, identifier); + DeclarationPointer tempDec = findDeclarationImport(lastType, identifier); // if we couldn't find a class declaration, it might be a partial namespace identifier if (!tempDec) { @@ -248,7 +265,7 @@ if (!tempDec && !identifier.explicitlyGlobal()) { identifier.setExplicitlyGlobal(true); - tempDec = findDeclarationImport(ClassDeclarationType, identifier); + tempDec = findDeclarationImport(lastType, identifier); if (!tempDec) { tempDec = findDeclarationImport(NamespaceDeclarationType, identifier); diff --git a/duchain/tests/uses.h b/duchain/tests/uses.h --- a/duchain/tests/uses.h +++ b/duchain/tests/uses.h @@ -82,6 +82,7 @@ void functionArguments(); void namespaces(); void useNamespace(); + void useNamespaceFunctionConst(); void lateStatic(); void closures(); void closureTypehints(); diff --git a/duchain/tests/uses.cpp b/duchain/tests/uses.cpp --- a/duchain/tests/uses.cpp +++ b/duchain/tests/uses.cpp @@ -1101,6 +1101,50 @@ compareUses(dec, RangeInRevision(8, 30, 8, 31)); } + +void TestUses::useNamespaceFunctionConst() +{ + // 0 1 2 3 4 5 6 7 + // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + TopDUContext* top = parse("findDeclarations(QualifiedIdentifier(QStringLiteral("a"))).first(); + QVERIFY(dec); + QCOMPARE(dec->kind(), Declaration::Type); + compareUses(dec, QList() << RangeInRevision(4, 21, 4, 22) << RangeInRevision(8, 5, 8, 6)); + + dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("B"))).first(); + QVERIFY(dec); + QCOMPARE(dec->kind(), Declaration::Instance); + compareUses(dec, QList() << RangeInRevision(5, 18, 5, 19) << RangeInRevision(9, 5, 9, 6)); + + dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("bazc"))).first(); + QVERIFY(dec); + QCOMPARE(dec->kind(), Declaration::Type); + compareUses(dec, QList() << RangeInRevision(6, 17, 6, 18) << RangeInRevision(10, 5, 10, 9)); + + dec = top->findDeclarations(QualifiedIdentifier(QStringLiteral("BazD"))).first(); + QVERIFY(dec); + QCOMPARE(dec->kind(), Declaration::Instance); + compareUses(dec, QList() << RangeInRevision(7, 14, 7, 15) << RangeInRevision(11, 5, 11, 9)); +} + void TestUses::lateStatic() { // 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 @@ -723,11 +723,14 @@ | OPEN_TAG_WITH_ECHO expr=expr semicolonOrCloseTag | INLINE_HTML | CONST #consts=constantDeclaration @ COMMA SEMICOLON - | USE #useNamespace=useNamespace @ COMMA SEMICOLON + | USE useStatement=useStatement | GOTO gotoLabel=STRING SEMICOLON | gotoTarget=STRING COLON -> statement ;; + ( useFunction=FUNCTION | useConst=CONST | 0 ) #useNamespace=useNamespace @ COMMA SEMICOLON +-> useStatement ;; + identifier=namespacedIdentifier (AS aliasIdentifier=identifier | 0) -> useNamespace ;;