diff --git a/language/duchain/codemodel.cpp b/language/duchain/codemodel.cpp index 0cc2bd835..8447987a3 100644 --- a/language/duchain/codemodel.cpp +++ b/language/duchain/codemodel.cpp @@ -1,456 +1,388 @@ /* 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 "codemodel.h" #include #include #include "appendedlist.h" #include "util/debug.h" #include #include "identifier.h" #include #include #include #define ifDebug(x) namespace KDevelop { class CodeModelItemHandler { public: static int leftChild(const CodeModelItem& m_data) { return (int)m_data.referenceCount; } static void setLeftChild(CodeModelItem& m_data, int child) { m_data.referenceCount = (uint)child; } static int rightChild(const CodeModelItem& m_data) { return (int)m_data.uKind; } static void setRightChild(CodeModelItem& m_data, int child) { m_data.uKind = (uint)child; } //Copies this item into the given one static void copyTo(const CodeModelItem& m_data, CodeModelItem& data) { data = m_data; } static void createFreeItem(CodeModelItem& data) { data = CodeModelItem(); data.referenceCount = (uint)-1; data.uKind = (uint)-1; } static bool isFree(const CodeModelItem& m_data) { return !m_data.id.isValid(); } static const CodeModelItem& data(const CodeModelItem& m_data) { return m_data; } static bool equals(const CodeModelItem& m_data, const CodeModelItem& rhs) { return m_data.id == rhs.id; } }; +static void testReferenceCounting(const KDevelop::IndexedString& file) +{ +#ifdef TEST_REFERENCE_COUNTING_2 + uint count = 0; + const CodeModelItem* i; + this->items(file, count, i); + for(int a = 0; a < count; ++a) + Q_ASSERT(i[a].id.hasReferenceCount()); +#endif +} + DEFINE_LIST_MEMBER_HASH(CodeModelRepositoryItem, items, CodeModelItem) class CodeModelRepositoryItem { public: CodeModelRepositoryItem() : centralFreeItem(-1) { initializeAppendedLists(); } CodeModelRepositoryItem(const CodeModelRepositoryItem& rhs, bool dynamic = true) : file(rhs.file), centralFreeItem(rhs.centralFreeItem) { initializeAppendedLists(dynamic); copyListsFrom(rhs); } ~CodeModelRepositoryItem() { freeAppendedLists(); } unsigned int hash() const { //We only compare the declaration. This allows us implementing a map, although the item-repository //originally represents a set. return file.index(); } uint itemSize() const { return dynamicSize(); } uint classSize() const { return sizeof(CodeModelRepositoryItem); } IndexedString file; int centralFreeItem; START_APPENDED_LISTS(CodeModelRepositoryItem); APPENDED_LIST_FIRST(CodeModelRepositoryItem, CodeModelItem, items); END_APPENDED_LISTS(CodeModelRepositoryItem, items); }; class CodeModelRequestItem { public: CodeModelRequestItem(const CodeModelRepositoryItem& item) : m_item(item) { } enum { AverageSize = 30 //This should be the approximate average size of an Item }; unsigned int hash() const { return m_item.hash(); } uint itemSize() const { return m_item.itemSize(); } void createItem(CodeModelRepositoryItem* item) const { Q_ASSERT(shouldDoDUChainReferenceCounting(item)); Q_ASSERT(shouldDoDUChainReferenceCounting(((char*)item) + (itemSize()-1))); new (item) CodeModelRepositoryItem(m_item, false); } static void destroy(CodeModelRepositoryItem* item, KDevelop::AbstractItemRepository&) { Q_ASSERT(shouldDoDUChainReferenceCounting(item)); // Q_ASSERT(shouldDoDUChainReferenceCounting(((char*)item) + (itemSize()-1))); item->~CodeModelRepositoryItem(); } static bool persistent(const CodeModelRepositoryItem* item) { Q_UNUSED(item); return true; } bool equals(const CodeModelRepositoryItem* item) const { return m_item.file == item->file; } const CodeModelRepositoryItem& m_item; }; class CodeModelPrivate { public: CodeModelPrivate() : m_repository(QStringLiteral("Code Model")) { } //Maps declaration-ids to items ItemRepository m_repository; }; CodeModel::CodeModel() : d(new CodeModelPrivate()) { } CodeModel::~CodeModel() { delete d; } void CodeModel::addItem(const IndexedString& file, const IndexedQualifiedIdentifier& id, CodeModelItem::Kind kind) { ifDebug( qCDebug(LANGUAGE) << "addItem" << file.str() << id.identifier().toString() << id.index; ) if(!id.isValid()) return; CodeModelRepositoryItem item; item.file = file; CodeModelRequestItem request(item); uint index = d->m_repository.findIndex(item); CodeModelItem newItem; newItem.id = id; newItem.kind = kind; newItem.referenceCount = 1; - #ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } - #endif + testReferenceCounting(file); if(index) { const CodeModelRepositoryItem* oldItem = d->m_repository.itemFromIndex(index); EmbeddedTreeAlgorithms alg(oldItem->items(), oldItem->itemsSize(), oldItem->centralFreeItem); int listIndex = alg.indexOf(newItem); QMutexLocker lock(d->m_repository.mutex()); DynamicItem editableItem = d->m_repository.dynamicItemFromIndex(index); CodeModelItem* items = const_cast(editableItem->items()); if(listIndex != -1) { //Only update the reference-count ++items[listIndex].referenceCount; items[listIndex].kind = kind; return; }else{ //Add the item to the list EmbeddedTreeAddItem add(items, editableItem->itemsSize(), editableItem->centralFreeItem, newItem); if(add.newItemCount() != editableItem->itemsSize()) { //The data needs to be transferred into a bigger list. That list is within "item". item.itemsList().resize(add.newItemCount()); add.transferData(item.itemsList().data(), item.itemsList().size(), &item.centralFreeItem); d->m_repository.deleteItem(index); }else{ //We're fine: The item fits into the existing list. -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); return; } } }else{ //We're creating a new index item.itemsList().append(newItem); } -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); Q_ASSERT(!d->m_repository.findIndex(request)); //This inserts the changed item volatile uint newIndex = d->m_repository.index(request); Q_UNUSED(newIndex); ifDebug( qCDebug(LANGUAGE) << "new index" << newIndex; ) -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); Q_ASSERT(d->m_repository.findIndex(request)); } void CodeModel::updateItem(const IndexedString& file, const IndexedQualifiedIdentifier& id, CodeModelItem::Kind kind) { ifDebug( qCDebug(LANGUAGE) << file.str() << id.identifier().toString() << kind; ) if(!id.isValid()) return; -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); CodeModelRepositoryItem item; item.file = file; CodeModelRequestItem request(item); CodeModelItem newItem; newItem.id = id; newItem.kind = kind; newItem.referenceCount = 1; uint index = d->m_repository.findIndex(item); if(index) { //Check whether the item is already in the mapped list, else copy the list into the new created item QMutexLocker lock(d->m_repository.mutex()); DynamicItem oldItem = d->m_repository.dynamicItemFromIndex(index); EmbeddedTreeAlgorithms alg(oldItem->items(), oldItem->itemsSize(), oldItem->centralFreeItem); int listIndex = alg.indexOf(newItem); Q_ASSERT(listIndex != -1); CodeModelItem* items = const_cast(oldItem->items()); Q_ASSERT(items[listIndex].id == id); items[listIndex].kind = kind; -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); return; } Q_ASSERT(0); //The updated item as not in the symbol table! } void CodeModel::removeItem(const IndexedString& file, const IndexedQualifiedIdentifier& id) //void CodeModel::removeDeclaration(const QualifiedIdentifier& id, const IndexedDeclaration& declaration) { if(!id.isValid()) return; -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + + testReferenceCounting(file); ifDebug( qCDebug(LANGUAGE) << "removeItem" << file.str() << id.identifier().toString(); ) CodeModelRepositoryItem item; item.file = file; CodeModelRequestItem request(item); uint index = d->m_repository.findIndex(item); if(index) { CodeModelItem searchItem; searchItem.id = id; QMutexLocker lock(d->m_repository.mutex()); DynamicItem oldItem = d->m_repository.dynamicItemFromIndex(index); EmbeddedTreeAlgorithms alg(oldItem->items(), oldItem->itemsSize(), oldItem->centralFreeItem); int listIndex = alg.indexOf(searchItem); if(listIndex == -1) return; CodeModelItem* items = const_cast(oldItem->items()); --items[listIndex].referenceCount; if(oldItem->items()[listIndex].referenceCount) return; //Nothing to remove, there's still a reference-count left //We have reduced the reference-count to zero, so remove the item from the list EmbeddedTreeRemoveItem remove(items, oldItem->itemsSize(), oldItem->centralFreeItem, searchItem); uint newItemCount = remove.newItemCount(); if(newItemCount != oldItem->itemsSize()) { if(newItemCount == 0) { //Has become empty, delete the item d->m_repository.deleteItem(index); -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); return; }else{ //Make smaller item.itemsList().resize(newItemCount); remove.transferData(item.itemsList().data(), item.itemsSize(), &item.centralFreeItem); //Delete the old list d->m_repository.deleteItem(index); //Add the new list d->m_repository.index(request); -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); return; } } } -#ifdef TEST_REFERENCE_COUNTING_2 - { - uint count = 0; - const CodeModelItem* i; - this->items(file, count, i); - for(int a = 0; a < count; ++a) - Q_ASSERT(i[a].id.hasReferenceCount()); - } -#endif + testReferenceCounting(file); } void CodeModel::items(const IndexedString& file, uint& count, const CodeModelItem*& items) const { ifDebug( qCDebug(LANGUAGE) << "items" << file.str(); ) CodeModelRepositoryItem item; item.file = file; CodeModelRequestItem request(item); uint index = d->m_repository.findIndex(item); if(index) { const CodeModelRepositoryItem* repositoryItem = d->m_repository.itemFromIndex(index); ifDebug( qCDebug(LANGUAGE) << "found index" << index << repositoryItem->itemsSize(); ) count = repositoryItem->itemsSize(); items = repositoryItem->items(); }else{ ifDebug( qCDebug(LANGUAGE) << "found no index"; ) count = 0; items = 0; } } CodeModel& CodeModel::self() { static CodeModel ret; return ret; } } diff --git a/language/duchain/declarationid.cpp b/language/duchain/declarationid.cpp index ffd4c9f23..0cdde0ff1 100644 --- a/language/duchain/declarationid.cpp +++ b/language/duchain/declarationid.cpp @@ -1,245 +1,206 @@ /* 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; } -KDevVarLengthArray DeclarationId::getDeclarations(const TopDUContext* top) const +void DeclarationId::iterateDeclarations(const TopDUContext* top, std::function func) const { - KDevVarLengthArray ret; - if(m_isDirect == false) { //Find the declaration by its qualified identifier and additionalIdentity - QualifiedIdentifier id(m_indirectData.identifier); + const 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()) { - //Hit - ret.append(decl); + if (func(decl)) + 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 + ///@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 - ret.append(decl); + if (func(decl)) + break; } } } } }else{ - Declaration* decl = m_directData.declaration(); - if(decl) - ret.append(decl); + func(m_directData.declaration()); } +} + +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 = 0; + Declaration* ret = nullptr; - if(m_isDirect == false) { - //Find the declaration by its qualified identifier and additionalIdentity - QualifiedIdentifier id(m_indirectData.identifier); + iterateDeclarations(top, [&ret](Declaration* decl){ + ret = decl; + return !ret->isForwardDeclaration(); + }); - 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; + 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) { - 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->specialize(m_specialization, topContextForSpecialization); } - - - 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; + return ret; } 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 775c3cf86..0d23e9673 100644 --- a/language/duchain/declarationid.h +++ b/language/duchain/declarationid.h @@ -1,210 +1,213 @@ /* 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