File indexing completed on 2024-05-12 04:38:02

0001 /*
0002     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "identifier.h"
0009 
0010 #include <QHash>
0011 #include "stringhelpers.h"
0012 #include "appendedlist_static.h"
0013 #include "serialization/itemrepository.h"
0014 #include "serialization/itemrepositoryreferencecounting.h"
0015 #include <serialization/repositorymanager.h>
0016 #include "util/kdevhash.h"
0017 #include <debug.h>
0018 
0019 #include <serialization/indexedstring.h>
0020 #include <utility>
0021 
0022 #define ifDebug(x) void()
0023 
0024 namespace KDevelop {
0025 template <bool dynamic = false>
0026 class IdentifierPrivate
0027 {
0028 public:
0029     IdentifierPrivate()
0030     {
0031     }
0032 
0033     template <bool rhsDynamic>
0034     explicit IdentifierPrivate(const IdentifierPrivate<rhsDynamic>& rhs)
0035         : m_unique(rhs.m_unique)
0036         , m_identifier(rhs.m_identifier)
0037         , m_refCount(0)
0038         , m_hash(rhs.m_hash)
0039     {
0040         copyListsFrom(rhs);
0041     }
0042 
0043     ~IdentifierPrivate()
0044     {
0045         templateIdentifiersList.free(const_cast<IndexedTypeIdentifier*>(templateIdentifiers()));
0046     }
0047 
0048     IdentifierPrivate& operator=(const IdentifierPrivate& rhs) = delete;
0049 
0050     //Flags the stored hash-value invalid
0051     void clearHash()
0052     {
0053         //This is always called on an object private to an Identifier, so there is no threading-problem.
0054         Q_ASSERT(dynamic);
0055         m_hash = 0;
0056     }
0057 
0058     uint hash() const
0059     {
0060         // Since this only needs reading and the data needs not to be private, this may be called by
0061         // multiple threads simultaneously, so computeHash() must be thread-safe.
0062         if (!m_hash && dynamic)
0063             computeHash();
0064         return m_hash;
0065     }
0066 
0067     int m_unique = 0;
0068     IndexedString m_identifier;
0069     uint m_refCount = 0;
0070 
0071     START_APPENDED_LISTS_STATIC(IdentifierPrivate)
0072 
0073     APPENDED_LIST_FIRST_STATIC(IndexedTypeIdentifier, templateIdentifiers)
0074 
0075     END_APPENDED_LISTS_STATIC(templateIdentifiers)
0076 
0077     uint itemSize() const
0078     {
0079         return sizeof(IdentifierPrivate<false> ) + lastOffsetBehind();
0080     }
0081 
0082     void computeHash() const
0083     {
0084         Q_ASSERT(dynamic);
0085         //this must stay thread-safe(may be called by multiple threads at a time)
0086         //The thread-safety is given because all threads will have the same result, and it will only be written once at the end.
0087         KDevHash kdevhash;
0088         kdevhash << m_identifier.hash() << m_unique;
0089         FOREACH_FUNCTION_STATIC(const IndexedTypeIdentifier &templateIdentifier, templateIdentifiers)
0090         kdevhash << templateIdentifier.hash();
0091         m_hash = kdevhash;
0092     }
0093 
0094     mutable uint m_hash = 0;
0095 };
0096 
0097 using DynamicIdentifierPrivate = IdentifierPrivate<true>;
0098 using ConstantIdentifierPrivate = IdentifierPrivate<false>;
0099 
0100 struct IdentifierItemRequest
0101 {
0102     IdentifierItemRequest(const DynamicIdentifierPrivate& identifier)
0103         : m_identifier(identifier)
0104     {
0105         identifier.hash(); //Make sure the hash is valid by calling this
0106     }
0107 
0108     enum {
0109         AverageSize = sizeof(IdentifierPrivate<false> ) + 4
0110     };
0111 
0112     //Should return the hash-value associated with this request(For example the hash of a string)
0113     uint hash() const
0114     {
0115         return m_identifier.hash();
0116     }
0117 
0118     //Should return the size of an item created with createItem
0119     uint itemSize() const
0120     {
0121         return m_identifier.itemSize();
0122     }
0123     //Should create an item where the information of the requested item is permanently stored. The pointer
0124     //@param item equals an allocated range with the size of itemSize().
0125     void createItem(ConstantIdentifierPrivate* item) const
0126     {
0127         new (item) ConstantIdentifierPrivate(m_identifier);
0128     }
0129 
0130     static bool persistent(const ConstantIdentifierPrivate* item)
0131     {
0132         return ( bool )item->m_refCount;
0133     }
0134 
0135     static void destroy(ConstantIdentifierPrivate* item, AbstractItemRepository&)
0136     {
0137         item->~ConstantIdentifierPrivate();
0138     }
0139 
0140     //Should return whether the here requested item equals the given item
0141     bool equals(const ConstantIdentifierPrivate* item) const
0142     {
0143         return item->m_hash == m_identifier.m_hash
0144                && item->m_unique == m_identifier.m_unique
0145                && item->m_identifier == m_identifier.m_identifier
0146                && m_identifier.listsEqual(*item);
0147     }
0148 
0149     const DynamicIdentifierPrivate& m_identifier;
0150 };
0151 
0152 using IdentifierRepository = ItemRepository<ConstantIdentifierPrivate, IdentifierItemRequest, true, QRecursiveMutex>;
0153 using IdentifierRepositoryManager = RepositoryManager<IdentifierRepository, false>;
0154 
0155 template <>
0156 class ItemRepositoryFor<IndexedIdentifier>
0157 {
0158     friend struct LockedItemRepository;
0159     static IdentifierRepository& repo()
0160     {
0161         static QRecursiveMutex mutex;
0162         static IdentifierRepositoryManager manager(QStringLiteral("Identifier Repository"), &mutex);
0163         return *manager.repository();
0164     }
0165 
0166 public:
0167     static auto* mutex() { return repo().mutex(); }
0168 };
0169 
0170 static uint emptyConstantIdentifierPrivateIndex()
0171 {
0172     static const uint index = LockedItemRepository::write<IndexedIdentifier>(
0173         [](IdentifierRepository& repo) { return repo.index(DynamicIdentifierPrivate()); });
0174     return index;
0175 }
0176 
0177 static const ConstantIdentifierPrivate* emptyConstantIdentifierPrivate()
0178 {
0179     static const ConstantIdentifierPrivate item;
0180     return &item;
0181 }
0182 
0183 bool IndexedIdentifier::isEmpty() const
0184 {
0185     return m_index == emptyConstantIdentifierPrivateIndex();
0186 }
0187 
0188 /**
0189  * Before something is modified in QualifiedIdentifierPrivate, it must be made sure that
0190  * it is private to the QualifiedIdentifier it is used in(@see QualifiedIdentifier::prepareWrite)
0191  */
0192 template <bool dynamic>
0193 class QualifiedIdentifierPrivate
0194 {
0195 public:
0196     QualifiedIdentifierPrivate()
0197         : m_explicitlyGlobal(false)
0198         , m_isExpression(false)
0199 
0200     {
0201     }
0202 
0203     template <bool rhsDynamic>
0204     explicit QualifiedIdentifierPrivate(const QualifiedIdentifierPrivate<rhsDynamic>& rhs)
0205         : m_explicitlyGlobal(rhs.m_explicitlyGlobal)
0206         , m_isExpression(rhs.m_isExpression)
0207         , m_hash(rhs.m_hash)
0208         , m_refCount(0)
0209     {
0210         copyListsFrom(rhs);
0211     }
0212 
0213     ~QualifiedIdentifierPrivate()
0214     {
0215         identifiersList.free(const_cast<IndexedIdentifier*>(identifiers()));
0216     }
0217 
0218     QualifiedIdentifierPrivate& operator=(const QualifiedIdentifierPrivate& rhs) = delete;
0219 
0220     bool m_explicitlyGlobal : 1;
0221     bool m_isExpression : 1;
0222     mutable uint m_hash = 0;
0223     uint m_refCount = 0;
0224 
0225     START_APPENDED_LISTS_STATIC(QualifiedIdentifierPrivate)
0226 
0227     APPENDED_LIST_FIRST_STATIC(IndexedIdentifier, identifiers)
0228 
0229     END_APPENDED_LISTS_STATIC(identifiers)
0230 
0231     uint itemSize() const
0232     {
0233         return sizeof(QualifiedIdentifierPrivate<false> ) + lastOffsetBehind();
0234     }
0235 
0236     //Constructs m_identifiers
0237     void splitIdentifiers(QStringView str, int start)
0238     {
0239         Q_ASSERT(dynamic);
0240         uint currentStart = start;
0241 
0242         while (currentStart < ( uint )str.length()) {
0243             identifiersList.append(IndexedIdentifier(Identifier(str, currentStart, &currentStart)));
0244             while (currentStart < ( uint )str.length() && (str[currentStart] == QLatin1Char(' ')))
0245                 ++currentStart;
0246             currentStart += 2; //Skip "::"
0247         }
0248     }
0249 
0250     inline void clearHash() const
0251     {
0252         m_hash = 0;
0253     }
0254 
0255     uint hash() const
0256     {
0257         if (m_hash == 0) {
0258             KDevHash hash;
0259 
0260             quint32 bitfields = static_cast<quint32>(m_explicitlyGlobal)
0261                                 | (m_isExpression << 1);
0262             hash << bitfields << identifiersSize();
0263             FOREACH_FUNCTION_STATIC(const IndexedIdentifier &identifier, identifiers) {
0264                 hash << identifier.index();
0265             }
0266 
0267             m_hash = hash;
0268         }
0269         return m_hash;
0270     }
0271 };
0272 
0273 using DynamicQualifiedIdentifierPrivate = QualifiedIdentifierPrivate<true>;
0274 using ConstantQualifiedIdentifierPrivate = QualifiedIdentifierPrivate<false>;
0275 
0276 struct QualifiedIdentifierItemRequest
0277 {
0278     QualifiedIdentifierItemRequest(const DynamicQualifiedIdentifierPrivate& identifier)
0279         : m_identifier(identifier)
0280     {
0281         identifier.hash(); //Make sure the hash is valid by calling this
0282     }
0283 
0284     enum {
0285         AverageSize = sizeof(QualifiedIdentifierPrivate<false> ) + 8
0286     };
0287 
0288     //Should return the hash-value associated with this request(For example the hash of a string)
0289     uint hash() const
0290     {
0291         return m_identifier.hash();
0292     }
0293 
0294     //Should return the size of an item created with createItem
0295     uint itemSize() const
0296     {
0297         return m_identifier.itemSize();
0298     }
0299 
0300     /**
0301      * Should create an item where the information of the requested item is permanently stored. The pointer
0302      * @param item equals an allocated range with the size of itemSize().
0303      */
0304     void createItem(ConstantQualifiedIdentifierPrivate* item) const
0305     {
0306         Q_ASSERT(shouldDoDUChainReferenceCounting(item));
0307         Q_ASSERT(shouldDoDUChainReferenceCounting(reinterpret_cast<char*>(item) + (itemSize() - 1)));
0308         new (item) ConstantQualifiedIdentifierPrivate(m_identifier);
0309     }
0310 
0311     static bool persistent(const ConstantQualifiedIdentifierPrivate* item)
0312     {
0313         return ( bool )item->m_refCount;
0314     }
0315 
0316     static void destroy(ConstantQualifiedIdentifierPrivate* item, AbstractItemRepository&)
0317     {
0318         Q_ASSERT(shouldDoDUChainReferenceCounting(item));
0319         item->~ConstantQualifiedIdentifierPrivate();
0320     }
0321 
0322     //Should return whether the here requested item equals the given item
0323     bool equals(const ConstantQualifiedIdentifierPrivate* item) const
0324     {
0325         return item->m_explicitlyGlobal == m_identifier.m_explicitlyGlobal
0326                && item->m_isExpression == m_identifier.m_isExpression
0327                && item->m_hash == m_identifier.m_hash
0328                && m_identifier.listsEqual(*item);
0329     }
0330 
0331     const DynamicQualifiedIdentifierPrivate& m_identifier;
0332 };
0333 
0334 using QualifiedIdentifierRepository
0335     = ItemRepository<ConstantQualifiedIdentifierPrivate, QualifiedIdentifierItemRequest, true, QRecursiveMutex>;
0336 using QualifiedIdentifierRepositoryManager = RepositoryManager<QualifiedIdentifierRepository, false>;
0337 
0338 template <>
0339 class ItemRepositoryFor<IndexedQualifiedIdentifier>
0340 {
0341     friend struct LockedItemRepository;
0342     static QualifiedIdentifierRepository& repo()
0343     {
0344         static QualifiedIdentifierRepositoryManager manager(QStringLiteral("Qualified Identifier Repository"),
0345                                                             ItemRepositoryFor<IndexedIdentifier>::mutex());
0346         return *manager.repository();
0347     }
0348 };
0349 
0350 static uint emptyConstantQualifiedIdentifierPrivateIndex()
0351 {
0352     static const uint index = LockedItemRepository::write<IndexedQualifiedIdentifier>(
0353         [](QualifiedIdentifierRepository& repo) { return repo.index(DynamicQualifiedIdentifierPrivate()); });
0354     return index;
0355 }
0356 
0357 static const ConstantQualifiedIdentifierPrivate* emptyConstantQualifiedIdentifierPrivate()
0358 {
0359     static const ConstantQualifiedIdentifierPrivate item;
0360     return &item;
0361 }
0362 
0363 Identifier::Identifier(const Identifier& rhs)
0364 {
0365     rhs.makeConstant();
0366     cd = rhs.cd;
0367     m_index = rhs.m_index;
0368 }
0369 
0370 Identifier::Identifier(uint index)
0371     : m_index(index)
0372 {
0373     Q_ASSERT(m_index);
0374     cd = LockedItemRepository::read<IndexedIdentifier>(
0375         [index](const IdentifierRepository& repo) { return repo.itemFromIndex(index); });
0376 }
0377 
0378 Identifier::Identifier(const IndexedString& str)
0379 {
0380     if (str.isEmpty()) {
0381         m_index = emptyConstantIdentifierPrivateIndex();
0382         cd = emptyConstantIdentifierPrivate();
0383     } else {
0384         m_index = 0;
0385         dd = new IdentifierPrivate<true>;
0386         dd->m_identifier = str;
0387     }
0388 }
0389 
0390 Identifier::Identifier(QStringView id, uint start, uint* takenRange)
0391 {
0392     if (id.isEmpty()) {
0393         m_index = emptyConstantIdentifierPrivateIndex();
0394         cd = emptyConstantIdentifierPrivate();
0395         return;
0396     }
0397 
0398     m_index = 0;
0399     dd = new IdentifierPrivate<true>;
0400 
0401     ///Extract template-parameters
0402     ParamIterator paramIt(u"<>:", id, start);
0403     dd->m_identifier = IndexedString(paramIt.prefix().trimmed());
0404     while (paramIt) {
0405         appendTemplateIdentifier(IndexedTypeIdentifier(IndexedQualifiedIdentifier(QualifiedIdentifier(*paramIt))));
0406         ++paramIt;
0407     }
0408 
0409     if (takenRange)
0410         *takenRange = paramIt.position();
0411 }
0412 
0413 Identifier::Identifier()
0414     : m_index(emptyConstantIdentifierPrivateIndex())
0415     , cd(emptyConstantIdentifierPrivate())
0416 {
0417 }
0418 
0419 Identifier& Identifier::operator=(const Identifier& rhs)
0420 {
0421     if (dd == rhs.dd && cd == rhs.cd)
0422         return *this;
0423 
0424     if (!m_index)
0425         delete dd;
0426     dd = nullptr;
0427 
0428     rhs.makeConstant();
0429     cd = rhs.cd;
0430     m_index = rhs.m_index;
0431     Q_ASSERT(cd);
0432     return *this;
0433 }
0434 
0435 Identifier::Identifier(Identifier&& rhs) Q_DECL_NOEXCEPT
0436     : m_index(rhs.m_index)
0437 {
0438     if (m_index) {
0439         cd = rhs.cd;
0440     } else {
0441         dd = rhs.dd;
0442     }
0443     rhs.cd = emptyConstantIdentifierPrivate();
0444     rhs.m_index = emptyConstantIdentifierPrivateIndex();
0445 }
0446 
0447 Identifier& Identifier::operator=(Identifier&& rhs) Q_DECL_NOEXCEPT
0448 {
0449     if (dd == rhs.dd && cd == rhs.cd)
0450         return *this;
0451 
0452     if (!m_index) {
0453         delete dd;
0454         dd = nullptr;
0455     }
0456 
0457     m_index = rhs.m_index;
0458 
0459     if (m_index) {
0460         cd = rhs.cd;
0461     } else {
0462         dd = rhs.dd;
0463     }
0464     rhs.cd = emptyConstantIdentifierPrivate();
0465     rhs.m_index = emptyConstantIdentifierPrivateIndex();
0466 
0467     return *this;
0468 }
0469 
0470 Identifier::~Identifier()
0471 {
0472     if (!m_index)
0473         delete dd;
0474 }
0475 
0476 bool Identifier::nameEquals(const Identifier& rhs) const
0477 {
0478     return identifier() == rhs.identifier();
0479 }
0480 
0481 uint Identifier::hash() const
0482 {
0483     if (!m_index)
0484         return dd->hash();
0485     else
0486         return cd->hash();
0487 }
0488 
0489 bool Identifier::isEmpty() const
0490 {
0491     if (!m_index)
0492         return dd->m_identifier.isEmpty() && dd->m_unique == 0 && dd->templateIdentifiersSize() == 0;
0493     else
0494         return cd->m_identifier.isEmpty() && cd->m_unique == 0 && cd->templateIdentifiersSize() == 0;
0495 }
0496 
0497 Identifier Identifier::unique(int token)
0498 {
0499     Identifier ret;
0500     ret.setUnique(token);
0501     return ret;
0502 }
0503 
0504 bool Identifier::isUnique() const
0505 {
0506     if (!m_index)
0507         return dd->m_unique;
0508     else
0509         return cd->m_unique;
0510 }
0511 
0512 int Identifier::uniqueToken() const
0513 {
0514     if (!m_index)
0515         return dd->m_unique;
0516     else
0517         return cd->m_unique;
0518 }
0519 
0520 void Identifier::setUnique(int token)
0521 {
0522     if (token != uniqueToken()) {
0523         prepareWrite();
0524         dd->m_unique = token;
0525     }
0526 }
0527 
0528 const IndexedString Identifier::identifier() const
0529 {
0530     if (!m_index)
0531         return dd->m_identifier;
0532     else
0533         return cd->m_identifier;
0534 }
0535 
0536 void Identifier::setIdentifier(QStringView identifier)
0537 {
0538     IndexedString id(identifier);
0539     if (id != this->identifier()) {
0540         prepareWrite();
0541         dd->m_identifier = std::move(id);
0542     }
0543 }
0544 
0545 void Identifier::setIdentifier(const IndexedString& identifier)
0546 {
0547     if (identifier != this->identifier()) {
0548         prepareWrite();
0549         dd->m_identifier = identifier;
0550     }
0551 }
0552 
0553 IndexedTypeIdentifier Identifier::templateIdentifier(int num) const
0554 {
0555     if (!m_index)
0556         return dd->templateIdentifiers()[num];
0557     else
0558         return cd->templateIdentifiers()[num];
0559 }
0560 
0561 uint Identifier::templateIdentifiersCount() const
0562 {
0563     if (!m_index)
0564         return dd->templateIdentifiersSize();
0565     else
0566         return cd->templateIdentifiersSize();
0567 }
0568 
0569 void Identifier::appendTemplateIdentifier(const IndexedTypeIdentifier& identifier)
0570 {
0571     prepareWrite();
0572     dd->templateIdentifiersList.append(identifier);
0573 }
0574 
0575 void Identifier::clearTemplateIdentifiers()
0576 {
0577     prepareWrite();
0578     dd->templateIdentifiersList.clear();
0579 }
0580 
0581 uint Identifier::index() const
0582 {
0583     makeConstant();
0584     Q_ASSERT(m_index);
0585     return m_index;
0586 }
0587 
0588 bool Identifier::inRepository() const
0589 {
0590     return m_index;
0591 }
0592 
0593 void Identifier::setTemplateIdentifiers(const QList<IndexedTypeIdentifier>& templateIdentifiers)
0594 {
0595     prepareWrite();
0596     dd->templateIdentifiersList.clear();
0597     for (const IndexedTypeIdentifier& id : templateIdentifiers) {
0598         dd->templateIdentifiersList.append(id);
0599     }
0600 }
0601 
0602 QString Identifier::toString(IdentifierStringFormattingOptions options) const
0603 {
0604     QString ret = identifier().str();
0605 
0606     if (!options.testFlag(RemoveTemplateInformation) && templateIdentifiersCount()) {
0607         QStringList templateIds;
0608         templateIds.reserve(templateIdentifiersCount());
0609         for (uint i = 0; i < templateIdentifiersCount(); ++i) {
0610             templateIds.append(templateIdentifier(i).toString(options));
0611         }
0612 
0613         ret += QLatin1String("< ") + templateIds.join(QLatin1String(", ")) + QLatin1String(" >");
0614     }
0615 
0616     return ret;
0617 }
0618 
0619 bool Identifier::isReserved() const
0620 {
0621     const auto str = identifier().str();
0622     constexpr QLatin1Char underscore{'_'};
0623     return str.size() >= 2 && str[0] == underscore && (str[1] == underscore || str[1].isUpper());
0624 }
0625 
0626 bool Identifier::operator==(const Identifier& rhs) const
0627 {
0628     return index() == rhs.index();
0629 }
0630 
0631 bool Identifier::operator!=(const Identifier& rhs) const
0632 {
0633     return !operator==(rhs);
0634 }
0635 
0636 uint QualifiedIdentifier::index() const
0637 {
0638     makeConstant();
0639     Q_ASSERT(m_index);
0640     return m_index;
0641 }
0642 
0643 void Identifier::makeConstant() const
0644 {
0645     if (m_index)
0646         return;
0647 
0648     LockedItemRepository::write<IndexedIdentifier>(
0649         [&, request = IdentifierItemRequest(*dd)](IdentifierRepository& repo) {
0650             m_index = repo.index(request);
0651             delete dd;
0652             cd = repo.itemFromIndex(m_index);
0653         });
0654 }
0655 
0656 void Identifier::prepareWrite()
0657 {
0658     if (m_index) {
0659         const IdentifierPrivate<false>* oldCc = cd;
0660         dd = new IdentifierPrivate<true>;
0661         dd->m_hash = oldCc->m_hash;
0662         dd->m_unique = oldCc->m_unique;
0663         dd->m_identifier = oldCc->m_identifier;
0664         dd->copyListsFrom(*oldCc);
0665         m_index = 0;
0666     }
0667 
0668     dd->clearHash();
0669 }
0670 
0671 bool QualifiedIdentifier::inRepository() const
0672 {
0673     if (m_index)
0674         return true;
0675 
0676     return LockedItemRepository::read<IndexedQualifiedIdentifier>(
0677         [&, request = QualifiedIdentifierItemRequest(*dd)](const QualifiedIdentifierRepository& repo) {
0678             return static_cast<bool>(repo.findIndex(request));
0679         });
0680 }
0681 
0682 QualifiedIdentifier::QualifiedIdentifier(uint index)
0683     : m_index(index)
0684     , cd(LockedItemRepository::read<IndexedQualifiedIdentifier>(
0685           [index](const QualifiedIdentifierRepository& repo) { return repo.itemFromIndex(index); }))
0686 {
0687 }
0688 
0689 QualifiedIdentifier::QualifiedIdentifier(QStringView id, bool isExpression)
0690 {
0691     if (id.isEmpty()) {
0692         m_index = emptyConstantQualifiedIdentifierPrivateIndex();
0693         cd = emptyConstantQualifiedIdentifierPrivate();
0694         return;
0695     }
0696 
0697     m_index = 0;
0698     dd = new DynamicQualifiedIdentifierPrivate;
0699 
0700     if (isExpression) {
0701         setIsExpression(true);
0702         if (!id.isEmpty()) {
0703             //Prevent tokenization, since we may lose information there
0704             Identifier finishedId;
0705             finishedId.setIdentifier(id);
0706             push(finishedId);
0707         }
0708     } else {
0709         if (id.startsWith(QLatin1String("::"))) {
0710             dd->m_explicitlyGlobal = true;
0711             dd->splitIdentifiers(id, 2);
0712         } else {
0713             dd->m_explicitlyGlobal = false;
0714             dd->splitIdentifiers(id, 0);
0715         }
0716     }
0717 }
0718 
0719 QualifiedIdentifier::QualifiedIdentifier(const Identifier& id)
0720 {
0721     if (id.isEmpty()) {
0722         m_index = emptyConstantQualifiedIdentifierPrivateIndex();
0723         cd = emptyConstantQualifiedIdentifierPrivate();
0724         return;
0725     }
0726 
0727     m_index = 0;
0728     dd = new DynamicQualifiedIdentifierPrivate;
0729 
0730     if (id.dd->m_identifier.str().isEmpty()) {
0731         dd->m_explicitlyGlobal = true;
0732     } else {
0733         dd->m_explicitlyGlobal = false;
0734         dd->identifiersList.append(IndexedIdentifier(id));
0735     }
0736 }
0737 
0738 QualifiedIdentifier::QualifiedIdentifier()
0739     : m_index(emptyConstantQualifiedIdentifierPrivateIndex())
0740     , cd(emptyConstantQualifiedIdentifierPrivate())
0741 {
0742 }
0743 
0744 QualifiedIdentifier::QualifiedIdentifier(const QualifiedIdentifier& id)
0745 {
0746     if (id.m_index) {
0747         m_index = id.m_index;
0748         cd = id.cd;
0749     } else {
0750         m_index = 0;
0751         dd = new QualifiedIdentifierPrivate<true>(*id.dd);
0752     }
0753 }
0754 
0755 QualifiedIdentifier::QualifiedIdentifier(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT
0756     : m_index(rhs.m_index)
0757 {
0758     if (m_index) {
0759         cd = rhs.cd;
0760     } else {
0761         dd = rhs.dd;
0762     }
0763     rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex();
0764     rhs.cd = emptyConstantQualifiedIdentifierPrivate();
0765 }
0766 
0767 QualifiedIdentifier& QualifiedIdentifier::operator=(const QualifiedIdentifier& rhs)
0768 {
0769     if (dd == rhs.dd && cd == rhs.cd)
0770         return *this;
0771 
0772     if (!m_index)
0773         delete dd;
0774     rhs.makeConstant();
0775     cd = rhs.cd;
0776     m_index = rhs.m_index;
0777     return *this;
0778 }
0779 
0780 QualifiedIdentifier& QualifiedIdentifier::operator=(QualifiedIdentifier&& rhs) Q_DECL_NOEXCEPT
0781 {
0782     if (!m_index)
0783         delete dd;
0784     m_index = rhs.m_index;
0785     if (m_index) {
0786         cd = rhs.cd;
0787     } else {
0788         dd = rhs.dd;
0789     }
0790     rhs.cd = emptyConstantQualifiedIdentifierPrivate();
0791     rhs.m_index = emptyConstantQualifiedIdentifierPrivateIndex();
0792     return *this;
0793 }
0794 
0795 QualifiedIdentifier::~QualifiedIdentifier()
0796 {
0797     if (!m_index)
0798         delete dd;
0799 }
0800 
0801 QStringList QualifiedIdentifier::toStringList(IdentifierStringFormattingOptions options) const
0802 {
0803     QStringList ret;
0804     ret.reserve(explicitlyGlobal() + count());
0805     if (explicitlyGlobal())
0806         ret.append(QString());
0807 
0808     if (m_index) {
0809         ret.reserve(ret.size() + cd->identifiersSize());
0810         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, cd->identifiers)
0811         ret << index.identifier().toString(options);
0812     } else {
0813         ret.reserve(ret.size() + dd->identifiersSize());
0814         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, dd->identifiers)
0815         ret << index.identifier().toString(options);
0816     }
0817 
0818     return ret;
0819 }
0820 
0821 QString QualifiedIdentifier::toString(IdentifierStringFormattingOptions options) const
0822 {
0823     const QString doubleColon = QStringLiteral("::");
0824 
0825     QString ret;
0826     if (!options.testFlag(RemoveExplicitlyGlobalPrefix) && explicitlyGlobal())
0827         ret = doubleColon;
0828 
0829     QStringList identifiers;
0830     if (m_index) {
0831         identifiers.reserve(cd->identifiersSize());
0832         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, cd->identifiers)
0833         {
0834             identifiers += index.identifier().toString(options);
0835         }
0836     } else {
0837         identifiers.reserve(dd->identifiersSize());
0838         FOREACH_FUNCTION_STATIC(const IndexedIdentifier &index, dd->identifiers)
0839         {
0840             identifiers += index.identifier().toString(options);
0841         }
0842     }
0843 
0844     return ret + identifiers.join(doubleColon);
0845 }
0846 
0847 QualifiedIdentifier QualifiedIdentifier::merge(const QualifiedIdentifier& base) const
0848 {
0849     QualifiedIdentifier ret(base);
0850     ret.push(*this);
0851     return ret;
0852 }
0853 
0854 QualifiedIdentifier QualifiedIdentifier::operator+(const QualifiedIdentifier& rhs) const
0855 {
0856     return rhs.merge(*this);
0857 }
0858 
0859 QualifiedIdentifier& QualifiedIdentifier::operator+=(const QualifiedIdentifier& rhs)
0860 {
0861     push(rhs);
0862     return *this;
0863 }
0864 
0865 QualifiedIdentifier QualifiedIdentifier::operator+(const Identifier& rhs) const
0866 {
0867     QualifiedIdentifier ret(*this);
0868     ret.push(rhs);
0869     return ret;
0870 }
0871 
0872 QualifiedIdentifier& QualifiedIdentifier::operator+=(const Identifier& rhs)
0873 {
0874     push(rhs);
0875     return *this;
0876 }
0877 
0878 QualifiedIdentifier QualifiedIdentifier::operator+(const IndexedIdentifier& rhs) const
0879 {
0880     QualifiedIdentifier ret(*this);
0881     ret.push(rhs);
0882     return ret;
0883 }
0884 
0885 QualifiedIdentifier& QualifiedIdentifier::operator+=(const IndexedIdentifier& rhs)
0886 {
0887     push(rhs);
0888     return *this;
0889 }
0890 
0891 bool QualifiedIdentifier::isExpression() const
0892 {
0893     if (m_index)
0894         return cd->m_isExpression;
0895     else
0896         return dd->m_isExpression;
0897 }
0898 
0899 void QualifiedIdentifier::setIsExpression(bool is)
0900 {
0901     if (is != isExpression()) {
0902         prepareWrite();
0903         dd->m_isExpression = is;
0904     }
0905 }
0906 
0907 bool QualifiedIdentifier::explicitlyGlobal() const
0908 {
0909     // True if started with "::"
0910     if (m_index)
0911         return cd->m_explicitlyGlobal;
0912     else
0913         return dd->m_explicitlyGlobal;
0914 }
0915 
0916 void QualifiedIdentifier::setExplicitlyGlobal(bool eg)
0917 {
0918     if (eg != explicitlyGlobal()) {
0919         prepareWrite();
0920         dd->m_explicitlyGlobal = eg;
0921     }
0922 }
0923 
0924 bool QualifiedIdentifier::sameIdentifiers(const QualifiedIdentifier& rhs) const
0925 {
0926     if (m_index && rhs.m_index)
0927         return cd->listsEqual(*rhs.cd);
0928     else if (m_index && !rhs.m_index)
0929         return cd->listsEqual(*rhs.dd);
0930     else if (!m_index && !rhs.m_index)
0931         return dd->listsEqual(*rhs.dd);
0932     else
0933         return dd->listsEqual(*rhs.cd);
0934 }
0935 
0936 bool QualifiedIdentifier::operator==(const QualifiedIdentifier& rhs) const
0937 {
0938     if (cd == rhs.cd)
0939         return true;
0940     return hash() == rhs.hash() && sameIdentifiers(rhs);
0941 }
0942 
0943 bool QualifiedIdentifier::operator!=(const QualifiedIdentifier& rhs) const
0944 {
0945     return !operator==(rhs);
0946 }
0947 
0948 bool QualifiedIdentifier::beginsWith(const QualifiedIdentifier& other) const
0949 {
0950     uint c = count();
0951     uint oc = other.count();
0952 
0953     for (uint i = 0; i < c && i < oc; ++i)
0954         if (at(i) == other.at(i)) {
0955             continue;
0956         } else {
0957             return false;
0958         }
0959 
0960     return true;
0961 }
0962 
0963 struct Visitor
0964 {
0965     Visitor(KDevVarLengthArray<QualifiedIdentifier>& target, uint hash)
0966         : target(target)
0967         , hash(hash)
0968     {
0969     }
0970 
0971     bool operator()(const ConstantQualifiedIdentifierPrivate* item, uint index) const
0972     {
0973         if (item->m_hash == hash)
0974             target.append(QualifiedIdentifier(index));
0975         return true;
0976     }
0977 
0978     KDevVarLengthArray<QualifiedIdentifier>& target;
0979     const uint hash;
0980 };
0981 
0982 uint QualifiedIdentifier::hash() const
0983 {
0984     if (m_index)
0985         return cd->hash();
0986     else
0987         return dd->hash();
0988 }
0989 
0990 uint qHash(const IndexedTypeIdentifier& id)
0991 {
0992     return id.hash();
0993 }
0994 
0995 uint qHash(const QualifiedIdentifier& id)
0996 {
0997     return id.hash();
0998 }
0999 
1000 uint qHash(const Identifier& id)
1001 {
1002     return id.hash();
1003 }
1004 
1005 bool QualifiedIdentifier::isQualified() const
1006 {
1007     return count() > 1 || explicitlyGlobal();
1008 }
1009 
1010 void QualifiedIdentifier::push(const Identifier& id)
1011 {
1012     if (id.isEmpty())
1013         return;
1014 
1015     push(IndexedIdentifier(id));
1016 }
1017 
1018 void QualifiedIdentifier::push(const IndexedIdentifier& id)
1019 {
1020     if (id.isEmpty()) {
1021         return;
1022     }
1023 
1024     prepareWrite();
1025 
1026     dd->identifiersList.append(id);
1027 }
1028 
1029 void QualifiedIdentifier::push(const QualifiedIdentifier& id)
1030 {
1031     if (id.isEmpty()) {
1032         return;
1033     }
1034 
1035     prepareWrite();
1036 
1037     if (id.m_index) {
1038         dd->identifiersList.append(id.cd->identifiers(), id.cd->identifiersSize());
1039     } else {
1040         dd->identifiersList.append(id.dd->identifiers(), id.dd->identifiersSize());
1041     }
1042 
1043     if (id.explicitlyGlobal()) {
1044         setExplicitlyGlobal(true);
1045     }
1046 }
1047 
1048 void QualifiedIdentifier::pop()
1049 {
1050     prepareWrite();
1051     if (!dd->identifiersSize())
1052         return;
1053     dd->identifiersList.resize(dd->identifiersList.size() - 1);
1054 }
1055 
1056 void QualifiedIdentifier::clear()
1057 {
1058     prepareWrite();
1059     dd->identifiersList.clear();
1060     dd->m_explicitlyGlobal = false;
1061     dd->m_isExpression = false;
1062 }
1063 
1064 bool QualifiedIdentifier::isEmpty() const
1065 {
1066     if (m_index)
1067         return cd->identifiersSize() == 0;
1068     else
1069         return dd->identifiersSize() == 0;
1070 }
1071 
1072 int QualifiedIdentifier::count() const
1073 {
1074     if (m_index)
1075         return cd->identifiersSize();
1076     else
1077         return dd->identifiersSize();
1078 }
1079 
1080 Identifier QualifiedIdentifier::first() const
1081 {
1082     return indexedFirst().identifier();
1083 }
1084 
1085 IndexedIdentifier QualifiedIdentifier::indexedFirst() const
1086 {
1087     if ((m_index && cd->identifiersSize() == 0) || (!m_index && dd->identifiersSize() == 0))
1088         return IndexedIdentifier();
1089     else
1090         return indexedAt(0);
1091 }
1092 
1093 Identifier QualifiedIdentifier::last() const
1094 {
1095     return indexedLast().identifier();
1096 }
1097 
1098 IndexedIdentifier QualifiedIdentifier::indexedLast() const
1099 {
1100     uint c = count();
1101     if (c)
1102         return indexedAt(c - 1);
1103     else
1104         return IndexedIdentifier();
1105 }
1106 
1107 Identifier QualifiedIdentifier::top() const
1108 {
1109     return last();
1110 }
1111 
1112 QualifiedIdentifier QualifiedIdentifier::mid(int pos, int len) const
1113 {
1114     QualifiedIdentifier ret;
1115     if (pos == 0)
1116         ret.setExplicitlyGlobal(explicitlyGlobal());
1117 
1118     int cnt = ( int )count();
1119 
1120     if (len == -1)
1121         len = cnt - pos;
1122 
1123     if (pos + len > cnt)
1124         len -= cnt - (pos + len);
1125 
1126     for (int a = pos; a < pos + len; a++)
1127         ret.push(at(a));
1128 
1129     return ret;
1130 }
1131 
1132 Identifier QualifiedIdentifier::at(int i) const
1133 {
1134     return indexedAt(i).identifier();
1135 }
1136 
1137 IndexedIdentifier QualifiedIdentifier::indexedAt(int i) const
1138 {
1139     if (m_index) {
1140         Q_ASSERT(i >= 0 && i < ( int )cd->identifiersSize());
1141         return cd->identifiers()[i];
1142     } else {
1143         Q_ASSERT(i >= 0 && i < ( int )dd->identifiersSize());
1144         return dd->identifiers()[i];
1145     }
1146 }
1147 
1148 void QualifiedIdentifier::makeConstant() const
1149 {
1150     if (m_index)
1151         return;
1152 
1153     LockedItemRepository::write<IndexedQualifiedIdentifier>(
1154         [&, request = QualifiedIdentifierItemRequest(*dd)](QualifiedIdentifierRepository& repo) {
1155             m_index = repo.index(request);
1156             delete dd;
1157             cd = repo.itemFromIndex(m_index);
1158         });
1159 }
1160 
1161 void QualifiedIdentifier::prepareWrite()
1162 {
1163     if (m_index) {
1164         const QualifiedIdentifierPrivate<false>* oldCc = cd;
1165         dd = new QualifiedIdentifierPrivate<true>;
1166         dd->m_explicitlyGlobal = oldCc->m_explicitlyGlobal;
1167         dd->m_isExpression = oldCc->m_isExpression;
1168         dd->m_hash = oldCc->m_hash;
1169 
1170         dd->copyListsFrom(*oldCc);
1171         m_index = 0;
1172     }
1173 
1174     dd->clearHash();
1175 }
1176 
1177 uint IndexedTypeIdentifier::hash() const
1178 {
1179     quint32 bitfields = static_cast<quint32>(m_isConstant)
1180                         | (m_isReference << 1)
1181                         | (m_isRValue << 2)
1182                         | (m_isVolatile << 3)
1183                         | (m_pointerDepth << 4)
1184                         | (m_pointerConstMask << 9);
1185     return KDevHash() << m_identifier.index() << bitfields;
1186 }
1187 
1188 bool IndexedTypeIdentifier::operator==(const IndexedTypeIdentifier& rhs) const
1189 {
1190     return m_identifier == rhs.m_identifier
1191            && m_isConstant == rhs.m_isConstant
1192            && m_isReference == rhs.m_isReference
1193            && m_isRValue == rhs.m_isRValue
1194            && m_isVolatile == rhs.m_isVolatile
1195            && m_pointerConstMask == rhs.m_pointerConstMask
1196            && m_pointerDepth == rhs.m_pointerDepth;
1197 }
1198 
1199 bool IndexedTypeIdentifier::operator!=(const IndexedTypeIdentifier& rhs) const
1200 {
1201     return !operator==(rhs);
1202 }
1203 
1204 bool IndexedTypeIdentifier::isReference() const
1205 {
1206     return m_isReference;
1207 }
1208 
1209 void IndexedTypeIdentifier::setIsReference(bool isRef)
1210 {
1211     m_isReference = isRef;
1212 }
1213 
1214 bool IndexedTypeIdentifier::isRValue() const
1215 {
1216     return m_isRValue;
1217 }
1218 
1219 void IndexedTypeIdentifier::setIsRValue(bool isRVal)
1220 {
1221     m_isRValue = isRVal;
1222 }
1223 
1224 bool IndexedTypeIdentifier::isConstant() const
1225 {
1226     return m_isConstant;
1227 }
1228 
1229 void IndexedTypeIdentifier::setIsConstant(bool isConst)
1230 {
1231     m_isConstant = isConst;
1232 }
1233 
1234 bool IndexedTypeIdentifier::isVolatile() const
1235 {
1236     return m_isVolatile;
1237 }
1238 
1239 void IndexedTypeIdentifier::setIsVolatile(bool isVolatile)
1240 {
1241     m_isVolatile = isVolatile;
1242 }
1243 
1244 int IndexedTypeIdentifier::pointerDepth() const
1245 {
1246     return m_pointerDepth;
1247 }
1248 
1249 void IndexedTypeIdentifier::setPointerDepth(int depth)
1250 {
1251     Q_ASSERT(depth <= 23 && depth >= 0);
1252     ///Clear the mask in removed fields
1253     for (int s = depth; s < ( int )m_pointerDepth; ++s)
1254         setIsConstPointer(s, false);
1255 
1256     m_pointerDepth = depth;
1257 }
1258 
1259 bool IndexedTypeIdentifier::isConstPointer(int depthNumber) const
1260 {
1261     return m_pointerConstMask & (1 << depthNumber);
1262 }
1263 
1264 void IndexedTypeIdentifier::setIsConstPointer(int depthNumber, bool constant)
1265 {
1266     if (constant)
1267         m_pointerConstMask |= (1 << depthNumber);
1268     else
1269         m_pointerConstMask &= (~(1 << depthNumber));
1270 }
1271 
1272 QString IndexedTypeIdentifier::toString(IdentifierStringFormattingOptions options) const
1273 {
1274     QString ret;
1275     if (isConstant())
1276         ret += QLatin1String("const ");
1277     if (isVolatile())
1278         ret += QLatin1String("volatile ");
1279 
1280     ret += m_identifier.identifier().toString(options);
1281     for (int a = 0; a < pointerDepth(); ++a) {
1282         ret += QLatin1Char('*');
1283         if (isConstPointer(a))
1284             ret += QLatin1String("const");
1285     }
1286 
1287     if (isRValue())
1288         ret += QLatin1String("&&");
1289     else if (isReference())
1290         ret += QLatin1Char('&');
1291     return ret;
1292 }
1293 
1294 IndexedTypeIdentifier::IndexedTypeIdentifier(const IndexedQualifiedIdentifier& identifier)
1295     : m_identifier(identifier)
1296     , m_isConstant(false)
1297     , m_isReference(false)
1298     , m_isRValue(false)
1299     , m_isVolatile(false)
1300     , m_pointerDepth(0)
1301     , m_pointerConstMask(0)
1302 { }
1303 
1304 IndexedTypeIdentifier::IndexedTypeIdentifier(QStringView identifier, bool isExpression)
1305     : m_identifier(QualifiedIdentifier(identifier, isExpression))
1306     , m_isConstant(false)
1307     , m_isReference(false)
1308     , m_isRValue(false)
1309     , m_isVolatile(false)
1310     , m_pointerDepth(0)
1311     , m_pointerConstMask(0)
1312 { }
1313 
1314 // NOTE: the definitions of ItemRepositoryReferenceCounting's inc(), dec() and setIndex() are so
1315 // complex that they can throw exceptions for many reasons. Yet some special member functions of
1316 // Indexed[Qualified]Identifier, which call them, are implicitly (the destructors) or explicitly
1317 // noexcept. The noexcept-ness of these functions is important for correctness and performance.
1318 // This is safe at the moment, because the entire KDevPlatformLanguage library, that contains these
1319 // classes, is compiled with exceptions disabled (-fno-exceptions), which already prevents exception
1320 // propagation to a caller of any non-inline function in this library.
1321 
1322 IndexedIdentifier::IndexedIdentifier(unsigned int index)
1323     : m_index(index)
1324 {
1325     ItemRepositoryReferenceCounting::inc(this);
1326 }
1327 
1328 IndexedIdentifier::IndexedIdentifier()
1329     : IndexedIdentifier(emptyConstantIdentifierPrivateIndex())
1330 {
1331 }
1332 
1333 IndexedIdentifier::IndexedIdentifier(const Identifier& id)
1334     : IndexedIdentifier(id.index())
1335 {
1336 }
1337 
1338 IndexedIdentifier::IndexedIdentifier(const IndexedIdentifier& rhs) noexcept
1339     : IndexedIdentifier(rhs.m_index)
1340 {
1341 }
1342 
1343 IndexedIdentifier::~IndexedIdentifier()
1344 {
1345     ItemRepositoryReferenceCounting::dec(this);
1346 }
1347 
1348 IndexedIdentifier& IndexedIdentifier::operator=(unsigned int index)
1349 {
1350     ItemRepositoryReferenceCounting::setIndex(this, m_index, index);
1351     return *this;
1352 }
1353 
1354 IndexedIdentifier& IndexedIdentifier::operator=(const Identifier& id)
1355 {
1356     return operator=(id.index());
1357 }
1358 
1359 IndexedIdentifier& IndexedIdentifier::operator=(const IndexedIdentifier& id) noexcept
1360 {
1361     return operator=(id.m_index);
1362 }
1363 
1364 bool IndexedIdentifier::operator==(const IndexedIdentifier& rhs) const
1365 {
1366     return m_index == rhs.m_index;
1367 }
1368 
1369 bool IndexedIdentifier::operator!=(const IndexedIdentifier& rhs) const
1370 {
1371     return m_index != rhs.m_index;
1372 }
1373 
1374 bool IndexedIdentifier::operator==(const Identifier& id) const
1375 {
1376     return m_index == id.index();
1377 }
1378 
1379 Identifier IndexedIdentifier::identifier() const
1380 {
1381     return Identifier(m_index);
1382 }
1383 
1384 IndexedIdentifier::operator Identifier() const
1385 {
1386     return Identifier(m_index);
1387 }
1388 
1389 bool IndexedQualifiedIdentifier::isValid() const
1390 {
1391     return m_index != emptyConstantQualifiedIdentifierPrivateIndex();
1392 }
1393 
1394 bool IndexedQualifiedIdentifier::isEmpty() const
1395 {
1396     return m_index == emptyConstantQualifiedIdentifierPrivateIndex();
1397 }
1398 
1399 int cnt = 0;
1400 
1401 IndexedQualifiedIdentifier IndexedTypeIdentifier::identifier() const
1402 {
1403     return m_identifier;
1404 }
1405 
1406 void IndexedTypeIdentifier::setIdentifier(const IndexedQualifiedIdentifier& id)
1407 {
1408     m_identifier = id;
1409 }
1410 
1411 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(unsigned int index)
1412     : m_index(index)
1413 {
1414     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ") Creating" << identifier().toString() << m_index);
1415 
1416     ItemRepositoryReferenceCounting::inc(this);
1417 }
1418 
1419 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier()
1420     : IndexedQualifiedIdentifier(emptyConstantQualifiedIdentifierPrivateIndex())
1421 {
1422 }
1423 
1424 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(const QualifiedIdentifier& id)
1425     : IndexedQualifiedIdentifier(id.index())
1426 {
1427 }
1428 
1429 IndexedQualifiedIdentifier::IndexedQualifiedIdentifier(const IndexedQualifiedIdentifier& id) noexcept
1430     : IndexedQualifiedIdentifier(id.m_index)
1431 {
1432 }
1433 
1434 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(unsigned int index)
1435 {
1436     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ") Assigning to" << identifier().toString() << m_index);
1437 
1438     ItemRepositoryReferenceCounting::setIndex(this, m_index, index);
1439     return *this;
1440 }
1441 
1442 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(const QualifiedIdentifier& id)
1443 {
1444     return operator=(id.index());
1445 }
1446 
1447 IndexedQualifiedIdentifier& IndexedQualifiedIdentifier::operator=(const IndexedQualifiedIdentifier& rhs) noexcept
1448 {
1449     return operator=(rhs.m_index);
1450 }
1451 
1452 IndexedQualifiedIdentifier::~IndexedQualifiedIdentifier()
1453 {
1454     ifDebug(qCDebug(LANGUAGE) << "(" << ++cnt << ") Destroying" << identifier().toString() << m_index);
1455     ItemRepositoryReferenceCounting::dec(this);
1456 }
1457 
1458 bool IndexedQualifiedIdentifier::operator==(const IndexedQualifiedIdentifier& rhs) const
1459 {
1460     return m_index == rhs.m_index;
1461 }
1462 
1463 bool IndexedQualifiedIdentifier::operator==(const QualifiedIdentifier& id) const
1464 {
1465     return m_index == id.index();
1466 }
1467 
1468 QualifiedIdentifier IndexedQualifiedIdentifier::identifier() const
1469 {
1470     return QualifiedIdentifier(m_index);
1471 }
1472 
1473 IndexedQualifiedIdentifier::operator QualifiedIdentifier() const
1474 {
1475     return QualifiedIdentifier(m_index);
1476 }
1477 
1478 void initIdentifierRepository()
1479 {
1480     emptyConstantIdentifierPrivateIndex();
1481     emptyConstantIdentifierPrivate();
1482     emptyConstantQualifiedIdentifierPrivateIndex();
1483     emptyConstantQualifiedIdentifierPrivate();
1484 }
1485 }
1486 
1487 QDebug operator<<(QDebug s, const KDevelop::Identifier& identifier)
1488 {
1489     s.nospace() << identifier.toString();
1490     return s.space();
1491 }
1492 
1493 QDebug operator<<(QDebug s, const KDevelop::QualifiedIdentifier& identifier)
1494 {
1495     s.nospace() << identifier.toString();
1496     return s.space();
1497 }