diff --git a/language/duchain/declarationid.cpp b/language/duchain/declarationid.cpp index 0cdde0ff1f..ffd4c9f23d 100644 --- a/language/duchain/declarationid.cpp +++ b/language/duchain/declarationid.cpp @@ -1,206 +1,245 @@ /* This file is part of KDevelop Copyright 2008 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "declarationid.h" #include "ducontext.h" #include "topducontext.h" #include "duchain.h" #include "declaration.h" #include "persistentsymboltable.h" #include "instantiationinformation.h" #include "../editor/cursorinrevision.h" #include namespace KDevelop { DeclarationId::DeclarationId(const IndexedQualifiedIdentifier& id, uint additionalId, const IndexedInstantiationInformation& specialization) : m_indirectData{id, additionalId} , m_isDirect(false) , m_specialization(specialization) { } DeclarationId::DeclarationId(const IndexedDeclaration& decl, const IndexedInstantiationInformation& specialization) : m_directData(decl) , m_isDirect(true) , m_specialization(specialization) { } DeclarationId::DeclarationId(const DeclarationId& rhs) : m_isDirect(rhs.m_isDirect) , m_specialization(rhs.m_specialization) { if (!m_isDirect) { // IndexedQualifiedIdentifier doesn't like zero-initialization... new (&m_indirectData.identifier) IndexedQualifiedIdentifier(rhs.m_indirectData.identifier); m_indirectData.additionalIdentity = rhs.m_indirectData.additionalIdentity; } else { m_directData = rhs.m_directData; } } DeclarationId::~DeclarationId() { if (!m_isDirect) { m_indirectData.~Indirect(); } } DeclarationId& DeclarationId::operator=(const DeclarationId& rhs) { if (&rhs == this) return *this; m_isDirect = rhs.m_isDirect; m_specialization = rhs.m_specialization; if (!m_isDirect) { m_indirectData = rhs.m_indirectData; } else { m_directData = rhs.m_directData; } return *this; } bool DeclarationId::isDirect() const { return m_isDirect; } void DeclarationId::setSpecialization(const IndexedInstantiationInformation& spec) { m_specialization = spec; } IndexedInstantiationInformation DeclarationId::specialization() const { return m_specialization; } -void DeclarationId::iterateDeclarations(const TopDUContext* top, std::function func) const +KDevVarLengthArray DeclarationId::getDeclarations(const TopDUContext* top) const { + KDevVarLengthArray ret; + if(m_isDirect == false) { //Find the declaration by its qualified identifier and additionalIdentity - const QualifiedIdentifier id(m_indirectData.identifier); + QualifiedIdentifier id(m_indirectData.identifier); if(top) { //Do filtering PersistentSymbolTable::FilteredDeclarationIterator filter = PersistentSymbolTable::self().getFilteredDeclarations(id, top->recursiveImportIndices()); for(; filter; ++filter) { Declaration* decl = filter->data(); if(decl && m_indirectData.additionalIdentity == decl->additionalIdentity()) { - if (func(decl)) - break; + //Hit + ret.append(decl); } } }else{ //Just accept anything PersistentSymbolTable::Declarations decls = PersistentSymbolTable::self().getDeclarations(id); PersistentSymbolTable::Declarations::Iterator decl = decls.iterator(); for(; decl; ++decl) { const IndexedDeclaration& iDecl(*decl); - ///@todo think this over once we don't pull in all imported top-context any more + ///@todo think this over once we don't pull in all imported top-context any more //Don't trigger loading of top-contexts from here, it will create a lot of problems if((!DUChain::self()->isInMemory(iDecl.topContextIndex()))) continue; if(!top) { Declaration* decl = iDecl.data(); if(decl && m_indirectData.additionalIdentity == decl->additionalIdentity()) { //Hit - if (func(decl)) - break; + ret.append(decl); } } } } }else{ - func(m_directData.declaration()); + Declaration* decl = m_directData.declaration(); + if(decl) + ret.append(decl); } -} - -KDevVarLengthArray DeclarationId::getDeclarations(const TopDUContext* top) const -{ - KDevVarLengthArray ret; - - iterateDeclarations(top, [&ret](Declaration* decl){ - ret.append(decl); - return false; - }); if(!ret.isEmpty() && m_specialization.index()) { KDevVarLengthArray newRet; foreach (Declaration* decl, ret) { Declaration* specialized = decl->specialize(m_specialization, top ? top : decl->topContext()); if(specialized) newRet.append(specialized); } return newRet; } return ret; } Declaration* DeclarationId::getDeclaration(const TopDUContext* top, bool instantiateIfRequired) const { - Declaration* ret = nullptr; + Declaration* ret = 0; - iterateDeclarations(top, [&ret](Declaration* decl){ - ret = decl; - return !ret->isForwardDeclaration(); - }); + if(m_isDirect == false) { + //Find the declaration by its qualified identifier and additionalIdentity + QualifiedIdentifier id(m_indirectData.identifier); - if(ret && m_specialization.isValid()) - { - const TopDUContext* topContextForSpecialization = top; - if(!instantiateIfRequired) - topContextForSpecialization = 0; //If we don't want to instantiate new declarations, set the top-context to zero, so specialize(..) will only look-up - else if(!topContextForSpecialization) - topContextForSpecialization = ret->topContext(); + if(top) { + //Do filtering + PersistentSymbolTable::FilteredDeclarationIterator filter = + PersistentSymbolTable::self().getFilteredDeclarations(id, top->recursiveImportIndices()); + for(; filter; ++filter) { + Declaration* decl = filter->data(); + if(decl && m_indirectData.additionalIdentity == decl->additionalIdentity()) { + //Hit + ret = decl; + if(!ret->isForwardDeclaration()) + break; + } + } + }else{ + //Just accept anything + PersistentSymbolTable::Declarations decls = PersistentSymbolTable::self().getDeclarations(id); + PersistentSymbolTable::Declarations::Iterator decl = decls.iterator(); + for(; decl; ++decl) { + const IndexedDeclaration& iDecl(*decl); + + ///@todo think this over once we don't pull in all imported top-context any more + //Don't trigger loading of top-contexts from here, it will create a lot of problems + if((!DUChain::self()->isInMemory(iDecl.topContextIndex()))) + continue; - return ret->specialize(m_specialization, topContextForSpecialization); + if(!top) { + Declaration* decl = iDecl.data(); + if(decl && m_indirectData.additionalIdentity == decl->additionalIdentity()) { + //Hit + ret = decl; + if(!ret->isForwardDeclaration()) + break; + } + } + } + } + }else{ + //Find the declaration by m_topContext and m_declaration + ret = m_directData.declaration(); } - return ret; + + + if(ret) + { + if(m_specialization.isValid()) + { + const TopDUContext* topContextForSpecialization = top; + if(!instantiateIfRequired) + topContextForSpecialization = 0; //If we don't want to instantiate new declarations, set the top-context to zero, so specialize(..) will only look-up + else if(!topContextForSpecialization) + topContextForSpecialization = ret->topContext(); + + return ret->specialize(m_specialization, topContextForSpecialization); + }else{ + return ret; + } + }else + return 0; } QualifiedIdentifier DeclarationId::qualifiedIdentifier() const { if(!m_isDirect) { QualifiedIdentifier baseIdentifier = m_indirectData.identifier.identifier(); if(!m_specialization.index()) return baseIdentifier; return m_specialization.information().applyToIdentifier(baseIdentifier); } else { Declaration* decl = getDeclaration(0); if(decl) return decl->qualifiedIdentifier(); return QualifiedIdentifier(i18n("(unknown direct declaration)")); } return QualifiedIdentifier(i18n("(missing)")) + m_indirectData.identifier.identifier(); } } diff --git a/language/duchain/declarationid.h b/language/duchain/declarationid.h index 0d23e96731..775c3cf860 100644 --- a/language/duchain/declarationid.h +++ b/language/duchain/declarationid.h @@ -1,213 +1,210 @@ /* This file is part of KDevelop Copyright 2008 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_DECLARATION_ID_H #define KDEVPLATFORM_DECLARATION_ID_H #include "indexeddeclaration.h" #include "identifier.h" #include "instantiationinformation.h" #include -#include //krazy:excludeall=dpointer class QString; namespace KDevelop { class Declaration; class TopDUContext; /** * \short Allows clearly identifying a Declaration. * * DeclarationId is needed to uniquely address Declarations that are in another top-context, * because there may be multiple parsed versions of a file. * * There are two forms of DeclarationId, one indirect and one direct. The direct form * holds a reference to the Declaration instance, whereas the indirect form stores the qualified * identifier and an additional index to disambiguate instances of multiple declarations with the same * identifier. * * Both forms also have a specialization index. It can be used in a language-specific way to pick other * versions of the declaration. When the declaration is found, Declaration::specialize() is called on * the found declaration with this value, and the returned value is the actually found declaration. * * \note This only works when the Declaration is in the symbol table. * */ class KDEVPLATFORMLANGUAGE_EXPORT DeclarationId { public: /** * Constructor for indirect access to a declaration. The resulting DeclarationId will not * have a direct reference to the Declaration, but will look it up as needed. * * \param id Identifier for this declaration id. * \param additionalId Additional index to disambiguate * \param specialization Specialization index (see class documentation). */ explicit DeclarationId(const IndexedQualifiedIdentifier& id = IndexedQualifiedIdentifier(), uint additionalId = 0, const IndexedInstantiationInformation& specialization = IndexedInstantiationInformation()); /** * Constructor for direct access to a declaration. The resulting DeclarationId will * directly reference the Declaration * * \param decl Declaration to reference. * \param specialization Specialization index (see class documentation). */ explicit DeclarationId(const IndexedDeclaration& decl, const IndexedInstantiationInformation& specialization = IndexedInstantiationInformation()); DeclarationId(const DeclarationId& rhs); ~DeclarationId(); DeclarationId& operator=(const DeclarationId& rhs); /** * Equality operator. * * \param rhs declaration identifier to compare. * \returns true if equal, otherwise false. */ bool operator==(const DeclarationId& rhs) const { if(m_isDirect != rhs.m_isDirect) return false; if(!m_isDirect) return m_indirectData.identifier == rhs.m_indirectData.identifier && m_indirectData.additionalIdentity == rhs.m_indirectData.additionalIdentity && m_specialization == rhs.m_specialization; else return m_directData == rhs.m_directData && m_specialization == rhs.m_specialization; } /** * Not equal operator. * * \param rhs declaration identifier to compare. * \returns true if not equal, otherwise false. */ bool operator!=(const DeclarationId& rhs) const { return !operator==(rhs); } /** * Determine whether this declaration identifier references a valid declaration. */ bool isValid() const { return (m_isDirect && m_directData.isValid()) || m_indirectData.identifier.isValid(); } /** * Hash function for this declaration identifier. * * \warning This may return different hashes for the same declaration, * depending on whether the id is direct or indirect, * and thus you cannot compare hashes for declaration equality (use operator==() instead) */ uint hash() const { if(m_isDirect) return KDevHash() << m_directData.hash() << m_specialization.index(); else return KDevHash() << m_indirectData.identifier.getIndex() << m_indirectData.additionalIdentity << m_specialization.index(); } /** * Retrieve the declaration, from the perspective of \a context. * In order to be retrievable, the declaration must be in the symbol table. * * \param context Context in which to search for the Declaration. * \param instantiateIfRequired Whether the declaration should be instantiated if required * \returns the referenced Declaration, or null if none was found. * */ Declaration* getDeclaration(const TopDUContext* context, bool instantiateIfRequired = true) const; /** * Same as getDeclaration(..), but returns all matching declarations if there are multiple. * This also returns found forward-declarations. */ KDevVarLengthArray getDeclarations(const TopDUContext* context) const; /** * Set the specialization index (see class documentation). * * \param specializationIndex the new specialization index. */ void setSpecialization(const IndexedInstantiationInformation& spec); /** * Retrieve the specialization index (see class documentation). * * \returns the specialization index. */ IndexedInstantiationInformation specialization() const; /** * Determine whether this DeclarationId directly references a Declaration by indices, * or if it uses identifiers and other data to reference the Declaration. * * \returns true if direct, false if indirect. */ bool isDirect() const; /** * Return the qualified identifier for this declaration. * * \warning This is relatively expensive, and not 100% correct in all cases(actually a top-context would be needed to resolve this correctly), * so avoid using this, except for debugging purposes. */ QualifiedIdentifier qualifiedIdentifier() const; private: - void iterateDeclarations(const TopDUContext* top, std::function func) const; - /// An indirect reference to the declaration, which uses the symbol-table for lookup. Should be preferred for all /// declarations that are in the symbol-table struct Indirect { IndexedQualifiedIdentifier identifier; /// Hash from signature, or similar. Used to disambiguate multiple declarations of the same name. uint additionalIdentity; Indirect& operator=(const Indirect& rhs) = default; }; union { Indirect m_indirectData; IndexedDeclaration m_directData; }; bool m_isDirect; // Can be used in a language-specific way to pick other versions of the declaration. // When the declaration is found, pickSpecialization is called on the found declaration // with this value, and the returned value is the actually found declaration. IndexedInstantiationInformation m_specialization; }; inline uint qHash(const KDevelop::DeclarationId& id) { return id.hash(); } } Q_DECLARE_TYPEINFO(KDevelop::DeclarationId, Q_MOVABLE_TYPE); #endif