File indexing completed on 2024-05-12 04:37:57

0001 /*
0002     SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de>
0003     SPDX-FileCopyrightText: 2014 Kevin Funk <kfunk@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "definitions.h"
0009 
0010 #include "appendedlist.h"
0011 #include "declaration.h"
0012 #include "declarationid.h"
0013 #include "duchainpointer.h"
0014 #include <serialization/indexedstring.h>
0015 #include "serialization/itemrepository.h"
0016 
0017 namespace KDevelop {
0018 DEFINE_LIST_MEMBER_HASH(DefinitionsItem, definitions, IndexedDeclaration)
0019 
0020 class DefinitionsItem
0021 {
0022 public:
0023     DefinitionsItem()
0024     {
0025         initializeAppendedLists();
0026     }
0027     DefinitionsItem(const DefinitionsItem& rhs, bool dynamic = true) : declaration(rhs.declaration)
0028     {
0029         initializeAppendedLists(dynamic);
0030         copyListsFrom(rhs);
0031     }
0032 
0033     ~DefinitionsItem()
0034     {
0035         freeAppendedLists();
0036     }
0037 
0038     DefinitionsItem& operator=(const DefinitionsItem& rhs) = delete;
0039 
0040     unsigned int hash() const
0041     {
0042         //We only compare the declaration. This allows us implementing a map, although the item-repository
0043         //originally represents a set.
0044         return declaration.hash();
0045     }
0046 
0047     unsigned int itemSize() const
0048     {
0049         return dynamicSize();
0050     }
0051 
0052     uint classSize() const
0053     {
0054         return sizeof(DefinitionsItem);
0055     }
0056 
0057     DeclarationId declaration;
0058 
0059     START_APPENDED_LISTS(DefinitionsItem);
0060     APPENDED_LIST_FIRST(DefinitionsItem, IndexedDeclaration, definitions);
0061     END_APPENDED_LISTS(DefinitionsItem, definitions);
0062 };
0063 
0064 class DefinitionsRequestItem
0065 {
0066 public:
0067 
0068     DefinitionsRequestItem(const DefinitionsItem& item) : m_item(item)
0069     {
0070     }
0071     enum {
0072         AverageSize = 30 //This should be the approximate average size of an Item
0073     };
0074 
0075     unsigned int hash() const
0076     {
0077         return m_item.hash();
0078     }
0079 
0080     uint itemSize() const
0081     {
0082         return m_item.itemSize();
0083     }
0084 
0085     void createItem(DefinitionsItem* item) const
0086     {
0087         new (item) DefinitionsItem(m_item, false);
0088     }
0089 
0090     static void destroy(DefinitionsItem* item, KDevelop::AbstractItemRepository&)
0091     {
0092         item->~DefinitionsItem();
0093     }
0094 
0095     static bool persistent(const DefinitionsItem*)
0096     {
0097         return true;
0098     }
0099 
0100     bool equals(const DefinitionsItem* item) const
0101     {
0102         return m_item.declaration == item->declaration;
0103     }
0104 
0105     const DefinitionsItem& m_item;
0106 };
0107 
0108 class DefinitionsVisitor
0109 {
0110 public:
0111     DefinitionsVisitor(Definitions* _definitions, const QTextStream& _out)
0112         : definitions(_definitions)
0113         , out(_out)
0114     {
0115     }
0116 
0117     bool operator()(const DefinitionsItem* item)
0118     {
0119         QDebug qout(out.device());
0120         auto id = item->declaration;
0121         const auto allDefinitions = definitions->definitions(id);
0122 
0123         qout << "Definitions for" << id.qualifiedIdentifier() << Qt::endl;
0124         for (const IndexedDeclaration& decl : allDefinitions) {
0125             if (decl.data()) {
0126                 qout << " " << decl.data()->qualifiedIdentifier() << "in" << decl.data()->url().byteArray() << "at"
0127                      << decl.data()->rangeInCurrentRevision() << Qt::endl;
0128             }
0129         }
0130 
0131         return true;
0132     }
0133 
0134 private:
0135     const Definitions* definitions;
0136     const QTextStream& out;
0137 };
0138 
0139 // Maps declaration-ids to definitions
0140 using DefinitionsRepo = ItemRepository<DefinitionsItem, DefinitionsRequestItem>;
0141 
0142 template<>
0143 class ItemRepositoryFor<Definitions>
0144 {
0145     friend struct LockedItemRepository;
0146     static DefinitionsRepo& repo()
0147     {
0148         static QMutex mutex;
0149         static DefinitionsRepo repo { QStringLiteral("Definition Map"), &mutex };
0150         return repo;
0151     }
0152 };
0153 
0154 Definitions::Definitions()
0155 {
0156     LockedItemRepository::initialize<Definitions>();
0157 }
0158 
0159 void Definitions::addDefinition(const DeclarationId& id, const IndexedDeclaration& definition)
0160 {
0161     DefinitionsItem item;
0162     item.declaration = id;
0163     item.definitionsList().append(definition);
0164     DefinitionsRequestItem request(item);
0165 
0166     LockedItemRepository::write<Definitions>([&](DefinitionsRepo& repo) {
0167         uint index = repo.findIndex(item);
0168 
0169         if (index) {
0170             // Check whether the item is already in the mapped list, else copy the list into the new created item
0171             const DefinitionsItem* oldItem = repo.itemFromIndex(index);
0172             for (unsigned int a = 0; a < oldItem->definitionsSize(); ++a) {
0173                 if (oldItem->definitions()[a] == definition)
0174                     return; // Already there
0175                 item.definitionsList().append(oldItem->definitions()[a]);
0176             }
0177 
0178             repo.deleteItem(index);
0179         }
0180 
0181         // This inserts the changed item
0182         repo.index(request);
0183     });
0184 }
0185 
0186 void Definitions::removeDefinition(const DeclarationId& id, const IndexedDeclaration& definition)
0187 {
0188     DefinitionsItem item;
0189     item.declaration = id;
0190     DefinitionsRequestItem request(item);
0191 
0192     LockedItemRepository::write<Definitions>([&](DefinitionsRepo& repo) {
0193         uint index = repo.findIndex(item);
0194 
0195         if (index) {
0196             // Check whether the item is already in the mapped list, else copy the list into the new created item
0197             const DefinitionsItem* oldItem = repo.itemFromIndex(index);
0198             for (unsigned int a = 0; a < oldItem->definitionsSize(); ++a)
0199                 if (!(oldItem->definitions()[a] == definition))
0200                     item.definitionsList().append(oldItem->definitions()[a]);
0201 
0202             repo.deleteItem(index);
0203             Q_ASSERT(repo.findIndex(item) == 0);
0204 
0205             // This inserts the changed item
0206             if (item.definitionsSize() != 0)
0207                 repo.index(request);
0208         }
0209     });
0210 }
0211 
0212 KDevVarLengthArray<IndexedDeclaration> Definitions::definitions(const DeclarationId& id) const
0213 {
0214     KDevVarLengthArray<IndexedDeclaration> ret;
0215 
0216     DefinitionsItem item;
0217     item.declaration = id;
0218     DefinitionsRequestItem request(item);
0219 
0220     LockedItemRepository::read<Definitions>([&](const DefinitionsRepo& repo) {
0221         uint index = repo.findIndex(item);
0222 
0223         if (index) {
0224             const DefinitionsItem* repositoryItem = repo.itemFromIndex(index);
0225             FOREACH_FUNCTION(const IndexedDeclaration& decl, repositoryItem->definitions)
0226             ret.append(decl);
0227         }
0228     });
0229 
0230     return ret;
0231 }
0232 
0233 void Definitions::dump(const QTextStream& out)
0234 {
0235     DefinitionsVisitor v(this, out);
0236     LockedItemRepository::read<Definitions>([&](const DefinitionsRepo& repo) {
0237         repo.visitAllItems(v);
0238     });
0239 }
0240 }